<commit_before>var _ = require('lodash');
var Promise = require('bluebird');
var Client = require('bitfinex');
var util = require('util');

module.exports = function(conf, trader){
    _.extend(this, conf);
    var self = this;

    var initDeferred = Promise.defer();
    this.initialized = initDeferred.promise;

    this.client = new Client(this.key, this.secret);
    ['orderbook', 'new_order', 'order_status', 'cancel_order' /*, 'wallet_balances'*/].forEach(function(command){
        self.client[command] = Promise.promisify(self.client[command]);
    })
    this.spreadAdapter = function(indata){
        var outdata = {
            exchange : 'bitfinex',
            bids : [],
            asks : []
        };

        var bids = indata.bids;
        var asks  = indata.asks;

        for (var i = 0; i < 5; i++) {
            outdata.bids.push([bids[i].price, bids[i].amount]);
            outdata.asks.push([asks[i].price, asks[i].amount]);
        };
        return outdata;
    };

    this.getSpread = function(currency){ // only USD ATM.
        return self.client.orderbook('btcusd').then(function(response){
            var data = self.spreadAdapter(response);
            _.extend(data, {exchange: 'bitfinex', currency: currency});
            trader.emit('spread_data', data);
            return data;
        });
    }

    this.getBalance = function(){

        // keeping this function intact in case I forget how deferreds work ;) / SK. 21 mars
        var deferred = Promise.defer();

        self.client.wallet_balances(function(error, data) {
            if(error) {
                console.error(error);
                return deferred.reject(error);
            }
            self.balance = {
                'USD' : Math.floor( parseFloat(_.find(data, {type: 'exchange', currency :'usd'}).available) * 1000) / 1000,
                'BTC' : Math.floor( parseFloat(_.find(data, {type: 'exchange', currency :'btc'}).available) * 1000) / 1000
            };
            console.log('bitfinex.balance: ', self.balance);
            if(_.isNaN(self.balance.USD) || _.isNaN(self.balance.BTC)){
                deferred.reject('Bitfinex balance isNaN');
            }
            deferred.resolve(self.balance);
        });

        return deferred.promise;
    }
    this.cancel = function(id){
        return this.client.cancel_order(id);
    };

    this.tradeCommand = function(options){
        console.log('executing bitfinex trade: ', options);

        return this.client.new_order('btcusd', options.volume.toString(), options.price.toString(), 'all', options.buySell.toLowerCase(), 'exchange limit').then(function(response){
            console.log('add order sent: ', response);
            return response;
        });
    };

    this.trade = function(options){
        var tradeResolver = Promise.defer();

        var neededOptions = ['currency', 'buySell', 'price', 'volume'];
        for (var i = neededOptions.length - 1; i >= 0; i--) {
            if(!_.has(options, neededOptions[i])){
                return tradeResolver.throw('Input data error').promise;
            }
        };

        this.tradeCommand(options).then(function(response){
            var id = response.order_id;
            var i = 0;

            console.log('bitfinex order id: ', id);

            function tradeChecker(response){
                if(tradeResolver.promise.isResolved()){ return ; } // quit the loop

                console.log('tradecheck bitfinex: ', response);

                if(response.original_amount == response.executed_amount ){
                    console.log('order is completed!');
                    tradeResolver.resolve(response);
                    return true;
                } else if (response.is_cancelled){
                    console.log('order is cancelled!');
                    tradeResolver.reject(response);
                    return false;
                } else if(response.is_live){
                    console.log('order ', id, 'is still running, iteration', i++);
                    Promise.delay(1000).then(function(){
                        return self.client.order_status(id); // here is where the request happens
                    }).then(tradeChecker); // keep looping this baby
                } else {
                    throw new Error('Unclear bitfinex trade situation: ', response);
                }
            }
            tradeChecker(response); // verify original response

            if(options.timeout && _.isNumber(options.timeout)){
                setTimeout(function(){
                    if( ! tradeResolver.promise.isResolved()) {
                        self.cancel(id).then(function(){
                            tradeResolver.reject('Trade timeout: ' + id);
                        });
                    }
                }, options.timeout);
            }
        }).catch(function(e){
            console.log('Error in nested bitfinex trade: ', e);
            tradeResolver.reject(e);
        });;

        return tradeResolver.promise;
    };

    this.getBalance().then(function(){
        initDeferred.resolve();
    });

}
<commit_msg>rewrite bitfinex trade command to have less nested promises, use timeout, etc<commit_after>var _ = require('lodash');
var Promise = require('bluebird');
var Client = require('bitfinex');
var util = require('util');

module.exports = function(conf, trader){
    _.extend(this, conf);
    var self = this;

    var initDeferred = Promise.defer();
    this.initialized = initDeferred.promise;

    this.client = new Client(this.key, this.secret);
    ['orderbook', 'new_order', 'order_status', 'cancel_order' /*, 'wallet_balances'*/].forEach(function(command){
        self.client[command] = Promise.promisify(self.client[command]);
    })

    this.pollingInterval = 1000;

    this.spreadAdapter = function(indata){
        var outdata = {
            exchange : 'bitfinex',
            bids : [],
            asks : []
        };

        var bids = indata.bids;
        var asks  = indata.asks;

        for (var i = 0; i < 5; i++) {
            outdata.bids.push([bids[i].price, bids[i].amount]);
            outdata.asks.push([asks[i].price, asks[i].amount]);
        };
        return outdata;
    };

    this.getSpread = function(currency){ // only USD ATM.
        return self.client.orderbook('btcusd').then(function(response){
            var data = self.spreadAdapter(response);
            _.extend(data, {exchange: 'bitfinex', currency: currency});
            trader.emit('spread_data', data);
            return data;
        });
    }

    this.getBalance = function(){

        // keeping this function intact in case I forget how deferreds work ;) / SK. 21 mars
        var deferred = Promise.defer();

        self.client.wallet_balances(function(error, data) {
            if(error) {
                console.error(error);
                return deferred.reject(error);
            }
            self.balance = {
                'USD' : Math.floor( parseFloat(_.find(data, {type: 'exchange', currency :'usd'}).available) * 1000) / 1000,
                'BTC' : Math.floor( parseFloat(_.find(data, {type: 'exchange', currency :'btc'}).available) * 1000) / 1000
            };
            console.log('bitfinex.balance: ', self.balance);
            if(_.isNaN(self.balance.USD) || _.isNaN(self.balance.BTC)){
                deferred.reject('Bitfinex balance isNaN');
            }
            deferred.resolve(self.balance);
        });

        return deferred.promise;
    }
    this.cancel = function(id){
        return self.client.cancel_order(id);
    };

    this.tradeCommand = function(options){
        console.log('executing bitfinex trade: ', options);

        return self.client.new_order('btcusd', options.volume.toString(), options.price.toString(), 'all', options.buySell.toLowerCase(), 'exchange limit').then(function(response){
            console.log('add order sent: ', response);
            return response;
        });
    };

    self.idExtractor = function(response){
        console.log('bitfinex order id: ', response.order_id);
        this.id = response.order_id;
        this.retries = 0;
        return response;
    };

    self.tradeChecker = function(){
        console.log('tradecheck bitfinex: ', this.id);
        return self.client.order_status(this.id)
            .bind(this)
            .then(self.responseProcessor)
            .then(self.tradeCheckLooper);
    }

    self.responseProcessor = function(response){
        if(response.original_amount == response.executed_amount ){
            console.log('order is completed!');
            return {
                success : true,
                response : response
            };
        } else if (response.is_cancelled){
            console.log('order is cancelled!');
            throw new Error('order is cancelled!', response);

        } else if(response.is_live){
            return false;
        } else {
            throw new Error('Unclear trade situation: ', response);
        }
    };

    // these can be generalized, broken out

    this.tradeValidator = function(options){
        return new Promise(function(resolve, reject){
            var neededOptions = ['currency', 'buySell', 'price', 'volume'];
            for (var i = neededOptions.length - 1; i >= 0; i--) {
                if(!_.has(options, neededOptions[i])){
                    reject("Trade doesn't have needed properties; 'currency', 'buySell', 'price', 'volume'");
                    return;
                }
            }
            resolve(options);
        });
    };

    self.tradeCheckLooper = function(finishedResponse){
        if(finishedResponse){
            return finishedResponse;
        }

        console.log('order ', this.id, 'is still running, iteration', this.retries++);

        // keep looping this baby
        if(this.retries <= 1){
            return Promise.bind(this).then(self.tradeChecker); // first retry do immediately
        } else {
            return Promise.delay(self.pollingInterval).bind(this).then(self.tradeChecker);
        }
    };

    this.trade = function(options){
        return self.tradeValidator(options)
            .then(self.tradeCommand)
            .bind({}) // create a shared this property
            .then(self.idExtractor)
            .then(function(response){
                if(options.timeout && _.isNumber(options.timeout)){
                    return Promise.bind(this).then(self.tradeChecker).timeout(options.timeout);

                } else {
                    return Promise.bind(this).then(self.tradeChecker);
                }
            }).catch(Promise.TimeoutError, function(e){
                console.log('Trade timeout, cancelling');
                self.cancel(this.id);
                throw e;
            });
    };

    this.getBalance().then(function(){
        initDeferred.resolve();
    });

}
<|endoftext|>


<commit_before>import PropTypes from "prop-types";
import React from 'react';
import {Row, Col} from 'reactstrap';
import classNames from 'classnames';
import Widget02 from './Widget02';

function colorClasses(state){
  return classNames('', {
    'success': state === 'on',
    'danger': state !== 'on'
  });
}

function iconClasses(state){
  return classNames('fa', {
    'fa-check': state === 'on',
    'fa-times': state !== 'on'
  });
}

const Process = ({process}) => (
  <Col xs={12} sm={6} md={4} xl={3}>
    <Widget02 header={process.name} mainText={process.description} icon={iconClasses(process.state)} color={colorClasses(process.state)} variant="1" />
  </Col>
);

Process.propTypes = {
  process: PropTypes.object
};

const Processes = ({processes}) => (
  <Row>
    {processes.map((process) => <Process key={process.name} process={process} />)}
  </Row>
);

Processes.propTypes = {
  processes: PropTypes.arrayOf(PropTypes.object)
};

export default Processes;
<commit_msg>fix: consistent service order in cockpit<commit_after>import PropTypes from "prop-types";
import React from 'react';
import {Row, Col} from 'reactstrap';
import classNames from 'classnames';
import Widget02 from './Widget02';

function colorClasses(state){
  return classNames('', {
    'success': state === 'on',
    'danger': state !== 'on'
  });
}

function iconClasses(state){
  return classNames('fa', {
    'fa-check': state === 'on',
    'fa-times': state !== 'on'
  });
}

const Process = ({process}) => (
  <Col xs={12} sm={6} md={4} xl={3}>
    <Widget02 header={process.name} mainText={process.description} icon={iconClasses(process.state)} color={colorClasses(process.state)} variant="1" />
  </Col>
);

Process.propTypes = {
  process: PropTypes.object
};

const Processes = ({processes}) => (
  <Row>
    {processes
      .sort((a, b) => a.name < b.name ? 1 : 0)
      .map((process) => <Process key={process.name} process={process} />)}
  </Row>
);

Processes.propTypes = {
  processes: PropTypes.arrayOf(PropTypes.object)
};

export default Processes;
<|endoftext|>


<commit_before>//http://www.clearlyinnovative.com/blog/post/1484840648/titanium-appcelerator-quickie-change-text-style-in-window-title
function windowClass(title, url) {
    var version = Ti.Platform.version;
    var device = Ti.Platform.name;
    // ios 7 windows withought bar image
    if (version >= 7 && (device === 'iPhone OS' || device === 'iPad OS' || device === 'iPod Touch OS')){
        var self = Ti.UI.createWindow({
        backgroundColor:'#fff',
        title:title,
        translucent:true,
        url:url,
    });
    }
// ios 6 and lower
else{
    //Titanium.UI.iPhone.SystemButtonStyle = 'PLAIN';
    var self = Ti.UI.createWindow({
        title:title,
        //fullscreen : true,
        barColor: '#650000',//barColor:'#980012',
        backButtonTitle:'Back',
        backgroundColor:'#fff',
        url:url,
    });

    // create the label
var titleLabel = Titanium.UI.createLabel({
    color:'#fff',
    //backgroundColor:'#f6f5f1',
    height:42,
    width:'100%',
    text:title,
    textAlign:'center',
    font:{fontFamily:'Helvetica Neue',fontSize:16,fontWeight:'bold'},
    shadowColor:'#000',shadowOffset:{x:0,y:-1}
});
}
// landscape orientation will hide navBar and statusBar
function changeOrientation (e) {
    if(e.orientation == '3' || e.orientation == '4'){  //landscape
        Titanium.UI.iPhone.hideStatusBar();
        self.hideNavBar();
    } else if (e.orientation == '1' || e.orientation == '2'){ //portrait
        Titanium.UI.iPhone.showStatusBar();
        self.showNavBar();
    }

};
// execute 'changeOrientation' when window first opens and than on every orientation change
changeOrientation(Titanium.Gesture);
Titanium.Gesture.addEventListener('orientationchange', function(e) {
    changeOrientation(Titanium.Gesture);
});

// associate label to title
self.setTitleControl(titleLabel);

    return self;
};

module.exports = windowClass;<commit_msg>fixed issue:<commit_after>//http://www.clearlyinnovative.com/blog/post/1484840648/titanium-appcelerator-quickie-change-text-style-in-window-title
function windowClass(title, url) {
    var version = Ti.Platform.version;
    var device = Ti.Platform.name;
    // ios 7 windows withought bar image
    if (version >= 7 && (device === 'iPhone OS' || device === 'iPad OS' || device === 'iPod Touch OS')){
        var self = Ti.UI.createWindow({
        backgroundColor:'#fff',
        title:title,
        translucent:true,
        url:url,
    });
    }
// ios 6 and lower
else{
    //Titanium.UI.iPhone.SystemButtonStyle = 'PLAIN';
    var self = Ti.UI.createWindow({
        title:title,
        //fullscreen : true,
        barColor: '#650000',//barColor:'#980012',
        backButtonTitle:'Back',
        backgroundColor:'#fff',
        url:url,
    });

    // create the label
var titleLabel = Titanium.UI.createLabel({
    color:'#fff',
    //backgroundColor:'#f6f5f1',
    height:42,
    width:'100%',
    text:title,
    textAlign:'center',
    font:{fontFamily:'Helvetica Neue',fontSize:16,fontWeight:'bold'},
    shadowColor:'#000',shadowOffset:{x:0,y:-1}
});
}
// landscape orientation will hide navBar and statusBar
function changeOrientation (e) {
    if(e.orientation == '3' || e.orientation == '4'){  //landscape
        //Titanium.UI.iPhone.hideStatusBar();
        self.hideNavBar();
    } else if (e.orientation == '1' || e.orientation == '2'){ //portrait
        //Titanium.UI.iPhone.showStatusBar();
        self.showNavBar();
    }

};
// execute 'changeOrientation' when window first opens and than on every orientation change
changeOrientation(Titanium.Gesture);
Titanium.Gesture.addEventListener('orientationchange', function(e) {
    changeOrientation(Titanium.Gesture);
});

// associate label to title
self.setTitleControl(titleLabel);

    return self;
};

module.exports = windowClass;<|endoftext|>


<commit_before>const express = require('express');
const mongoose = require('mongoose');
const moment = require('moment');
const OrderNote = require('./../models/OrderNote');
const Orderer = require('./../models/Orderer');
const util = require('./../helper');

mongoose.Promise = global.Promise;

const router = express.Router();

/*
    POST /api/note
    일일장부 등록

    ERROR CODES
        1 : EMPTY REQUIRED FIELD
        2 : PERMISSION DENIED
*/
router.post('/', (req, res) => {

    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    if (util.empty(req.body.orderer_name)) {
        return res.status(400).json({
            error: 'EMPTY REQUIRED FIELD',
            code: 1
        });
    }

    if (util.empty(req.body.receiver_name)) {
        return res.status(400).json({
            error: 'EMPTY REQUIRED FIELD',
            code: 1
        });
    }

    const {
        orderer_name,       // 주문자 이름 또는 회사명
        orderer_phone,      // 주문자 연락처
        orderer_id="no",    // 주문자 고유식별자(등록된 거래처면 ID값으로, 등록되지 않았다면 "no"로 등록)
        receiver_name,      // 받는 분 이름
        receiver_phone,     // 받는 분 연락처
        delivery_category,  // 배달품 종류 (ex. 꽃바구니, 꽃다발, 관엽 등등...)
        delivery_price,     // 가격
        delivery_count,     // 상품 갯수
        delivery_date,      // 배달일자
        delivery_address,   // 배달주소
        delivery_text,      // 글씨(경조사어 및 주문자 이름)
        memo
        // delivery_image,     // 배송된 물품의 사진...(차후 설계하자...)
        // is_payment          // 결제관련 여부 파악 (이것도 차후로...)

    } = req.body;

    let note;

    // 등록된 거래처가 아닌 일반계정으로 장부 입력시
    if (orderer_id === 'no') {
        const c_year = (new Date()).getFullYear();
        const date = {
            $gte: new Date(c_year, 0, 1),
            $lt: new Date((c_year+1), 0, 1)
        };

        const condition = {
            '$and': [
                { 'orderer.id': 'no' },
                { 'orderer.name': orderer_name.trim() },
                { 'orderer.phone': orderer_phone },
                { 'delivery.date': date }
            ]
        };

        // 똑같은 주문자명과 연락처로 장부건수가 1년사이 9건이 넘을 경우
        // 10건째부터는 거래처로 등록한다.
        OrderNote.count(condition, (errCount, count) => {
            if (errCount) throw errCount;

            if (count >= 9) {
                let orderer = new Orderer({
                    'name': orderer_name.trim(),
                    'phone': orderer_phone,
                    'def_ribtext': delivery_text
                });

                orderer.save( (errOrdererSave) => {
                    if (errOrdererSave) throw errOrdererSave;

                    // 기존 일반계정으로 등록되어 있던 장부들은 새로이 등록된 거래처 아이디로 업데이트한다.
                    OrderNote.updateMany({
                        $and: [
                            { 'orderer.id': 'no' },
                            { 'orderer.name': orderer_name.trim() },
                            { 'orderer.phone': orderer_phone }
                        ]
                    },
                    { 'orderer.id': orderer._id },
                    (errUpdate, raw) => {
                        if (errUpdate) throw errUpdate;

                        if (raw) {
                            note = new OrderNote({
                                'orderer.name': orderer_name.trim(),
                                'orderer.phone': orderer_phone,
                                'orderer.id': orderer._id,
                                'receiver.name': receiver_name.trim(),
                                'receiver.phone': receiver_phone,
                                'delivery.category': delivery_category,
                                'delivery.price': delivery_price,
                                'delivery.count': delivery_count,
                                'delivery.date': new Date(delivery_date),
                                'delivery.address': delivery_address,
                                'delivery.text': delivery_text,
                                'memo': memo
                            });

                            note.save( (errSave) => {
                                if (errSave) throw errSave;

                                return res.json({
                                    success: true,
                                    id: note._id
                                });
                            });
                        }
                    });
                });
            } else {    // 9건이 넘지않을 경우에는 기존 방식대로 일반계정으로 등록한다.
                note = new OrderNote({
                    'orderer.name': orderer_name.trim(),
                    'orderer.phone': orderer_phone,
                    'orderer.id': orderer_id,
                    'receiver.name': receiver_name.trim(),
                    'receiver.phone': receiver_phone,
                    'delivery.category': delivery_category,
                    'delivery.price': delivery_price,
                    'delivery.count': delivery_count,
                    'delivery.date': new Date(delivery_date),
                    'delivery.address': delivery_address,
                    'delivery.text': delivery_text,
                    'memo': memo
                });

                note.save( (errSave) => {
                    if (errSave) throw errSave;

                    return res.json({
                        success: true,
                        id: note._id
                    });
                });
            }
        });
    } else {
        note = new OrderNote({
            'orderer.name': orderer_name.trim(),
            'orderer.phone': orderer_phone,
            'orderer.id': orderer_id,
            'receiver.name': receiver_name.trim(),
            'receiver.phone': receiver_phone,
            'delivery.category': delivery_category,
            'delivery.price': delivery_price,
            'delivery.count': delivery_count,
            'delivery.date': new Date(delivery_date),
            'delivery.address': delivery_address,
            'delivery.text': delivery_text,
            'memo': memo
        });

        note.save( (errSave) => {
            if (errSave) throw errSave;

            return res.json({
                success: true,
                id: note._id
            });
        });
    }
});

/*
    GET /api/note
    모든 장부들 조회

    ERROR CODES
        1 : PERMISSION DENIED
*/
router.get('/', (req, res) => {

    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 1
        });
    }

    // 보여주고 싶은 field를 설정
    const projection = {
        '_id': 1,
        'orderer.name': 1,
        'receiver.name': 1,
        'delivery.category': 1,
        'delivery.price': 1,
        'delivery.count': 1,
        'delivery.address': 1,
        'delivery.date': 1,
        // 'delivery.image': 1,
        'is_payment': 1
        // 'memo': 1
    };

    OrderNote.find({}, projection)
        .sort({'delivery.date': -1})
        .exec( (err, notes) => {
            if (err) throw err;

            return res.json({
                success: true,
                data: notes
            });
        });
});

/*
    GET /api/note/today
    특정 장부를 조회

    ERROR CODES
        2 : PERMISSION DENIED
        3 : NO RESOURCE
*/
router.get('/today', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    const today = moment();
    today.hour(1).minute(0);

    const tomorrow = moment(today).add(1, 'day');
    tomorrow.hour(0).minute(0);

    OrderNote
        .find({
            'delivery.date': { $gte: today.toDate(), $lt: tomorrow.toDate() }
        })
        .sort({ 'delivery.date': -1 })
        .exec((err, notes) => {
            if (err) throw err;

            if (notes.length === 0) {
                return res.status(400).json({
                    error: 'NO RESOURCE',
                    code: 3
                });
            }

            return res.json({
                data: notes
            });
        });
});

/*
    GET /api/note/search/:searchTxt
    특정 장부를 조회

    ERROR CODES
        2 : PERMISSION DENIED
*/
router.get('/search/:searchTxt', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    const searchTxt = decodeURIComponent(req.params.searchTxt);

    let condition = null;

    // 찾고자 하는 날짜로 검색
    if (searchTxt.indexOf('-') !== -1) {
        const dateArray = [];
        searchTxt.split('-').forEach( (d) => {
            dateArray.push(parseInt(d, 10));
        });

        condition = {
            'delivery.date': {
                $gte: new Date(dateArray[0], dateArray[1]-1, dateArray[2], 0, 0, 0),
                $lt: new Date(dateArray[0], dateArray[1]-1, dateArray[2], 23, 0, 0)
            }
        };
    } else {    // 찾고자 하는 검색어로 검색
        condition = {
            $or: [
                {'orderer.name': new RegExp(searchTxt, 'i')},
                {'orderer.phone': new RegExp(searchTxt, 'i')},
                {'receiver.name': new RegExp(searchTxt, 'i')},
                {'receiver.phone': new RegExp(searchTxt, 'i')},
                {'delivery.address': new RegExp(searchTxt, 'i')},
                {'delivery.text': new RegExp(searchTxt, 'i')},
                {'memo': new RegExp(searchTxt, 'i')}
            ]
        };
    }

    OrderNote
        .find(condition)
        .sort({'delivery.date': -1})
        .exec( (err, notes) => {
            if (err) throw err;

            return res.json({
                data: notes
            });

        });

});

/*
    GET /api/note/month/:month
    month 월에 해당하는 자료를 조회

    ERROR CODES
        2 : PERMISSION DENIED
*/
router.get('/month/:month', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    // 찾고자 하는 년, 월로 검색 (Calendar)
    const now = new Date(req.params.month);
    const lastDayOfMonth = new Date(now.getFullYear(), (now.getMonth()+1));
    lastDayOfMonth.setHours(lastDayOfMonth.getHours()-1);

    const condition = {
        'delivery.date': {
            $gt: now,
            $lte: lastDayOfMonth
        }
    };

    OrderNote
        .aggregate([
            { $match: condition },
            { $project: {
                d: {
                    $dayOfMonth: '$delivery.date'
                }
            }},
            { $group: {
                _id: '$d'
            }},
            { $sort: {
                _id: 1
            }}
        ], (err, notes) => {
            if (err) throw err;

            return res.json({
                data: notes
            });

        });

});

/*
    GET /api/note/stat
    상품종류에 해당하는 자료를 조회(필터링된 조건을 분석해서)하여 2년사이의 데이터를 반환

    ERROR CODES
        2 : PERMISSION DENIED
*/
router.get('/stat', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    const { category, filters } = req.query;

    // 찾고자 하는 자료를 2년내로 한정한다
	const c_year = (new Date()).getFullYear();
    const date = {
        $gte: new Date((c_year-1), 0, 1),
        $lt: new Date((c_year+1), 0, 1)
    };

    let condition;

    if ( category === '전체') {
        condition = {
            'delivery.date': date
        };
    } else {
        condition = {
            $and: [
                { 'delivery.date': date },
                { 'delivery.category': category }
            ]
        };
    }

    if (filters && filters.length > 0) {
        const regex = new RegExp(filters.join('|'), 'gi');

        if ( category === '전체') {
            condition['$or'] = [
                { 'delivery.address': regex },
                { 'delivery.text': regex }
            ];
        } else {
            condition['$and'].push({
                $or: [
                    { 'delivery.address': regex },
                    { 'delivery.text': regex }
                ]
            });
        }
    }

    OrderNote
        .aggregate([
            { $match: condition },
            { $project: {
                yearMonth: { $dateToString: { format: '%Y-%m', date: '$delivery.date' }},
                price: '$delivery.price',
                deliveryCount: '$delivery.count'
            }},
            { $group: {
                _id: {
                    yearMonth: '$yearMonth',
                    price: '$price'
                },
                count: { $sum: '$deliveryCount' }
            }},
            { $group: {
                _id: '$_id.yearMonth',
                count: { $sum: '$count' },
                detail: {
                    $push: { price: '$_id.price', count: '$count' }
                }
            }},
            { $sort: {
                _id: 1
            }}
        ], (err, stats) => {
            if (err) throw err;

            return res.json({
                data: stats
            });

        });

});

/*
    GET /api/note/:id
    특정 장부를 조회

    ERROR CODES
        1 : INVALID ID
        2 : PERMISSION DENIED
        3 : NO RESOURCE
*/
router.get('/:id', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    if (!mongoose.Types.ObjectId.isValid(req.params.id)) {
        return res.status(400).json({
            error: 'INVALID ID',
            code: 1
        });
    }

    OrderNote.findById(req.params.id, (err, note) => {
        if (err) throw err;

        if (!note) {
            return res.status(400).json({
                error: 'NO RESOURCE',
                code: 3
            });
        }
    });

});

module.exports = router;<commit_msg>폰번호로 검색할때 날짜로 오인하는 것과 locale을 적용해서 달력에 표시하는 것 수정<commit_after>const express = require('express');
const mongoose = require('mongoose');
const moment = require('moment');
const OrderNote = require('./../models/OrderNote');
const Orderer = require('./../models/Orderer');
const util = require('./../helper');

mongoose.Promise = global.Promise;

const router = express.Router();

/*
    POST /api/note
    일일장부 등록

    ERROR CODES
        1 : EMPTY REQUIRED FIELD
        2 : PERMISSION DENIED
*/
router.post('/', (req, res) => {

    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    if (util.empty(req.body.orderer_name)) {
        return res.status(400).json({
            error: 'EMPTY REQUIRED FIELD',
            code: 1
        });
    }

    if (util.empty(req.body.receiver_name)) {
        return res.status(400).json({
            error: 'EMPTY REQUIRED FIELD',
            code: 1
        });
    }

    const {
        orderer_name,       // 주문자 이름 또는 회사명
        orderer_phone,      // 주문자 연락처
        orderer_id="no",    // 주문자 고유식별자(등록된 거래처면 ID값으로, 등록되지 않았다면 "no"로 등록)
        receiver_name,      // 받는 분 이름
        receiver_phone,     // 받는 분 연락처
        delivery_category,  // 배달품 종류 (ex. 꽃바구니, 꽃다발, 관엽 등등...)
        delivery_price,     // 가격
        delivery_count,     // 상품 갯수
        delivery_date,      // 배달일자
        delivery_address,   // 배달주소
        delivery_text,      // 글씨(경조사어 및 주문자 이름)
        memo
        // delivery_image,     // 배송된 물품의 사진...(차후 설계하자...)
        // is_payment          // 결제관련 여부 파악 (이것도 차후로...)

    } = req.body;

    let note;

    // 등록된 거래처가 아닌 일반계정으로 장부 입력시
    if (orderer_id === 'no') {
        const c_year = (new Date()).getFullYear();
        const date = {
            $gte: new Date(c_year, 0, 1),
            $lt: new Date((c_year+1), 0, 1)
        };

        const condition = {
            '$and': [
                { 'orderer.id': 'no' },
                { 'orderer.name': orderer_name.trim() },
                { 'orderer.phone': orderer_phone },
                { 'delivery.date': date }
            ]
        };

        // 똑같은 주문자명과 연락처로 장부건수가 1년사이 9건이 넘을 경우
        // 10건째부터는 거래처로 등록한다.
        OrderNote.count(condition, (errCount, count) => {
            if (errCount) throw errCount;

            if (count >= 9) {
                let orderer = new Orderer({
                    'name': orderer_name.trim(),
                    'phone': orderer_phone,
                    'def_ribtext': delivery_text
                });

                orderer.save( (errOrdererSave) => {
                    if (errOrdererSave) throw errOrdererSave;

                    // 기존 일반계정으로 등록되어 있던 장부들은 새로이 등록된 거래처 아이디로 업데이트한다.
                    OrderNote.updateMany({
                        $and: [
                            { 'orderer.id': 'no' },
                            { 'orderer.name': orderer_name.trim() },
                            { 'orderer.phone': orderer_phone }
                        ]
                    },
                    { 'orderer.id': orderer._id },
                    (errUpdate, raw) => {
                        if (errUpdate) throw errUpdate;

                        if (raw) {
                            note = new OrderNote({
                                'orderer.name': orderer_name.trim(),
                                'orderer.phone': orderer_phone,
                                'orderer.id': orderer._id,
                                'receiver.name': receiver_name.trim(),
                                'receiver.phone': receiver_phone,
                                'delivery.category': delivery_category,
                                'delivery.price': delivery_price,
                                'delivery.count': delivery_count,
                                'delivery.date': new Date(delivery_date),
                                'delivery.address': delivery_address,
                                'delivery.text': delivery_text,
                                'memo': memo
                            });

                            note.save( (errSave) => {
                                if (errSave) throw errSave;

                                return res.json({
                                    success: true,
                                    id: note._id
                                });
                            });
                        }
                    });
                });
            } else {    // 9건이 넘지않을 경우에는 기존 방식대로 일반계정으로 등록한다.
                note = new OrderNote({
                    'orderer.name': orderer_name.trim(),
                    'orderer.phone': orderer_phone,
                    'orderer.id': orderer_id,
                    'receiver.name': receiver_name.trim(),
                    'receiver.phone': receiver_phone,
                    'delivery.category': delivery_category,
                    'delivery.price': delivery_price,
                    'delivery.count': delivery_count,
                    'delivery.date': new Date(delivery_date),
                    'delivery.address': delivery_address,
                    'delivery.text': delivery_text,
                    'memo': memo
                });

                note.save( (errSave) => {
                    if (errSave) throw errSave;

                    return res.json({
                        success: true,
                        id: note._id
                    });
                });
            }
        });
    } else {
        note = new OrderNote({
            'orderer.name': orderer_name.trim(),
            'orderer.phone': orderer_phone,
            'orderer.id': orderer_id,
            'receiver.name': receiver_name.trim(),
            'receiver.phone': receiver_phone,
            'delivery.category': delivery_category,
            'delivery.price': delivery_price,
            'delivery.count': delivery_count,
            'delivery.date': new Date(delivery_date),
            'delivery.address': delivery_address,
            'delivery.text': delivery_text,
            'memo': memo
        });

        note.save( (errSave) => {
            if (errSave) throw errSave;

            return res.json({
                success: true,
                id: note._id
            });
        });
    }
});

/*
    GET /api/note
    모든 장부들 조회

    ERROR CODES
        1 : PERMISSION DENIED
*/
router.get('/', (req, res) => {

    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 1
        });
    }

    // 보여주고 싶은 field를 설정
    const projection = {
        '_id': 1,
        'orderer.name': 1,
        'receiver.name': 1,
        'delivery.category': 1,
        'delivery.price': 1,
        'delivery.count': 1,
        'delivery.address': 1,
        'delivery.date': 1,
        // 'delivery.image': 1,
        'is_payment': 1
        // 'memo': 1
    };

    OrderNote.find({}, projection)
        .sort({'delivery.date': -1})
        .exec( (err, notes) => {
            if (err) throw err;

            return res.json({
                success: true,
                data: notes
            });
        });
});

/*
    GET /api/note/today
    특정 장부를 조회

    ERROR CODES
        2 : PERMISSION DENIED
        3 : NO RESOURCE
*/
router.get('/today', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    const today = moment();
    today.hour(1).minute(0);

    const tomorrow = moment(today).add(1, 'day');
    tomorrow.hour(0).minute(0);

    OrderNote
        .find({
            'delivery.date': { $gte: today.toDate(), $lt: tomorrow.toDate() }
        })
        .sort({ 'delivery.date': -1 })
        .exec((err, notes) => {
            if (err) throw err;

            if (notes.length === 0) {
                return res.status(400).json({
                    error: 'NO RESOURCE',
                    code: 3
                });
            }

            return res.json({
                data: notes
            });
        });
});

/*
    GET /api/note/search/:searchTxt
    특정 장부를 조회

    ERROR CODES
        2 : PERMISSION DENIED
*/
router.get('/search/:searchTxt', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    const searchTxt = decodeURIComponent(req.params.searchTxt);

    let condition = null;

    // 찾고자 하는 날짜로 검색
    if (searchTxt.indexOf('-') !== -1 && searchTxt.indexOf('0') !== 0) {
        const dateArray = [];
        searchTxt.split('-').forEach( (d) => {
            dateArray.push(parseInt(d, 10));
        });

        condition = {
            'delivery.date': {
                $gte: new Date(dateArray[0], dateArray[1]-1, dateArray[2], 0, 0, 0),
                $lt: new Date(dateArray[0], dateArray[1]-1, dateArray[2], 23, 0, 0)
            }
        };
    } else {    // 찾고자 하는 검색어로 검색
        condition = {
            $or: [
                {'orderer.name': new RegExp(searchTxt, 'i')},
                {'orderer.phone': new RegExp(searchTxt, 'i')},
                {'receiver.name': new RegExp(searchTxt, 'i')},
                {'receiver.phone': new RegExp(searchTxt, 'i')},
                {'delivery.address': new RegExp(searchTxt, 'i')},
                {'delivery.text': new RegExp(searchTxt, 'i')},
                {'memo': new RegExp(searchTxt, 'i')}
            ]
        };
    }

    OrderNote
        .find(condition)
        .sort({'delivery.date': -1})
        .exec( (err, notes) => {
            if (err) throw err;

            return res.json({
                data: notes
            });

        });

});

/*
    GET /api/note/month/:month
    month 월에 해당하는 자료를 조회

    ERROR CODES
        2 : PERMISSION DENIED
*/
router.get('/month/:month', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    // 찾고자 하는 년, 월로 검색 (Calendar)
    const now = new Date(req.params.month);
    const lastDayOfMonth = new Date(now.getFullYear(), (now.getMonth()+1));
    lastDayOfMonth.setHours(lastDayOfMonth.getHours()-1);

    const condition = {
        'delivery.date': {
            $gt: now,
            $lte: lastDayOfMonth
        }
    };

    OrderNote
        .aggregate([
            { $match: condition },
            { $project: {
                d: {
                    $dayOfMonth: {
                        date: '$delivery.date',
                        timezone: 'Asia/Seoul'
                    }
                }
            }},
            { $group: {
                _id: '$d'
            }},
            { $sort: {
                _id: 1
            }}
        ], (err, notes) => {
            if (err) throw err;

            return res.json({
                data: notes
            });

        });

});

/*
    GET /api/note/stat
    상품종류에 해당하는 자료를 조회(필터링된 조건을 분석해서)하여 2년사이의 데이터를 반환

    ERROR CODES
        2 : PERMISSION DENIED
*/
router.get('/stat', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    const { category, filters } = req.query;

    // 찾고자 하는 자료를 2년내로 한정한다
	const c_year = (new Date()).getFullYear();
    const date = {
        $gte: new Date((c_year-1), 0, 1),
        $lt: new Date((c_year+1), 0, 1)
    };

    let condition;

    if ( category === '전체') {
        condition = {
            'delivery.date': date
        };
    } else {
        condition = {
            $and: [
                { 'delivery.date': date },
                { 'delivery.category': category }
            ]
        };
    }

    if (filters && filters.length > 0) {
        const regex = new RegExp(filters.join('|'), 'gi');

        if ( category === '전체') {
            condition['$or'] = [
                { 'delivery.address': regex },
                { 'delivery.text': regex }
            ];
        } else {
            condition['$and'].push({
                $or: [
                    { 'delivery.address': regex },
                    { 'delivery.text': regex }
                ]
            });
        }
    }

    OrderNote
        .aggregate([
            { $match: condition },
            { $project: {
                yearMonth: { $dateToString: { format: '%Y-%m', date: '$delivery.date' }},
                price: '$delivery.price',
                deliveryCount: '$delivery.count'
            }},
            { $group: {
                _id: {
                    yearMonth: '$yearMonth',
                    price: '$price'
                },
                count: { $sum: '$deliveryCount' }
            }},
            { $group: {
                _id: '$_id.yearMonth',
                count: { $sum: '$count' },
                detail: {
                    $push: { price: '$_id.price', count: '$count' }
                }
            }},
            { $sort: {
                _id: 1
            }}
        ], (err, stats) => {
            if (err) throw err;

            return res.json({
                data: stats
            });

        });

});

/*
    GET /api/note/:id
    특정 장부를 조회

    ERROR CODES
        1 : INVALID ID
        2 : PERMISSION DENIED
        3 : NO RESOURCE
*/
router.get('/:id', (req, res) => {
    if (typeof req.session.loginInfo === 'undefined') {
        return res.status(401).json({
            error: 'PERMISSION DENIED',
            code: 2
        });
    }

    if (!mongoose.Types.ObjectId.isValid(req.params.id)) {
        return res.status(400).json({
            error: 'INVALID ID',
            code: 1
        });
    }

    OrderNote.findById(req.params.id, (err, note) => {
        if (err) throw err;

        if (!note) {
            return res.status(400).json({
                error: 'NO RESOURCE',
                code: 3
            });
        }
    });

});

module.exports = router;<|endoftext|>


<commit_before>$(document).ready(function() {
  $.ajaxSetup({ cache: true });
  $.getScript('https://connect.facebook.net/en_US/sdk.js', function(){
    FB.init({
      appId: '{1589516044683643}',
      version: 'v2.5' // or v2.0, v2.1, v2.2, v2.3
    });
    $('#loginbutton,#feedbutton').removeAttr('disabled');
    FB.getLoginStatus(updateStatusCallback);
  });
});

function updateStatusCallback(){
   console.log('Status updated!!');
   // Your logic here
}

// This is called with the results from from FB.getLoginStatus().
function statusChangeCallback(response) {
  console.log('statusChangeCallback');
  console.log(response);
  // The response object is returned with a status field that lets the
  // app know the current login status of the person.
  // Full docs on the response object can be found in the documentation
  // for FB.getLoginStatus().
  if (response.status === 'connected') {
    // Logged into your app and Facebook.
    testAPI();
    //window.location.href = '/exp';
    console.log('Redirected?');
  } else if (response.status === 'not_authorized') {
    // The person is logged into Facebook, but not your app.
    document.getElementById('status').innerHTML = 'Please log ' +
      'into this app.';
  } else {
    // The person is not logged into Facebook, so we're not sure if
    // they are logged into this app or not.
    document.getElementById('status').innerHTML = 'Please log ' +
      'into Facebook.';
  }
}

// This function is called when someone finishes with the Login
// Button.  See the onlogin handler attached to it in the sample
// code below.
function checkLoginState() {
  FB.getLoginStatus(function(response) {
    statusChangeCallback(response);
    /*window.top.location = "/exp";
    console.log("Redirect!");*/
  });
}

window.fbAsyncInit = function() {
  FB.init({
    appId      : '1589516044683643',
    cookie     : true,  // enable cookies to allow the server to access
                        // the session
    xfbml      : true,  // parse social plugins on this page
    version    : 'v2.2' // use version 2.2
  });

  // Now that we've initialized the JavaScript SDK, we call
  // FB.getLoginStatus().  This function gets the state of the
  // person visiting this page and can return one of three states to
  // the callback you provide.  They can be:
  //
  // 1. Logged into your app ('connected')
  // 2. Logged into Facebook, but not your app ('not_authorized')
  // 3. Not logged into Facebook and can't tell if they are logged into
  //    your app or not.
  //
  // These three cases are handled in the callback function.

  FB.getLoginStatus(function(response) {
    statusChangeCallback(response);
  });
};

// Load the SDK asynchronously
(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "https://connect.facebook.net/en_US/sdk.js";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

// Here we run a very simple test of the Graph API after login is
// successful.  See statusChangeCallback() for when this call is made.
function testAPI() {
  console.log('Welcome!  Fetching your information.... ');
  FB.api('/me', function(response) {
    userID = JSON.stringify(response.id);
    console.log("resp: " + JSON.stringify(response));
    console.log("userID: " + userID);
    console.log('Successful login for: ' + response.name);
    /*document.getElementById('status').innerHTML =
      'Thanks for logging in, ' + response.name + '!';*/
    alert('Thanks for logging in, ' + response.name + '!');
    window.location.href = '/exp';
  });
}

function logOut() {
  try {
    if (FB.getAccessToken() != null) {
      FB.logout(function(response) {
        // user is now logged out from facebook do your post request or just redirect
        console.log("No Err-Logout")
        window.location.replace("/");
        });
      } else {
        // user is not logged in with facebook, maybe with something else
        console.log("Not logged in");
        window.location.replace();
      }
  } catch (err) {
    // any errors just logout
    console.log("Err-forced logout");
    window.location.replace("/");
  }
}
/*
  if (!response.session) {
    window.location = "/";
    return;
  }

  FB.logout(function(response) {
    window.location.href = '/';
    console.log("Logged out");
  });
}*/

function getProfileInfo() {
  FB.getLoginStatus(function(response) {
    if (response.status === 'connected') {
      // the user is logged in and has authenticated your
      // app, and response.authResponse supplies
      // the user's ID, a valid access token, a signed
      // request, and the time the access token
      // and signed request each expire
      var uid = response.authResponse.userID;
      var accessToken = response.authResponse.accessToken;

      FB.api('/me', function(response) {
        document.getElementById('userName').innerHTML = response.name;
        //alert ("Welcome " + response.name + ": Your UID is " + response.id);
        console.log("response.id: " + response.id);
        console.log("uid: " + uid);
        console.log("accessToken: " + accessToken);
      });

      FB.api('/me', 'GET', {fields: 'picture.width(175).height(175)'}, function(response) {
        console.log("response pic data url: " + response.picture.data.url);
				document.getElementById('profPic').innerHTML = "";
			});

      FB.api('/me/user_friends', 'GET', {fields: 'user_friends'}, function(response) {
        console.log("response: " + JSON.stringify(response));
        console.log("user friends: " + response.user_friends);
				//document.getElementById('profPic').innerHTML = "";
			});

      /*
      FB.api('/me', 'GET', {fields: 'first_name,last_name,name,id,picture.width(150).height(150)'}, function(response) {
				document.getElementById('status').innerHTML = "";
			});
      */
/*
      FB.api(
        //"/{user-id}/picture",
        "{"+ uid +"}/picture",
        function (response) {
          console.log("resp: " + JSON.stringify(response));
          if (response && !response.error) {
          }
        }
      );*/
    } else if (response.status === 'not_authorized') {
      // the user is logged in to Facebook,
      // but has not authenticated your app
    } else {
      // the user isn't logged in to Facebook.
    }
  });

        /*
    console.log("userID: " + userID);
    FB.api(
      //"/{user-id}/picture",
      "{user-id}/picture",
      function (response) {
        console.log(response);
        console.log("resp: " + JSON.stringify(response));
        if (response && !response.error) {
          //document.getElementById('profPic').innerHTML = response.

        }
      }
    );

    FB.api('/me', function(response) {
      console.log("Changing profile pic");
      document.getElementById('userName').innerHTML = response.name;
    });*/
}
<commit_msg>made proc pic even smaller<commit_after>$(document).ready(function() {
  $.ajaxSetup({ cache: true });
  $.getScript('https://connect.facebook.net/en_US/sdk.js', function(){
    FB.init({
      appId: '{1589516044683643}',
      version: 'v2.5' // or v2.0, v2.1, v2.2, v2.3
    });
    $('#loginbutton,#feedbutton').removeAttr('disabled');
    FB.getLoginStatus(updateStatusCallback);
  });
});

function updateStatusCallback(){
   console.log('Status updated!!');
   // Your logic here
}

// This is called with the results from from FB.getLoginStatus().
function statusChangeCallback(response) {
  console.log('statusChangeCallback');
  console.log(response);
  // The response object is returned with a status field that lets the
  // app know the current login status of the person.
  // Full docs on the response object can be found in the documentation
  // for FB.getLoginStatus().
  if (response.status === 'connected') {
    // Logged into your app and Facebook.
    testAPI();
    //window.location.href = '/exp';
    console.log('Redirected?');
  } else if (response.status === 'not_authorized') {
    // The person is logged into Facebook, but not your app.
    document.getElementById('status').innerHTML = 'Please log ' +
      'into this app.';
  } else {
    // The person is not logged into Facebook, so we're not sure if
    // they are logged into this app or not.
    document.getElementById('status').innerHTML = 'Please log ' +
      'into Facebook.';
  }
}

// This function is called when someone finishes with the Login
// Button.  See the onlogin handler attached to it in the sample
// code below.
function checkLoginState() {
  FB.getLoginStatus(function(response) {
    statusChangeCallback(response);
    /*window.top.location = "/exp";
    console.log("Redirect!");*/
  });
}

window.fbAsyncInit = function() {
  FB.init({
    appId      : '1589516044683643',
    cookie     : true,  // enable cookies to allow the server to access
                        // the session
    xfbml      : true,  // parse social plugins on this page
    version    : 'v2.2' // use version 2.2
  });

  // Now that we've initialized the JavaScript SDK, we call
  // FB.getLoginStatus().  This function gets the state of the
  // person visiting this page and can return one of three states to
  // the callback you provide.  They can be:
  //
  // 1. Logged into your app ('connected')
  // 2. Logged into Facebook, but not your app ('not_authorized')
  // 3. Not logged into Facebook and can't tell if they are logged into
  //    your app or not.
  //
  // These three cases are handled in the callback function.

  FB.getLoginStatus(function(response) {
    statusChangeCallback(response);
  });
};

// Load the SDK asynchronously
(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "https://connect.facebook.net/en_US/sdk.js";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));

// Here we run a very simple test of the Graph API after login is
// successful.  See statusChangeCallback() for when this call is made.
function testAPI() {
  console.log('Welcome!  Fetching your information.... ');
  FB.api('/me', function(response) {
    userID = JSON.stringify(response.id);
    console.log("resp: " + JSON.stringify(response));
    console.log("userID: " + userID);
    console.log('Successful login for: ' + response.name);
    /*document.getElementById('status').innerHTML =
      'Thanks for logging in, ' + response.name + '!';*/
    alert('Thanks for logging in, ' + response.name + '!');
    window.location.href = '/exp';
  });
}

function logOut() {
  try {
    if (FB.getAccessToken() != null) {
      FB.logout(function(response) {
        // user is now logged out from facebook do your post request or just redirect
        console.log("No Err-Logout")
        window.location.replace("/");
        });
      } else {
        // user is not logged in with facebook, maybe with something else
        console.log("Not logged in");
        window.location.replace();
      }
  } catch (err) {
    // any errors just logout
    console.log("Err-forced logout");
    window.location.replace("/");
  }
}
/*
  if (!response.session) {
    window.location = "/";
    return;
  }

  FB.logout(function(response) {
    window.location.href = '/';
    console.log("Logged out");
  });
}*/

function getProfileInfo() {
  FB.getLoginStatus(function(response) {
    if (response.status === 'connected') {
      // the user is logged in and has authenticated your
      // app, and response.authResponse supplies
      // the user's ID, a valid access token, a signed
      // request, and the time the access token
      // and signed request each expire
      var uid = response.authResponse.userID;
      var accessToken = response.authResponse.accessToken;

      FB.api('/me', function(response) {
        document.getElementById('userName').innerHTML = response.name;
        //alert ("Welcome " + response.name + ": Your UID is " + response.id);
        console.log("response.id: " + response.id);
        console.log("uid: " + uid);
        console.log("accessToken: " + accessToken);
      });

      FB.api('/me', 'GET', {fields: 'picture.width(150).height(150)'}, function(response) {
        console.log("response pic data url: " + response.picture.data.url);
				document.getElementById('profPic').innerHTML = "";
			});

      FB.api('/me/user_friends', 'GET', {fields: 'user_friends'}, function(response) {
        console.log("response: " + JSON.stringify(response));
        console.log("user friends: " + response.user_friends);
				//document.getElementById('profPic').innerHTML = "";
			});

      /*
      FB.api('/me', 'GET', {fields: 'first_name,last_name,name,id,picture.width(150).height(150)'}, function(response) {
				document.getElementById('status').innerHTML = "";
			});
      */
/*
      FB.api(
        //"/{user-id}/picture",
        "{"+ uid +"}/picture",
        function (response) {
          console.log("resp: " + JSON.stringify(response));
          if (response && !response.error) {
          }
        }
      );*/
    } else if (response.status === 'not_authorized') {
      // the user is logged in to Facebook,
      // but has not authenticated your app
    } else {
      // the user isn't logged in to Facebook.
    }
  });

        /*
    console.log("userID: " + userID);
    FB.api(
      //"/{user-id}/picture",
      "{user-id}/picture",
      function (response) {
        console.log(response);
        console.log("resp: " + JSON.stringify(response));
        if (response && !response.error) {
          //document.getElementById('profPic').innerHTML = response.

        }
      }
    );

    FB.api('/me', function(response) {
      console.log("Changing profile pic");
      document.getElementById('userName').innerHTML = response.name;
    });*/
}
<|endoftext|>


<commit_before>// @flow

const promisify = require('util').promisify;
const OpenShiftClient = require('openshift-client');
const R = require('ramda');
const { createJWTWithoutUserId } = require('@lagoon/commons/src/jwt');
const { logger } = require('@lagoon/commons/src/local-logging');
const {
  getOpenShiftInfoForProject,
  updateTask
} = require('@lagoon/commons/src/api');
const {
  sendToLagoonLogs,
  initSendToLagoonLogs
} = require('@lagoon/commons/src/logs');
const {
  consumeTasks,
  initSendToLagoonTasks,
  createTaskMonitor
} = require('@lagoon/commons/src/tasks');

const lagoonApiRoute = R.compose(
  // Default to the gateway IP in virtualbox, so pods running in minishift can
  // connect to docker-for-mac containers.
  R.defaultTo('http://10.0.2.2:3000'),
  R.find(R.test(/api-/)),
  R.split(','),
  R.propOr('', 'LAGOON_ROUTES')
)(process.env);

initSendToLagoonLogs();
initSendToLagoonTasks();

const messageConsumer = async msg => {
  const { project, task, environment } = JSON.parse(msg.content.toString());

  logger.verbose(
    `Received JobOpenshift task for project: ${project.name}, task: ${task.id}`
  );

  const result = await getOpenShiftInfoForProject(project.name);
  const projectOpenShift = result.project;

  const ocsafety = string =>
    string.toLocaleLowerCase().replace(/[^0-9a-z-]/g, '-');

  try {
    var safeBranchName = ocsafety(environment.name);
    var safeProjectName = ocsafety(project.name);
    var openshiftConsole = projectOpenShift.openshift.consoleUrl.replace(
      /\/$/,
      ''
    );
    var openshiftToken = projectOpenShift.openshift.token || '';
    var openshiftProject = projectOpenShift.openshiftProjectPattern
      ? projectOpenShift.openshiftProjectPattern
          .replace('${branch}', safeBranchName)
          .replace('${project}', safeProjectName)
      : `${safeProjectName}-${safeBranchName}`;
    var jobName = `${openshiftProject}-${task.id}`;
  } catch (error) {
    logger.error(`Error while loading information for project ${project.name}`);
    logger.error(error);
    throw error;
  }

  const jobConfig = (name, spec) => {
    let config = {
      apiVersion: 'batch/v1',
      kind: 'Job',
      metadata: {
        name
      },
      spec: {
        parallelism: 1,
        completions: 1,
        backoffLimit: 0,
        template: {
          metadata: {
            name: 'pi'
          },
          spec: {
            ...spec,
            restartPolicy: 'Never'
          }
        }
      }
    };

    return config;
  };

  // OpenShift API object
  const openshift = new OpenShiftClient.OApi({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    }
  });

  // Kubernetes API Object - needed as some API calls are done to the Kubernetes API part of OpenShift and
  // the OpenShift API does not support them.
  const kubernetes = new OpenShiftClient.Core({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    }
  });

  const batchApi = new OpenShiftClient.Batch({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    }
  });

  let projectStatus = {};
  try {
    const projectsGet = promisify(openshift.projects(openshiftProject).get);
    projectStatus = await projectsGet();
  } catch (err) {
    if (err.code == 404) {
      logger.error(`Project ${openshiftProject} does not exist, bailing`);
      return;
    } else {
      logger.error(err);
      throw new Error();
    }
  }

  // Get pod spec for desired service
  let taskPodSpec;
  try {
    const podsGet = promisify(kubernetes.ns(openshiftProject).pods.get);
    const pods = await podsGet();

    const oneContainerPerSpec = pods.items.reduce(
      (specs, pod) => ({
        ...specs,
        ...pod.spec.containers.reduce(
          (specs, container) => ({
            ...specs,
            [container.name]: {
              ...pod.spec,
              containers: [container]
            }
          }),
          {}
        )
      }),
      {}
    );

    if (!oneContainerPerSpec[task.service]) {
      logger.error(`No spec for service ${task.service}, bailing`);
      return;
    }

    // Create an API token that this task pod can use. It only has permissions
    // for the tasks project, and only has access for 1 day.
    const apiToken = createJWTWithoutUserId ({
      payload: {
        role: 'none',
        permissions: {
          projects: [project.id],
          customers: [],
        },
        aud: process.env.JWTAUDIENCE,
        iss: 'openshiftjobs',
        sub: 'openshiftjobs',
      },
      expiresIn: '1d',
      jwtSecret: process.env.JWTSECRET,
    });

    const cronjobEnvVars = env => env.name === 'CRONJOBS';
    const containerEnvLens = R.lensPath(['containers', 0, 'env']);
    const removeCronjobs = R.over(containerEnvLens, R.reject(cronjobEnvVars));
    const addTaskEnvVars = R.over(containerEnvLens, R.concat([
      {
        name: 'TASK_API_HOST',
        value: lagoonApiRoute,
      },
      {
        name: 'TASK_API_AUTH',
        value: apiToken,
      },
      {
        name: 'TASK_DATA_ID',
        value: task.id,
      },
    ]));

    const containerCommandLens = R.lensPath(['containers', 0, 'command']);
    const setContainerCommand = R.set(containerCommandLens, [
      '/sbin/tini',
      '--',
      '/lagoon/entrypoints.sh',
      '/bin/sh',
      '-c',
      task.command,
    ]);

    taskPodSpec = R.pipe(
      R.prop(task.service),
      removeCronjobs,
      addTaskEnvVars,
      setContainerCommand,
    )(oneContainerPerSpec);
  } catch (err) {
    logger.error(err);
    throw new Error(err);
  }

  // Create a new openshift job to run the lagoon task
  let openshiftJob;
  try {
    const jobConfigPost = promisify(
      batchApi.namespaces(openshiftProject).jobs.post
    );
    openshiftJob = await jobConfigPost({
      body: jobConfig(jobName, taskPodSpec)
    });
  } catch (err) {
    logger.error(err);
    throw new Error();
  }

  // Update lagoon task
  let updatedTask;
  try {
    const convertDateFormat = R.init;
    const dateOrNull = R.unless(R.isNil, convertDateFormat);

    updatedTask = await updateTask(task.id, {
      remoteId: openshiftJob.metadata.uid,
      created: convertDateFormat(openshiftJob.metadata.creationTimestamp),
      started: dateOrNull(openshiftJob.status.startTime)
    });
  } catch (error) {
    logger.error(
      `Could not update task ${project.name} ${task.name}. Message: ${error}`
    );
  }

  logger.verbose(`${openshiftProject}: Running job: ${task.name}`);

  const monitorPayload = {
    task: updatedTask.updateTask,
    project,
    environment
  };

  const taskMonitorLogs = await createTaskMonitor(
    'job-openshift',
    monitorPayload
  );

  sendToLagoonLogs(
    'start',
    project.name,
    '',
    'task:job-openshift:start',
    {},
    `*[${project.name}]* Task \`${task.id}\` *${task.name}* started`
  );
};

const deathHandler = async (msg, lastError) => {
  const { project, task } = JSON.parse(msg.content.toString());

  sendToLagoonLogs(
    'error',
    project.name,
    '',
    'task:job-openshift:error',
    {},
    `*[${project.name}]* Task \`${task.id}\` *${task.name}* ERROR:
\`\`\`
${lastError}
\`\`\``
  );
};

const retryHandler = async (msg, error, retryCount, retryExpirationSecs) => {
  const { project, task } = JSON.parse(msg.content.toString());

  sendToLagoonLogs(
    'warn',
    project.name,
    '',
    'task:job-openshift:retry',
    {
      error: error.message,
      msg: JSON.parse(msg.content.toString()),
      retryCount: 1
    },
    `*[${project.name}]* Task \`${task.id}\` *${task.name}* ERROR:
\`\`\`
${error.message}
\`\`\`
Retrying job in ${retryExpirationSecs} secs`
  );
};

consumeTasks('job-openshift', messageConsumer, retryHandler, deathHandler);
<commit_msg>Get job spec templates from DeploymentConfigs instead of running Pods<commit_after>// @flow

const promisify = require('util').promisify;
const OpenShiftClient = require('openshift-client');
const R = require('ramda');
const { createJWTWithoutUserId } = require('@lagoon/commons/src/jwt');
const { logger } = require('@lagoon/commons/src/local-logging');
const {
  getOpenShiftInfoForProject,
  updateTask
} = require('@lagoon/commons/src/api');
const {
  sendToLagoonLogs,
  initSendToLagoonLogs
} = require('@lagoon/commons/src/logs');
const {
  consumeTasks,
  initSendToLagoonTasks,
  createTaskMonitor
} = require('@lagoon/commons/src/tasks');

const lagoonApiRoute = R.compose(
  // Default to the gateway IP in virtualbox, so pods running in minishift can
  // connect to docker-for-mac containers.
  R.defaultTo('http://10.0.2.2:3000'),
  R.find(R.test(/api-/)),
  R.split(','),
  R.propOr('', 'LAGOON_ROUTES')
)(process.env);

initSendToLagoonLogs();
initSendToLagoonTasks();

const messageConsumer = async msg => {
  const { project, task, environment } = JSON.parse(msg.content.toString());

  logger.verbose(
    `Received JobOpenshift task for project: ${project.name}, task: ${task.id}`
  );

  const result = await getOpenShiftInfoForProject(project.name);
  const projectOpenShift = result.project;

  const ocsafety = string =>
    string.toLocaleLowerCase().replace(/[^0-9a-z-]/g, '-');

  try {
    var safeBranchName = ocsafety(environment.name);
    var safeProjectName = ocsafety(project.name);
    var openshiftConsole = projectOpenShift.openshift.consoleUrl.replace(
      /\/$/,
      ''
    );
    var openshiftToken = projectOpenShift.openshift.token || '';
    var openshiftProject = projectOpenShift.openshiftProjectPattern
      ? projectOpenShift.openshiftProjectPattern
          .replace('${branch}', safeBranchName)
          .replace('${project}', safeProjectName)
      : `${safeProjectName}-${safeBranchName}`;
    var jobName = `${openshiftProject}-${task.id}`;
  } catch (error) {
    logger.error(`Error while loading information for project ${project.name}`);
    logger.error(error);
    throw error;
  }

  const jobConfig = (name, spec) => {
    let config = {
      apiVersion: 'batch/v1',
      kind: 'Job',
      metadata: {
        name
      },
      spec: {
        parallelism: 1,
        completions: 1,
        backoffLimit: 0,
        template: {
          metadata: {
            name: 'pi'
          },
          spec: {
            ...spec,
            restartPolicy: 'Never'
          }
        }
      }
    };

    return config;
  };

  // OpenShift API object
  const openshift = new OpenShiftClient.OApi({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    }
  });

  const batchApi = new OpenShiftClient.Batch({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    }
  });

  let projectStatus = {};
  try {
    const projectsGet = promisify(openshift.projects(openshiftProject).get);
    projectStatus = await projectsGet();
  } catch (err) {
    if (err.code == 404) {
      logger.error(`Project ${openshiftProject} does not exist, bailing`);
      return;
    } else {
      logger.error(err);
      throw new Error();
    }
  }

  // Get pod spec for desired service
  let taskPodSpec;
  try {
    const deploymentConfigsGet = promisify(openshift.ns(openshiftProject).deploymentconfigs.get);
    const deploymentConfigs = await deploymentConfigsGet();

    const oneContainerPerSpec = deploymentConfigs.items.reduce(
      (specs, deploymentConfig) => ({
        ...specs,
        ...deploymentConfig.spec.template.spec.containers.reduce(
          (specs, container) => ({
            ...specs,
            [container.name]: {
              ...deploymentConfig.spec.template.spec,
              containers: [container]
            }
          }),
          {}
        )
      }),
      {}
    );

    if (!oneContainerPerSpec[task.service]) {
      logger.error(`No spec for service ${task.service}, bailing`);
      return;
    }

    // Create an API token that this task pod can use. It only has permissions
    // for the tasks project, and only has access for 1 day.
    const apiToken = createJWTWithoutUserId ({
      payload: {
        role: 'none',
        permissions: {
          projects: [project.id],
          customers: [],
        },
        aud: process.env.JWTAUDIENCE,
        iss: 'openshiftjobs',
        sub: 'openshiftjobs',
      },
      expiresIn: '1d',
      jwtSecret: process.env.JWTSECRET,
    });

    const cronjobEnvVars = env => env.name === 'CRONJOBS';
    const containerEnvLens = R.lensPath(['containers', 0, 'env']);
    const removeCronjobs = R.over(containerEnvLens, R.reject(cronjobEnvVars));
    const addTaskEnvVars = R.over(containerEnvLens, R.concat([
      {
        name: 'TASK_API_HOST',
        value: lagoonApiRoute,
      },
      {
        name: 'TASK_API_AUTH',
        value: apiToken,
      },
      {
        name: 'TASK_DATA_ID',
        value: task.id,
      },
    ]));

    const containerCommandLens = R.lensPath(['containers', 0, 'command']);
    const setContainerCommand = R.set(containerCommandLens, [
      '/sbin/tini',
      '--',
      '/lagoon/entrypoints.sh',
      '/bin/sh',
      '-c',
      task.command,
    ]);

    taskPodSpec = R.pipe(
      R.prop(task.service),
      removeCronjobs,
      addTaskEnvVars,
      setContainerCommand,
    )(oneContainerPerSpec);
  } catch (err) {
    logger.error(err);
    throw new Error(err);
  }

  // Create a new openshift job to run the lagoon task
  let openshiftJob;
  try {
    const jobConfigPost = promisify(
      batchApi.namespaces(openshiftProject).jobs.post
    );
    openshiftJob = await jobConfigPost({
      body: jobConfig(jobName, taskPodSpec)
    });
  } catch (err) {
    logger.error(err);
    throw new Error();
  }

  // Update lagoon task
  let updatedTask;
  try {
    const convertDateFormat = R.init;
    const dateOrNull = R.unless(R.isNil, convertDateFormat);

    updatedTask = await updateTask(task.id, {
      remoteId: openshiftJob.metadata.uid,
      created: convertDateFormat(openshiftJob.metadata.creationTimestamp),
      started: dateOrNull(openshiftJob.status.startTime)
    });
  } catch (error) {
    logger.error(
      `Could not update task ${project.name} ${task.name}. Message: ${error}`
    );
  }

  logger.verbose(`${openshiftProject}: Running job: ${task.name}`);

  const monitorPayload = {
    task: updatedTask.updateTask,
    project,
    environment
  };

  const taskMonitorLogs = await createTaskMonitor(
    'job-openshift',
    monitorPayload
  );

  sendToLagoonLogs(
    'start',
    project.name,
    '',
    'task:job-openshift:start',
    {},
    `*[${project.name}]* Task \`${task.id}\` *${task.name}* started`
  );
};

const deathHandler = async (msg, lastError) => {
  const { project, task } = JSON.parse(msg.content.toString());

  sendToLagoonLogs(
    'error',
    project.name,
    '',
    'task:job-openshift:error',
    {},
    `*[${project.name}]* Task \`${task.id}\` *${task.name}* ERROR:
\`\`\`
${lastError}
\`\`\``
  );
};

const retryHandler = async (msg, error, retryCount, retryExpirationSecs) => {
  const { project, task } = JSON.parse(msg.content.toString());

  sendToLagoonLogs(
    'warn',
    project.name,
    '',
    'task:job-openshift:retry',
    {
      error: error.message,
      msg: JSON.parse(msg.content.toString()),
      retryCount: 1
    },
    `*[${project.name}]* Task \`${task.id}\` *${task.name}* ERROR:
\`\`\`
${error.message}
\`\`\`
Retrying job in ${retryExpirationSecs} secs`
  );
};

consumeTasks('job-openshift', messageConsumer, retryHandler, deathHandler);
<|endoftext|>


<commit_before><commit_msg>Delete toast.js<commit_after><|endoftext|>


<commit_before>//
// Inclass Virtual DOM Exercise
// ============================
//
// You need to implement createElement() and updateElement()
//
;(function(exports) {

'use strict'

function h(tag, props, ...children) {
    return { tag, props: props ? props : { },
        children: Array.isArray(children[0]) ? children[0] : children }
}

function createElement(node) {
	console.log('Create element called for', node)
	// create the element and return it to the caller
	// the node might have event listeners that need to be registered
	// the node might have children that need to be created as well
    var foo = document.createTextNode("I am element")
    // var element = document.createElement(node)
    // perform a tree traversal
    // leaf
    if (!node.children) {
        var leaf = document.createTextNode(node)
        console.log(node)
        return leaf
    }
    var element = document.createElement(node.tag);
    node.children.forEach(function (item) {
        // console.log(item)
        var childElement = createElement(item)
        element.appendChild(childElement)
    });
    // loop through property object
    Object.keys(node.props).forEach(function (key, index) {
        // console.log('att : ' + key)
        // console.log('value : ' + node.props[key])
        var attName = key
        if (key === 'className') {
            attName = 'class'
        }
        if (key === 'onClick') {
            attName = 'onclick'
        }
        var att = document.createAttribute(attName)
        att.value = node.props[key]
        element.setAttributeNode(att)
    })

	return element;
}

function changed(node1, node2) {
    return typeof node1 !== typeof node2 ||
            (typeof node1 === 'string' && node1 !== node2) ||
            node1.tag !== node2.tag ||
            (node1.props && node2.props &&
            	node1.props.id && node2.props.id &&
            	node1.props.id != node2.props.id)
}

function updateElement(parent, newNode, oldNode, index=0) {
	// index will be needed when you traverse children
	// add the new node to the parent DOM element if
	// the new node is different from the old node
	// at the same location in the DOM.
	// ideally we also handle inserts, but ignore that functionality for now.

    if (!oldNode) {
        parent.appendChild(createElement(newNode))
    } else {
    	console.log('update element that may have changed')
    	// you can use my changed(node1, node2) method above
    	// to determine if an element has changed or not

    	// be sure to also update the children!
    }
}

const deepCopy = (obj) => {
    if (obj === null || typeof(obj) !== 'object')
        return obj;
    const props = {}
    if (obj.props) {
        for (let p in obj.props) {
            props[p] = obj.props[p]
        }
    }
    return h(obj.tag, props,
        Array.isArray(obj.children) ? obj.children.map(deepCopy) : obj.children)
}

const update = () => requestAnimationFrame(() => {
	// compare the current vdom with the original vdom for updates
    updateElement(h.mounted.root, h.mounted.current, h.mounted.original)
    h.mounted.original = deepCopy(h.mounted.current)
})

h.mount = (root, component) => {
    // we keep a copy of the original virtual DOM so we can diff it later for updates
    const originalComponent = deepCopy(component)
    h.mounted = { root: root, current: component, original: originalComponent }
    updateElement(root, originalComponent)
}

exports.h = h

})(window);<commit_msg>complete createElement()<commit_after>//
// Inclass Virtual DOM Exercise
// ============================
//
// You need to implement createElement() and updateElement()
//
;(function(exports) {

'use strict'

function h(tag, props, ...children) {
    return { tag, props: props ? props : { },
        children: Array.isArray(children[0]) ? children[0] : children }
}

function createElement(node) {
	console.log('Create element called for', node)
	// create the element and return it to the caller
	// the node might have event listeners that need to be registered
	// the node might have children that need to be created as well
    var foo = document.createTextNode("I am element")
    // var element = document.createElement(node)
    // perform a tree traversal
    // leaf
    if (!node.children) {
        var leaf = document.createTextNode(node)
        console.log(node)
        return leaf
    }
    var element = document.createElement(node.tag);
    node.children.forEach(function (item) {
        // console.log(item)
        var childElement = createElement(item)
        element.appendChild(childElement)
    });
    // loop through property object
    Object.keys(node.props).forEach(function (key, index) {
        // console.log('att : ' + key)
        // console.log('value : ' + node.props[key])
        var attName = key
        if (key === 'className') {
            attName = 'class'
        }
        if (key === 'onClick') {
            attName = 'onclick'
        }
        var att = document.createAttribute(attName)
        if (key !== 'onClick') {
            att.value = node.props[key]
            element.setAttributeNode(att)
        } else {
            element.setAttributeNode(att)
            element.onclick = node.props[key]
        }
    })

	return element;
}

function changed(node1, node2) {
    return typeof node1 !== typeof node2 ||
            (typeof node1 === 'string' && node1 !== node2) ||
            node1.tag !== node2.tag ||
            (node1.props && node2.props &&
            	node1.props.id && node2.props.id &&
            	node1.props.id != node2.props.id)
}

function updateElement(parent, newNode, oldNode, index=0) {
	// index will be needed when you traverse children
	// add the new node to the parent DOM element if
	// the new node is different from the old node
	// at the same location in the DOM.
	// ideally we also handle inserts, but ignore that functionality for now.

    if (!oldNode) {
        parent.appendChild(createElement(newNode))
    } else {
    	console.log('update element that may have changed')
    	// you can use my changed(node1, node2) method above
    	// to determine if an element has changed or not

    	// be sure to also update the children!
    }
}

const deepCopy = (obj) => {
    if (obj === null || typeof(obj) !== 'object')
        return obj;
    const props = {}
    if (obj.props) {
        for (let p in obj.props) {
            props[p] = obj.props[p]
        }
    }
    return h(obj.tag, props,
        Array.isArray(obj.children) ? obj.children.map(deepCopy) : obj.children)
}

const update = () => requestAnimationFrame(() => {
	// compare the current vdom with the original vdom for updates
    updateElement(h.mounted.root, h.mounted.current, h.mounted.original)
    h.mounted.original = deepCopy(h.mounted.current)
})

h.mount = (root, component) => {
    // we keep a copy of the original virtual DOM so we can diff it later for updates
    const originalComponent = deepCopy(component)
    h.mounted = { root: root, current: component, original: originalComponent }
    updateElement(root, originalComponent)
}

exports.h = h

})(window);<|endoftext|>


<commit_before>//
//  exoplayer.js
//
// estat Cordova Plugin by Benjamin BEAUVAIS on 22/10/16.
//
// exoplayer Plugin for Cordova Android
// www.lanewscompany.com
//
// MIT Licensed

function exoplayer(){}

// Call this to register for push notifications and retreive a push Token
exoplayer.initPlayer = function(success, fail) {
	cordova.exec(success, fail, "exoplayer", "initPlayer",false);
};

exoplayer.play = function(url,success, fail) {
	cordova.exec(success, fail, "exoplayer", "play", [url]);
};

// Event spawned when a notification is received while the application is active
exoplayer.notificationCallback = function(notification) {
	var ev = document.createEvent('HTMLEvents');
	ev.notification = notification;
	ev.initEvent('push-notification', true, true, arguments);
	document.dispatchEvent(ev);
};

module.exports = exoplayer;
<commit_msg>Update exoplayer.js<commit_after>//
//  exoplayer.js
//
// estat Cordova Plugin by Benjamin BEAUVAIS on 22/10/16.
//
// exoplayer Plugin for Cordova Android
// www.lanewscompany.com
//
// MIT Licensed

function exoplayer(){}

// Call this to register for push notifications and retreive a push Token
exoplayer.initPlayer = function(serial, success, fail) {
	cordova.exec(success, fail, "exoplayer", "initPlayer",[serial]);
};

exoplayer.play = function(url,success, fail) {
	cordova.exec(success, fail, "exoplayer", "play", [url]);
};

// Event spawned when a notification is received while the application is active
exoplayer.notificationCallback = function(notification) {
	var ev = document.createEvent('HTMLEvents');
	ev.notification = notification;
	ev.initEvent('push-notification', true, true, arguments);
	document.dispatchEvent(ev);
};

module.exports = exoplayer;
<|endoftext|>


<commit_before>/* eslint camelcase: 0 */
import common from './common/ru_RU';
import dappsMaker from './dapps-maker/ru_RU';
import dappsSubmission from './dapps-submission/ru_RU';
import home from './home/ru_RU';
import footer from './footer/ru_RU';
import gettingStarted from './getting-started/ru_RU';
import privacyPolicy from './privacy-policy/ru_RU';
import termsOfService from './terms-of-conditions/ru_RU';
import accessWallet from './access-wallet/ru_RU';
import interfaceTranslations from './interface/ru_RU';
import team from './team/ru_RU';
import errorsGlobal from './errors-global/ru_RU';
import trezorError from './errors-trezor/ru_RU';
import ledgerError from './errors-ledger/ru_RU';
import keepkeyError from './errors-keepkey/ru_RU';
import bitboxError from './errors-bitbox/ru_RU';
import buyHardwareWallet from './other/buy-hardware-wallet/ru_RU';
import convertUnits from './other/convert-units/ru_RU';
import verifyMessage from './other/verify-message/ru_RU';
import sendTx from './send-tx/ru_RU';
import ens from './dapps-ens/ru_RU';
import subDomain from './dapps-sub-domain/ru_RU';
import scheduleTx from './dapps-schedule-tx/ru_RU';
import nftManager from './nft-manager/ru_RU';
import signMessage from './sign-message/ru_RU';
import dappsAmbrpay from './dapps-ambrpay/ru_RU';
import phishing from './other/phishing/ru_RU';
import header from './header/ru_RU';
import dappsMCDMaker from './dapps-mcd-maker/ru_RU';

const ru_RU = {
  common: common,
  home: home,
  footer: footer,
  gettingStarted: gettingStarted,
  privacyPol: privacyPolicy,
  termsOfService: termsOfService,
  team: team,
  accessWallet: accessWallet,
  interface: interfaceTranslations,
  errorsGlobal: errorsGlobal,
  trezorError: trezorError,
  ledgerError: ledgerError,
  keepkeyError: keepkeyError,
  bitboxError: bitboxError,
  buyHardwareWallet: buyHardwareWallet,
  dappsMaker: dappsMaker,
  convertUnits: convertUnits,
  verifyMessage: verifyMessage,
  sendTx: sendTx,
  ens: ens,
  subDomain: subDomain,
  scheduleTx: scheduleTx,
  nftManager: nftManager,
  signMessage: signMessage,
  dappsSubmission: dappsSubmission,
  dappsAmbrpay: dappsAmbrpay,
  phishing: phishing,
  header: header,
  dappsMCDMaker: dappsMCDMaker
};
export default ru_RU;
<commit_msg>translation: 🌐 remove team file<commit_after>/* eslint camelcase: 0 */
import common from './common/ru_RU';
import dappsMaker from './dapps-maker/ru_RU';
import dappsSubmission from './dapps-submission/ru_RU';
import home from './home/ru_RU';
import footer from './footer/ru_RU';
import gettingStarted from './getting-started/ru_RU';
import privacyPolicy from './privacy-policy/ru_RU';
import termsOfService from './terms-of-conditions/ru_RU';
import accessWallet from './access-wallet/ru_RU';
import interfaceTranslations from './interface/ru_RU';
import errorsGlobal from './errors-global/ru_RU';
import trezorError from './errors-trezor/ru_RU';
import ledgerError from './errors-ledger/ru_RU';
import keepkeyError from './errors-keepkey/ru_RU';
import bitboxError from './errors-bitbox/ru_RU';
import buyHardwareWallet from './other/buy-hardware-wallet/ru_RU';
import convertUnits from './other/convert-units/ru_RU';
import verifyMessage from './other/verify-message/ru_RU';
import sendTx from './send-tx/ru_RU';
import ens from './dapps-ens/ru_RU';
import subDomain from './dapps-sub-domain/ru_RU';
import scheduleTx from './dapps-schedule-tx/ru_RU';
import nftManager from './nft-manager/ru_RU';
import signMessage from './sign-message/ru_RU';
import dappsAmbrpay from './dapps-ambrpay/ru_RU';
import phishing from './other/phishing/ru_RU';
import header from './header/ru_RU';
import dappsMCDMaker from './dapps-mcd-maker/ru_RU';

const ru_RU = {
  common: common,
  home: home,
  footer: footer,
  gettingStarted: gettingStarted,
  privacyPol: privacyPolicy,
  termsOfService: termsOfService,
  accessWallet: accessWallet,
  interface: interfaceTranslations,
  errorsGlobal: errorsGlobal,
  trezorError: trezorError,
  ledgerError: ledgerError,
  keepkeyError: keepkeyError,
  bitboxError: bitboxError,
  buyHardwareWallet: buyHardwareWallet,
  dappsMaker: dappsMaker,
  convertUnits: convertUnits,
  verifyMessage: verifyMessage,
  sendTx: sendTx,
  ens: ens,
  subDomain: subDomain,
  scheduleTx: scheduleTx,
  nftManager: nftManager,
  signMessage: signMessage,
  dappsSubmission: dappsSubmission,
  dappsAmbrpay: dappsAmbrpay,
  phishing: phishing,
  header: header,
  dappsMCDMaker: dappsMCDMaker
};
export default ru_RU;
<|endoftext|>


<commit_before>if (Meteor.isClient) {
  // This code only runs on the client
  Template.body.helpers({
    fishes: [
      { text: "pygmy angelfish",imageurl:"http://www.seascapestudio.net/reference/fishes/centropyge_argi.jpg" },
      { text: "blue dot grouper",imageurl:"http://www.richard-seaman.com/Underwater/Egypt/Highlights/PeacockGrouper.jpg" },
      { text: "blue line grouper",imageurl:"http://www.aquariumdomain.com/images/fish_marine/grouper_blueline2.jpg" },
      {text:  "teira batfish",imageurl:"http://www.aquariumdomain.com/images/fish_marine/tieraBatfish8.jpg"},
      {text:  "convict blenny",imageurl:"http://www.roslyndakin.com/wp-content/uploads/2011/01/convictadult.jpg"}
    ]
  });
}<commit_msg>linked app to mongo db collection<commit_after>
Fishes = new Mongo.Collection("fishes");
if (Meteor.isClient) {
  // This code only runs on the client
  Template.body.helpers({
    fishes: function () {
      return Fishes.find({});
    }
  });
}<|endoftext|>


<commit_before><commit_msg>update one last key piece<commit_after><|endoftext|>


<commit_before>var database = global.database;
var ranks = global.data.ranks;
var util = global.util;
var viewers = global.util.viewers;
var options = global.options;
var mongoose = global.modules.mongoose;
var sync = global.modules.sync;

database.quotes = mongoose.model(options.twitch.channel + '.quotes', mongoose.Schema({
    quote: String,
    author: String,
    create: Date,
    added: String
}));

module.exports = {
    /*
      usage: !quote <author> <quote>
    */
    quote: function (user, author, quote) {

        // Only viewers can use this
        if (user.rank < ranks.viewer) {
            util.chatter.say(options.output.quote.rank.weave(
                user
            ));
            return;
        }

        // Check both params are there
        if (!author || !quote) {
            util.chatter.say(options.output.quote.syntax);
            return;
        }

        // Params
        author = util.viewers.get(author);
        author = author.name.toLowerCase();
        quote = [].slice.call(arguments, 0);
        quote.splice(0, 2);

        // Find the author
        global.database.users.findOne({name: author}, function (err, user) {
            if (user) {
                // Replace any " in case they added them, and any more than one space
                var sanitizedQuote = quote.join(' ').replace(/\"/g, '').replace(/\s\s+/g, ' ');
                util.chatter.say(options.output.quote.normal.weave(
                    user,
                    sanitizedQuote
                ));
                var newQuote = new global.database.quotes({
                    quote: sanitizedQuote,
                    user: author,
                    create: new Date,
                    added: user.name
                });
                sync.wait(newQuote, 'save', [sync.defer()]);
            } else {
                // Author not found
                util.chatter.say(options.output.quote.unknown.weave(
                    author
                ));
            }
        });
    },
    /*
      usage: !recite <author=[random]>
    */
    recite: function (user, author) {
        // TODO
    }
}
<commit_msg>Quote fixes.<commit_after>var database = global.database;
var ranks = global.data.ranks;
var util = global.util;
var viewers = global.util.viewers;
var options = global.options;
var mongoose = global.modules.mongoose;
var sync = global.modules.sync;

database.quotes = mongoose.model(options.twitch.channel + '.quotes', mongoose.Schema({
    quote: String,
    author: String,
    create: Date,
    added: String
}));

module.exports = {
    /*
      usage: !quote <author> <quote>
    */
    quote: function (user, author, quote) {

        // Only viewers can use this
        if (user.rank < ranks.viewer) {
            util.chatter.say(options.output.quote.rank.weave(
                user
            ));
            return;
        }

        // Check both params are there
        if (!author || !quote) {
            util.chatter.say(options.output.quote.syntax);
            return;
        }

        // Params
        author = util.viewers.get(author);
        author = author.name.toLowerCase();
        quote = [].slice.call(arguments, 0);
        quote.splice(0, 2);

        // Find the author
        global.database.users.findOne({name: author}, function (err, user) {
            if (user) {
                // Remove any more than one space
                var sanitizedQuote = quote.join(' ').replace(/\s\s+/g, ' ');
                util.chatter.say(options.output.quote.normal.weave(
                    user,
                    sanitizedQuote
                ));
                var newQuote = new global.database.quotes({
                    quote: sanitizedQuote,
                    author: author,
                    create: new Date,
                    added: user.name
                });
                sync.wait(newQuote, 'save', [sync.defer()]);
            } else {
                // Author not found
                util.chatter.say(options.output.quote.unknown.weave(
                    author
                ));
            }
        });
    },
    /*
      usage: !recite <author=[random]>
    */
    recite: function (user, author) {
        // TODO
    }
}
<|endoftext|>


<commit_before>
var Xhr = new Class({
  Implements: [Events],
  Binds:['state_change', 'request'],

  encoding:false, //urlencode|multipart
  headers:$H({}),

  initialize:function(async, encoding){
    this.async = $defined(async) ? async : true;
    this.lnk   = new Browser.Request();
    this.encoding = encoding || 'urlencode';
  },

  request:function(url, method, data){

    var encoder = this["encode_"+this.encoding]
    if(!encoder)
        throw "Unknow encoder";

    this.lnk.open( method||'GET' , url, this.async);
    this.lnk.onreadystatechange = this.state_change;

    data = this.data_cleanup(data||[]); //data is a list

    encoder.encode.call(this, data, function(data){
      if(method == 'GET')
          data = null;

      this.headers.each( function(val, key){
          this.lnk.setRequestHeader(key, val);
      }.bind(this));

      this.lnk[encoder.transport_callback](data);

      if((!this.async) && this.lnk.readyState==4)
        this.state_change();
    }.bind(this));

  },

  isSuccess: function(){
    return this.lnk.readyState == 4
           && ((this.lnk.status >= 200) && (this.lnk.status < 300));
  },

    //prepare data as a list of {key:key,value:value} pairs, ready to be encoded
  data_cleanup:function(data){
    var ret = [];
    data.each(function(data){
      switch ($type(data)){
        case 'string' : ret.push(data);break;
        case 'element': ret.extend(document.id(data).toQueryList()); break;
        case 'hash': ret.extend(Hash.toQueryList(data));break;
        case 'object':ret.push(data);break; //default
      }
    });
    return ret;
  },

  addHeaders:function(vals){
    $extend(this.headers, vals);
    return this;
  },

  state_change:function(){
    if(!this.isSuccess()) return false;
    this.lnk.onreadystatechange = $empty; //prevent dbl calls

    var responseHeaders = this.lnk.getAllResponseHeaders();

    if(!responseHeaders){
      var lnk = this.lnk;
      Array.each(['Content-Type'], function(name, index){
        responseHeaders  += name + ': ' + lnk.getResponseHeader(name);
      });
    }

    var headers = Xhr.split_headers(responseHeaders);

    var content_type = (headers['content-type'] || "text/xml").split(';')[0];
    var val;

    if(content_type=="application/json") val = Urls.jsx_eval(this.lnk.responseText);
    else if(!(/[^a-z]xml$/).test(content_type)) val = this.lnk.responseText;
    else {
        val = this.lnk.responseXML;//prepare serialize for later, no other chance after here (BB)
        if(!val.xml && !window.XMLSerializer)
            val.xml = this.lnk.responseText;
    }
    this.fireEvent('success', [val, headers ] );
  }

});

if(Browser.Engine.name == 'webkit'){
  XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
    function byteValue(x) {
      return x.charCodeAt(0) & 0xff;
    }
    var ords = Array.prototype.map.call(datastr, byteValue);
    var ui8a = new Uint8Array(ords);
    this.send(ui8a);
  }
}
<commit_msg>Compatibility IE10<commit_after>
var Xhr = new Class({
  Implements: [Events],
  Binds:['state_change', 'request'],

  encoding:false, //urlencode|multipart
  headers:$H({}),

  initialize:function(async, encoding){
    this.async = $defined(async) ? async : true;
    this.lnk   = new Browser.Request();
    this.encoding = encoding || 'urlencode';
  },

  request:function(url, method, data){

    var encoder = this["encode_"+this.encoding]
    if(!encoder)
        throw "Unknow encoder";

    this.lnk.open( method||'GET' , url, this.async);
    this.lnk.onreadystatechange = this.state_change;
    try { this.lnk.responseType = "msxml-document"; } catch(err){}

    data = this.data_cleanup(data||[]); //data is a list

    encoder.encode.call(this, data, function(data){
      if(method == 'GET')
          data = null;

      this.headers.each( function(val, key){
          this.lnk.setRequestHeader(key, val);
      }.bind(this));

      this.lnk[encoder.transport_callback](data);

      if((!this.async) && this.lnk.readyState==4)
        this.state_change();
    }.bind(this));

  },

  isSuccess: function(){
    return this.lnk.readyState == 4
           && ((this.lnk.status >= 200) && (this.lnk.status < 300));
  },

    //prepare data as a list of {key:key,value:value} pairs, ready to be encoded
  data_cleanup:function(data){
    var ret = [];
    data.each(function(data){
      switch ($type(data)){
        case 'string' : ret.push(data);break;
        case 'element': ret.extend(document.id(data).toQueryList()); break;
        case 'hash': ret.extend(Hash.toQueryList(data));break;
        case 'object':ret.push(data);break; //default
      }
    });
    return ret;
  },

  addHeaders:function(vals){
    $extend(this.headers, vals);
    return this;
  },

  state_change:function(){
    if(!this.isSuccess()) return false;
    this.lnk.onreadystatechange = $empty; //prevent dbl calls

    var responseHeaders = this.lnk.getAllResponseHeaders();

    if(!responseHeaders){
      var lnk = this.lnk;
      Array.each(['Content-Type'], function(name, index){
        responseHeaders  += name + ': ' + lnk.getResponseHeader(name);
      });
    }

    var headers = Xhr.split_headers(responseHeaders);

    var content_type = (headers['content-type'] || "text/xml").split(';')[0];
    var val;

    if(content_type=="application/json") val = Urls.jsx_eval(this.lnk.responseText);
    else if(!(/[^a-z]xml$/).test(content_type)) val = this.lnk.responseText;
    else {
        val = this.lnk.responseXML;//prepare serialize for later, no other chance after here (BB)
        if(!val.xml && !window.XMLSerializer)
            val.xml = this.lnk.responseText;
    }
    this.fireEvent('success', [val, headers ] );
  }

});

if(Browser.Engine.name == 'webkit'){
  XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
    function byteValue(x) {
      return x.charCodeAt(0) & 0xff;
    }
    var ords = Array.prototype.map.call(datastr, byteValue);
    var ui8a = new Uint8Array(ords);
    this.send(ui8a);
  }
}
<|endoftext|>