<commit_before>/**
* DD_roundies, this adds rounded-corner CSS in standard browsers and VML sublayers in IE that accomplish a similar appearance when comparing said browsers.
* Author: Drew Diller
* Email: drew.diller@gmail.com
* URL: http://www.dillerdesign.com/experiment/DD_roundies/
* Version: 0.0.2a -  preview 2008.12.26
* Licensed under the MIT License: http://dillerdesign.com/experiment/DD_roundies/#license
*
* Usage:
* DD_roundies.addRule('#doc .container', '10px 5px'); // selector and multiple radii
* DD_roundies.addRule('.box', 5, true); // selector, radius, and optional addition of border-radius code for standard browsers.
*
* Just want the PNG fixing effect for IE6, and don't want to also use the DD_belatedPNG library?  Don't give any additional arguments after the CSS selector.
* DD_roundies.addRule('.your .example img');
**/

eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('t K={16:\'K\',1L:G,1M:G,1d:G,2f:y(){u(D.2g!=8&&D.1N&&!D.1N[q.16]){q.1L=M;q.1M=M}17 u(D.2g==8){q.1d=M}},2h:D.2i,1O:[],1b:{},2j:y(){u(q.1L||q.1M){D.1N.2L(q.16,\'2M:2N-2O-2P:x\')}u(q.1d){D.2Q(\'<?2R 2S="\'+q.16+\'" 2T="#1P#2k" ?>\')}},2l:y(){t a=D.1k(\'z\');D.2m.1w.1Q(a,D.2m.1w.1w);u(a.12){2n{t b=a.12;b.1x(q.16+\'\\\\:*\',\'{1l:2U(#1P#2k)}\');q.12=b}2o(2p){}}17{q.12=a}},1x:y(a,b,c){u(1R b==\'1S\'||b===2V){b=0}u(b.2W.2q().1y(\'2X\')==-1){b=b.2q().2Y(/[^0-9 ]/g,\'\').1T(\' \')}H(t i=0;i<4;i++){b[i]=(!b[i]&&b[i]!==0)?b[C.1e((i-2),0)]:b[i]}u(q.12){u(q.12.1x){t d=a.1T(\',\');H(t i=0;i<d.1U;i++){q.12.1x(d[i],\'1l:2Z(K.1V.2r(q, [\'+b.1W(\',\')+\']))\')}}17 u(c){t e=b.1W(\'F \')+\'F\';q.12.1z(D.2s(a+\' {Q-1f:\'+e+\'; -30-Q-1f:\'+e+\';}\'));q.12.1z(D.2s(a+\' {-1A-Q-1m-1n-1f:\'+b[0]+\'F \'+b[0]+\'F; -1A-Q-1m-1X-1f:\'+b[1]+\'F \'+b[1]+\'F; -1A-Q-1Y-1X-1f:\'+b[2]+\'F \'+b[2]+\'F; -1A-Q-1Y-1n-1f:\'+b[3]+\'F \'+b[3]+\'F;}\'))}}17 u(q.1d){q.1O.31({\'2t\':a,\'2u\':b})}},2v:y(a){2w(32.33){I\'z.Q\':I\'z.34\':I\'z.1B\':q.1o(a);13;I\'z.2x\':q.1Z(a);13;I\'z.1p\':I\'z.2y\':I\'z.2z\':q.1o(a);13;I\'z.20\':a.18.z.20=(a.z.20==\'S\')?\'S\':\'35\';13;I\'z.21\':q.22(a);13;I\'z.1c\':a.18.z.1c=a.z.1c;13}},1o:y(a){a.14.23=\'\';q.2A(a);q.1Z(a);q.1C(a);q.1D(a);q.24(a);q.2B(a);q.22(a)},22:y(a){u(a.W.21.1y(\'36\')!=-1){t b=a.W.21;b=1g(b.37(b.25(\'=\')+1,b.25(\')\')),10)/2C;H(t v 1h a.x){a.x[v].1i.38=b}}},2A:y(a){u(!a.W){1q}17{t b=a.W}a.14.1p=\'\';a.14.1E=\'\';t c=(b.1p==\'2D\');t d=M;u(b.1E!=\'S\'||a.1F){u(!a.1F){a.J=b.1E;a.J=a.J.39(5,a.J.25(\'")\')-5)}17{a.J=a.26}t e=q;u(!e.1b[a.J]){t f=D.1k(\'3a\');f.1r(\'3b\',y(){q.1s=q.3c;q.1t=q.3d;e.1D(a)});f.3e=e.16+\'3f\';f.14.23=\'1l:S; 1j:27; 1m:-2E; 1n:-2E; Q:S;\';f.26=a.J;f.2F(\'1s\');f.2F(\'1t\');D.2G.1Q(f,D.2G.1w);e.1b[a.J]=f}a.x.Z.1i.26=a.J;d=G}a.x.Z.2H=!d;a.x.Z.1G=\'S\';a.x.1u.2H=!c;a.x.1u.1G=b.1p;a.14.1E=\'S\';a.14.1p=\'2D\'},1Z:y(a){a.x.1H.1G=a.W.2x},1C:y(a){t c=[\'N\',\'19\',\'1a\',\'O\'];a.P={};H(t b=0;b<4;b++){a.P[c[b]]=1g(a.W[\'Q\'+c[b]+\'U\'],10)||0}},1D:y(c){t e=[\'O\',\'N\',\'U\',\'V\'];H(t d=0;d<4;d++){c.E[e[d]]=c[\'3g\'+e[d]]}t f=y(a,b){a.z.1n=(b?0:c.E.O)+\'F\';a.z.1m=(b?0:c.E.N)+\'F\';a.z.1s=c.E.U+\'F\';a.z.1t=c.E.V+\'F\'};H(t v 1h c.x){t g=(v==\'Z\')?1:2;c.x[v].3h=(c.E.U*g)+\', \'+(c.E.V*g);f(c.x[v],M)}f(c.18,G);u(K.1d){c.x.1H.z.28=\'-3i\';u(1R c.P==\'1S\'){q.1C(c)}c.x.1u.z.28=(c.P.N-1)+\'F \'+(c.P.O-1)+\'F\'}},24:y(j){t k=y(a,w,h,r,b,c,d){t e=a?[\'m\',\'1I\',\'l\',\'1J\',\'l\',\'1I\',\'l\',\'1J\',\'l\']:[\'1J\',\'l\',\'1I\',\'l\',\'1J\',\'l\',\'1I\',\'l\',\'m\'];b*=d;c*=d;w*=d;h*=d;t R=r.2I();H(t i=0;i<4;i++){R[i]*=d;R[i]=C.3j(w/2,h/2,R[i])}t f=[e[0]+C.11(0+b)+\',\'+C.11(R[0]+c),e[1]+C.11(R[0]+b)+\',\'+C.11(0+c),e[2]+C.15(w-R[1]+b)+\',\'+C.11(0+c),e[3]+C.15(w+b)+\',\'+C.11(R[1]+c),e[4]+C.15(w+b)+\',\'+C.15(h-R[2]+c),e[5]+C.15(w-R[2]+b)+\',\'+C.15(h+c),e[6]+C.11(R[3]+b)+\',\'+C.15(h+c),e[7]+C.11(0+b)+\',\'+C.15(h-R[3]+c),e[8]+C.11(0+b)+\',\'+C.11(R[0]+c)];u(!a){f.3k()}t g=f.1W(\'\');1q g};u(1R j.P==\'1S\'){q.1C(j)}t l=j.P;t m=j.2J.2I();t n=k(M,j.E.U,j.E.V,m,0,0,2);m[0]-=C.1e(l.O,l.N);m[1]-=C.1e(l.N,l.19);m[2]-=C.1e(l.19,l.1a);m[3]-=C.1e(l.1a,l.O);H(t i=0;i<4;i++){m[i]=C.1e(m[i],0)}t o=k(G,j.E.U-l.O-l.19,j.E.V-l.N-l.1a,m,l.O,l.N,2);t p=k(M,j.E.U-l.O-l.19+1,j.E.V-l.N-l.1a+1,m,l.O,l.N,1);j.x.1u.29=o;j.x.Z.29=p;j.x.1H.29=n+o;q.2K(j)},2B:y(a){t s=a.W;t b=[\'N\',\'O\',\'19\',\'1a\'];H(t i=0;i<4;i++){a.14[\'1B\'+b[i]]=(1g(s[\'1B\'+b[i]],10)||0)+(1g(s[\'Q\'+b[i]+\'U\'],10)||0)+\'F\'}a.14.Q=\'S\'},2K:y(e){t f=K;u(!e.J||!f.1b[e.J]){1q}t g=e.W;t h={\'X\':0,\'Y\':0};t i=y(a,b){t c=M;2w(b){I\'1n\':I\'1m\':h[a]=0;13;I\'3l\':h[a]=0.5;13;I\'1X\':I\'1Y\':h[a]=1;13;1P:u(b.1y(\'%\')!=-1){h[a]=1g(b,10)*0.3m}17{c=G}}t d=(a==\'X\');h[a]=C.15(c?((e.E[d?\'U\':\'V\']-(e.P[d?\'O\':\'N\']+e.P[d?\'19\':\'1a\']))*h[a])-(f.1b[e.J][d?\'1s\':\'1t\']*h[a]):1g(b,10));h[a]+=1};H(t b 1h h){i(b,g[\'2y\'+b])}e.x.Z.1i.1j=(h.X/(e.E.U-e.P.O-e.P.19+1))+\',\'+(h.Y/(e.E.V-e.P.N-e.P.1a+1));t j=g.2z;t c={\'T\':1,\'R\':e.E.U+1,\'B\':e.E.V+1,\'L\':1};t k={\'X\':{\'2a\':\'L\',\'2b\':\'R\',\'d\':\'U\'},\'Y\':{\'2a\':\'T\',\'2b\':\'B\',\'d\':\'V\'}};u(j!=\'2c\'){c={\'T\':(h.Y),\'R\':(h.X+f.1b[e.J].1s),\'B\':(h.Y+f.1b[e.J].1t),\'L\':(h.X)};u(j.1y(\'2c-\')!=-1){t v=j.1T(\'2c-\')[1].3n();c[k[v].2a]=1;c[k[v].2b]=e.E[k[v].d]+1}u(c.B>e.E.V){c.B=e.E.V+1}}e.x.Z.z.3o=\'3p(\'+c.T+\'F \'+c.R+\'F \'+c.B+\'F \'+c.L+\'F)\'},1v:y(a){t b=q;2d(y(){b.1o(a)},1)},2e:y(a){q.1D(a);q.24(a)},1V:y(b){q.z.1l=\'S\';u(!q.W){1q}17{t c=q.W}t d={3q:G,3r:G,3s:G,3t:G,3u:G,3v:G,3w:G};u(d[q.1K]===G){1q}t e=q;t f=K;q.2J=b;q.E={};t g={3x:\'2e\',3y:\'2e\'};u(q.1K==\'A\'){t i={3z:\'1v\',3A:\'1v\',3B:\'1v\',3C:\'1v\'};H(t a 1h i){g[a]=i[a]}}H(t h 1h g){q.1r(\'3D\'+h,y(){f[g[h]](e)})}q.1r(\'3E\',y(){f.2v(e)});t j=y(a){a.z.3F=1;u(a.W.1j==\'3G\'){a.z.1j=\'3H\'}};j(q.3I);j(q);q.18=D.1k(\'3J\');q.18.14.23=\'1l:S; 1j:27; 28:0; 1B:0; Q:0; 3K:S;\';q.18.z.1c=c.1c;q.x={\'1u\':M,\'Z\':M,\'1H\':M};H(t v 1h q.x){q.x[v]=D.1k(f.16+\':3L\');q.x[v].1i=D.1k(f.16+\':3M\');q.x[v].1z(q.x[v].1i);q.x[v].3N=G;q.x[v].z.1j=\'27\';q.x[v].z.1c=c.1c;q.x[v].3O=\'1,1\';q.18.1z(q.x[v])}q.x.Z.1G=\'S\';q.x.Z.1i.3P=\'3Q\';q.3R.1Q(q.18,q);q.1F=G;u(q.1K==\'3S\'){q.1F=M;q.z.3T=\'3U\'}2d(y(){f.1o(e)},1)}};2n{D.3V("3W",G,M)}2o(2p){}K.2f();K.2j();K.2l();u(K.1d&&D.1r&&K.2h){D.1r(\'3X\',y(){u(D.3Y==\'3Z\'){t d=K.1O;t e=d.1U;t f=y(a,b,c){2d(y(){K.1V.2r(a,b)},c*2C)};H(t i=0;i<e;i++){t g=D.2i(d[i].2t);t h=g.1U;H(t r=0;r<h;r++){u(g[r].1K!=\'40\'){f(g[r],d[i].2u,r)}}}}})}',62,249,'||||||||||||||||||||||||||this|||var|if|||vml|function|style|||Math|document|dim|px|false|for|case|vmlBg|DD_roundies||true|Top|Left|bW|border||none||Width|Height|currentStyle|||image||floor|styleSheet|break|runtimeStyle|ceil|ns|else|vmlBox|Right|Bottom|imgSize|zIndex|IE8|max|radius|parseInt|in|filler|position|createElement|behavior|top|left|applyVML|backgroundColor|return|attachEvent|width|height|color|pseudoClass|firstChild|addRule|search|appendChild|webkit|padding|vmlStrokeWeight|vmlOffsets|backgroundImage|isImg|fillcolor|stroke|qy|qx|nodeName|IE6|IE7|namespaces|selectorsToProcess|default|insertBefore|typeof|undefined|split|length|roundify|join|right|bottom|vmlStrokeColor|display|filter|vmlOpacity|cssText|vmlPath|lastIndexOf|src|absolute|margin|path|b1|b2|repeat|setTimeout|reposition|IEversion|documentMode|querySelector|querySelectorAll|createVmlNameSpace|VML|createVmlStyleSheet|documentElement|try|catch|err|toString|call|createTextNode|selector|radii|readPropertyChanges|switch|borderColor|backgroundPosition|backgroundRepeat|vmlFill|nixBorder|100|transparent|10000px|removeAttribute|body|filled|slice|DD_radii|clipImage|add|urn|schemas|microsoft|com|writeln|import|namespace|implementation|url|null|constructor|Array|replace|expression|moz|push|event|propertyName|borderWidth|block|lpha|substring|opacity|substr|img|onload|offsetWidth|offsetHeight|className|_sizeFinder|offset|coordsize|1px|min|reverse|center|01|toUpperCase|clip|rect|BODY|TABLE|TR|TD|SELECT|OPTION|TEXTAREA|resize|move|mouseleave|mouseenter|focus|blur|on|onpropertychange|zoom|static|relative|offsetParent|ignore|background|shape|fill|stroked|coordorigin|type|tile|parentNode|IMG|visibility|hidden|execCommand|BackgroundImageCache|onreadystatechange|readyState|complete|INPUT'.split('|'),0,{}))<commit_msg>[视图]删除无用文件夹<commit_after><|endoftext|>


<commit_before>const express = require('express');
const router = express.Router();

router.get('/', function (req, res, next) {
    res.status(200).json({
        api: 'node-api-seed',
        version: '0.0.0'
    });
});

module.exports = router;
<commit_msg>Refactored route<commit_after>const express = require('express');
const router = express.Router();

module.exports = router;

router.get('/', serverPulse);

function serverPulse(req, res, next) {
    res.status(200).json({
        api: 'node-api-seed',
        version: '0.0.0'
    });
}
<|endoftext|>


<commit_before>const bg = require('./common.js');
const _ = require('lodash');
const common = require('../common/common.js');
const constants = require('../common/constants.js');
const ga = require('../common/ga.js');
const spData = require('../common/sp-data.js');

const spCm = require('./sp-cm.js');
const spRta = require('./sp-rta.js');

const entityDailySyncEvent = {};

function checkEntityId(entityId) {
    if (bg.isUnset(entityId)) {
        throw new Error('invalid entityId=' + entityId);
    }
}

function mkEvent(tag) {
    const event = {};
    console.log('Created event', tag);
    event.promise = new Promise((resolve, reject) => {
        event.set = val => {
            resolve(val);
            event.set = () => { /* ignore multiple sets */ };
        };
        event.error = e => {
            reject(e);
            event.error = () => { /* ignore multiple errors */ };
        };
    });

    return event;
}

function getEntitySyncEvent(entityId) {
    if (!entityDailySyncEvent[entityId]) {
        const event = mkEvent(`entity ${entityId}`);
        entityDailySyncEvent[entityId] = event;
        if (bg.hasSyncedToday('sp'))
            event.set();
    }
    return entityDailySyncEvent[entityId];
}

async function dataGather(req) {
    // We want to make sure that we at least attempt to sync every single
    // domain, but any exceptions we encounter should be propagated so that we
    // don't record this as a success.
    let deferredException = null;

    let entities = bg.getEntityIds();

    // if we are responding to a client request, always sync that entityId first
    if (req && req.entityId) {
        entities.unshift({ domain: req.domain, entityId: req.entityId });
        entities = _.uniqBy(entities, x => x.entityId);
    }

    for (const { domain, entityId } of entities) {
        checkEntityId(entityId);
        for (const collector of [spCm(domain, entityId), spRta(domain, entityId)]) {
            try {
                const campaignIds = await requestCampaignData(collector);
                const adGroups = await getAdGroups(entityId);
                const summaries = await getCampaignSummaries({ entityId });

                await bg.parallelQueue(campaignIds, async function(campaignId) {
                    const summary = summaries.find(x => x.campaignId == campaignId);
                    if (!spData.isRunning(summary)) {
                        return;
                    }

                    const adGroupItem = adGroups.find(x => x.campaignId == campaignId);
                    let adGroupId = null;
                    if (adGroupItem) {
                        adGroupId = adGroupItem.adGroupId;
                    }
                    else {
                        adGroupId = await collector.getAdGroupId(campaignId);
                        if (adGroupId)
                            await storeAdGroupMetadata({ entityId: collector.entityId, adGroupId, campaignId });
                    }

                    if (adGroupId) {
                        if (!(summary && summary.asin)) {
                            await requestCampaignMetadata(collector, campaignId, adGroupId);
                        }
                        await requestKeywordData(collector, campaignId, adGroupId);
                    }
                });

                // Actually completing the block above with either collector
                // means that we don't need to try the other one. Sometimes this
                // eans that we'll get the same data twice on both collectors,
                // but oh well.
                break;
            }
            catch (ex) {
                if (!bg.handleServerErrors(ex, "sp.dataGather")) {
                    ga.merror(ex, `context: domain ${domain}, entityId ${entityId}`);
                }
                deferredException = ex;
            }
        }
    }

    if (deferredException) {
        throw deferredException;
    }
}

const getAllowedCampaigns = bg.cache.coMemo(async function({ entityId }) {
    checkEntityId(entityId);
    const allowed = await bg.ajax(`${bg.serviceUrl}/api/data/${entityId}/allowed`, {
        method: 'GET',
        responseType: 'json'
    });

    if (allowed.length)
        return allowed;

    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}/allowed`, {
        method: 'GET',
        responseType: 'json'
    });
}, { maxAge: 30000 });

const getCampaignSummaries = bg.cache.coMemo(async function({ entityId }) {
    checkEntityId(entityId);

    await summaryReady(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}/summary`, {
        method: 'GET',
        responseType: 'json'
    });
}, { maxAge: 30000 });

async function summaryReady(entityId) {
    const syncEvent = getEntitySyncEvent(entityId);
    await syncEvent.promise;
}

async function requestCampaignData(collector) {
    const syncEvent = getEntitySyncEvent(collector.entityId);
    let campaignIds = [];

    try {
        console.log('requesting campaign data for', collector.entityId);
        const missing = await getMissingDates(collector.entityId);
        const days = new Set(missing.missingDays);
        const now = Date.now();

        if (missing.needLifetime) {
            const data = await collector.getLifetimeCampaignData();
            await storeLifetimeCampaignData(collector.entityId, now, data);
        }

        if (days.size) {
            const latestDay = Math.max(...days.values());
            const latestData = await collector.getDailyCampaignData(latestDay);
            await storeDailyCampaignData(collector.entityId, latestDay, latestData);

            campaignIds = latestData.map(x => x.campaignId);
            const status = await collector.getCampaignStatus(campaignIds);
            await storeCampaignStatus(collector.entityId, now, status);
            syncEvent.set();

            days.delete(latestDay);
            await bg.parallelQueue(days.values(), async date => {
                const data = await collector.getDailyCampaignData(date);
                await storeDailyCampaignData(collector.entityId, date, data);
            });
        }
    }
    finally {
        syncEvent.set();
    }

    return campaignIds;
}

async function requestCampaignMetadata(collector, campaignId, adGroupId) {
    const asin = await collector.getCampaignAsin(campaignId, adGroupId);
    if (asin) {
        await storeCampaignMetadata(collector.entityId, campaignId, asin);
    }
}

async function requestKeywordData(collector, campaignId, adGroupId) {
    let timestamp = Date.now();

    console.log('requesting keyword data for', collector.entityId, adGroupId);
    const data = await collector.getKeywordData(campaignId, adGroupId);

    if (data && data.length) {
        await storeKeywordData(collector.entityId, adGroupId, timestamp, data);
    }
}

function storeDailyCampaignData(entityId, timestamp, data) {
    return bg.ajax(`${bg.serviceUrl}/api/campaignData/${entityId}?timestamp=${timestamp}`, {
        method: 'PUT',
        jsonData: { aaData: data },
        contentType: 'application/json',
    });
}

function storeLifetimeCampaignData(entityId, timestamp, data) {
    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}?timestamp=${timestamp}`, {
        method: 'PUT',
        jsonData: { aaData: data },
        contentType: 'application/json',
    });
}

function storeCampaignStatus(entityId, timestamp, data) {
    return bg.ajax(`${bg.serviceUrl}/api/campaignStatus/${entityId}?timestamp=${timestamp}`, {
        method: 'PUT',
        jsonData: data,
        contentType: 'application/json',
    });
}

async function storeKeywordData(entityId, adGroupId, timestamp, data) {
    // Chop the large keyword list into small, bite-sized chunks for easier
    // digestion on the server.
    for (const chunk of common.pageArray(data, 50)) {
        await bg.ajax(`${bg.serviceUrl}/api/keywordData/${entityId}/${adGroupId}?timestamp=${timestamp}`, {
            method: 'PUT',
            jsonData: { aaData: chunk },
            contentType: 'application/json',
        });
    }
}

function getMissingDates(entityId) {
    return bg.ajax(`https://${constants.hostname}/api/campaignData/${entityId}/missingDates`, {
        method: 'GET',
        responseType: 'json',
    });
}

const getCampaignHistory = bg.cache.coMemo(function(entityId, campaignId) { // TODO: date ranges, etc.
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}/${campaignId}`, {
        method: 'GET',
        responseType: 'json'
    });
});

const getAllCampaignData = bg.cache.coMemo(function({ entityId, startTimestamp, endTimestamp }) {
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}?startTimestamp=${startTimestamp}&endTimestamp=${endTimestamp}`, {
        method: 'GET',
        responseType: 'json'
    });
});

const getDataHistory = bg.cache.coMemo(async function({ entityId, campaignId }) { // TODO: date ranges, etc.
    const snapshots = await getCampaignHistory(entityId, campaignId);
    return common.convertSnapshotsToDeltas(snapshots);
});

const getAggregateCampaignHistory = bg.cache.coMemo(async function({ entityId, campaignIds }) {
    let aggregate = [];
    await bg.parallelQueue(campaignIds, async function(campaignId) {
        try {
            let history = await getDataHistory({ entityId, campaignId });
            aggregate = aggregate.concat(...history);
        }
        catch (ex) {
            if (bg.handleServerErrors(ex) == 'notAllowed') {
                // swallow this
            }
            throw ex;
        }
    });

    return aggregate.sort((a, b) => a.timestamp - b.timestamp);
});

const getKeywordData = bg.cache.coMemo(async function({ domain, entityId, campaignId, adGroupId }) {
    checkEntityId(entityId);
    const url = `${bg.serviceUrl}/api/keywordData/${entityId}/${adGroupId}`;
    const opts = {
        method: 'GET',
        responseType: 'json',
    };
    let data = await bg.ajax(url, opts);

    if (!data || data.length == 0) {
        // Possibly this is the first time we've ever seen this campaign. If so,
        // let's query Amazon and populate our own servers, and then come back.
        // This is very slow but should usually only happen once.

        for (const collector of [spCm(domain, entityId), spRta(domain, entityId)]) {
            try {
                await requestKeywordData(collector, campaignId, adGroupId);
                data = await bg.ajax(url, opts);
                break;
            }
            catch (ex) {
                ga.merror(ex, `context: domain ${domain}, entityId ${entityId}, collector ${collector.name}`);
            }
        }
    }

    return data;
});

const getAggregateKeywordData = bg.cache.coMemo(function({ domain, entityId, adGroupIds }) {
    return bg.parallelQueue(adGroupIds, async function(adGroupId) {
        try {
            return await getKeywordData({ domain, entityId, adGroupId });
        }
        catch (ex) {
            if (bg.handleServerErrors(ex) == 'notAllowed') {
                // swallow this
            }
            throw ex;
        }
    });
});

function storeCampaignMetadata(entityId, campaignId, asin) {
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/campaignMetadata/${entityId}/${campaignId}`, {
        method: 'PUT',
        jsonData: { asin },
    });
}

function storeAdGroupMetadata({ entityId, adGroupId, campaignId }) {
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/adGroupMetadata/${entityId}/${adGroupId}`, {
        method: 'PUT',
        jsonData: { campaignId },
    });
}

function getAdGroups(entityId) {
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/adGroups/${entityId}`, {
        method: 'GET',
        responseType: 'json',
    });
}

async function updateKeyword({ domain, entityId, keywordIdList, operation, dataValues }) {
    // TODO: the parameters to the Amazon API imply that you can pass more than
    // 1 keyword at a time, but testing this shows that doing so just generates
    // an error. So we do it the stupid way instead, with a loop.
    const timestamp = Date.now();

    const successes = [];
    await bg.parallelQueue(keywordIdList, async function(id) {
        const response = await bg.ajax(`https://${domain}/api/sponsored-products/updateKeywords/`, {
            method: 'POST',
            formData: Object.assign({operation, entityId, keywordIds: id}, dataValues),
            responseType: 'json',
        });
        if (response.success) {
            successes.push(id);
        }
    });

    for (const page of common.pageArray(successes, 50)) {
        await bg.ajax(`${bg.serviceUrl}/api/keywordData/${entityId}?timestamp=${timestamp}`, {
            method: 'PATCH',
            jsonData: { operation, dataValues, keywordIds: page },
            responseType: 'json',
        });
    }

    if (successes.length)
        getKeywordData.clear();

    // TODO: in the case that we have a lot of these (bulk update), implement
    // progress feedback.
    return { success: successes.length == keywordIdList.length };
}

module.exports = {
    name: 'sp',
    dataGather,
    getAllowedCampaigns,
    getCampaignSummaries,
    getAllCampaignData,
    getDataHistory,
    getAggregateCampaignHistory,
    getKeywordData,
    getAggregateKeywordData,
    storeAdGroupMetadata,
    updateKeyword,
};
<commit_msg>add analytics to know what collector people are using<commit_after>const bg = require('./common.js');
const _ = require('lodash');
const common = require('../common/common.js');
const constants = require('../common/constants.js');
const ga = require('../common/ga.js');
const spData = require('../common/sp-data.js');

const spCm = require('./sp-cm.js');
const spRta = require('./sp-rta.js');

const entityDailySyncEvent = {};

function checkEntityId(entityId) {
    if (bg.isUnset(entityId)) {
        throw new Error('invalid entityId=' + entityId);
    }
}

function mkEvent(tag) {
    const event = {};
    console.log('Created event', tag);
    event.promise = new Promise((resolve, reject) => {
        event.set = val => {
            resolve(val);
            event.set = () => { /* ignore multiple sets */ };
        };
        event.error = e => {
            reject(e);
            event.error = () => { /* ignore multiple errors */ };
        };
    });

    return event;
}

function getEntitySyncEvent(entityId) {
    if (!entityDailySyncEvent[entityId]) {
        const event = mkEvent(`entity ${entityId}`);
        entityDailySyncEvent[entityId] = event;
        if (bg.hasSyncedToday('sp'))
            event.set();
    }
    return entityDailySyncEvent[entityId];
}

async function dataGather(req) {
    // We want to make sure that we at least attempt to sync every single
    // domain, but any exceptions we encounter should be propagated so that we
    // don't record this as a success.
    let deferredException = null;

    let entities = bg.getEntityIds();

    // if we are responding to a client request, always sync that entityId first
    if (req && req.entityId) {
        entities.unshift({ domain: req.domain, entityId: req.entityId });
        entities = _.uniqBy(entities, x => x.entityId);
    }

    for (const { domain, entityId } of entities) {
        checkEntityId(entityId);
        for (const collector of [spCm(domain, entityId), spRta(domain, entityId)]) {
            try {
                const campaignIds = await requestCampaignData(collector);
                const adGroups = await getAdGroups(entityId);
                const summaries = await getCampaignSummaries({ entityId });

                await bg.parallelQueue(campaignIds, async function(campaignId) {
                    const summary = summaries.find(x => x.campaignId == campaignId);
                    if (!spData.isRunning(summary)) {
                        return;
                    }

                    const adGroupItem = adGroups.find(x => x.campaignId == campaignId);
                    let adGroupId = null;
                    if (adGroupItem) {
                        adGroupId = adGroupItem.adGroupId;
                    }
                    else {
                        adGroupId = await collector.getAdGroupId(campaignId);
                        if (adGroupId)
                            await storeAdGroupMetadata({ entityId: collector.entityId, adGroupId, campaignId });
                    }

                    if (adGroupId) {
                        if (!(summary && summary.asin)) {
                            await requestCampaignMetadata(collector, campaignId, adGroupId);
                        }
                        await requestKeywordData(collector, campaignId, adGroupId);
                    }
                });

                // Actually completing the block above with either collector
                // means that we don't need to try the other one. Sometimes this
                // means that we'll get the same data twice on both collectors,
                // but oh well.
                ga.mga('event', 'collector-complete', collector.name);
                break;
            }
            catch (ex) {
                if (!bg.handleServerErrors(ex, "sp.dataGather")) {
                    ga.merror(ex, `context: domain ${domain}, entityId ${entityId}`);
                }
                deferredException = ex;
            }
        }
    }

    if (deferredException) {
        throw deferredException;
    }
}

const getAllowedCampaigns = bg.cache.coMemo(async function({ entityId }) {
    checkEntityId(entityId);
    const allowed = await bg.ajax(`${bg.serviceUrl}/api/data/${entityId}/allowed`, {
        method: 'GET',
        responseType: 'json'
    });

    if (allowed.length)
        return allowed;

    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}/allowed`, {
        method: 'GET',
        responseType: 'json'
    });
}, { maxAge: 30000 });

const getCampaignSummaries = bg.cache.coMemo(async function({ entityId }) {
    checkEntityId(entityId);

    await summaryReady(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}/summary`, {
        method: 'GET',
        responseType: 'json'
    });
}, { maxAge: 30000 });

async function summaryReady(entityId) {
    const syncEvent = getEntitySyncEvent(entityId);
    await syncEvent.promise;
}

async function requestCampaignData(collector) {
    const syncEvent = getEntitySyncEvent(collector.entityId);
    let campaignIds = [];

    try {
        console.log('requesting campaign data for', collector.entityId);
        const missing = await getMissingDates(collector.entityId);
        const days = new Set(missing.missingDays);
        const now = Date.now();

        if (missing.needLifetime) {
            const data = await collector.getLifetimeCampaignData();
            await storeLifetimeCampaignData(collector.entityId, now, data);
        }

        if (days.size) {
            const latestDay = Math.max(...days.values());
            const latestData = await collector.getDailyCampaignData(latestDay);
            await storeDailyCampaignData(collector.entityId, latestDay, latestData);

            campaignIds = latestData.map(x => x.campaignId);
            const status = await collector.getCampaignStatus(campaignIds);
            await storeCampaignStatus(collector.entityId, now, status);
            syncEvent.set();

            days.delete(latestDay);
            await bg.parallelQueue(days.values(), async date => {
                const data = await collector.getDailyCampaignData(date);
                await storeDailyCampaignData(collector.entityId, date, data);
            });
        }
    }
    finally {
        syncEvent.set();
    }

    return campaignIds;
}

async function requestCampaignMetadata(collector, campaignId, adGroupId) {
    const asin = await collector.getCampaignAsin(campaignId, adGroupId);
    if (asin) {
        await storeCampaignMetadata(collector.entityId, campaignId, asin);
    }
}

async function requestKeywordData(collector, campaignId, adGroupId) {
    let timestamp = Date.now();

    console.log('requesting keyword data for', collector.entityId, adGroupId);
    const data = await collector.getKeywordData(campaignId, adGroupId);

    if (data && data.length) {
        await storeKeywordData(collector.entityId, adGroupId, timestamp, data);
    }
}

function storeDailyCampaignData(entityId, timestamp, data) {
    return bg.ajax(`${bg.serviceUrl}/api/campaignData/${entityId}?timestamp=${timestamp}`, {
        method: 'PUT',
        jsonData: { aaData: data },
        contentType: 'application/json',
    });
}

function storeLifetimeCampaignData(entityId, timestamp, data) {
    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}?timestamp=${timestamp}`, {
        method: 'PUT',
        jsonData: { aaData: data },
        contentType: 'application/json',
    });
}

function storeCampaignStatus(entityId, timestamp, data) {
    return bg.ajax(`${bg.serviceUrl}/api/campaignStatus/${entityId}?timestamp=${timestamp}`, {
        method: 'PUT',
        jsonData: data,
        contentType: 'application/json',
    });
}

async function storeKeywordData(entityId, adGroupId, timestamp, data) {
    // Chop the large keyword list into small, bite-sized chunks for easier
    // digestion on the server.
    for (const chunk of common.pageArray(data, 50)) {
        await bg.ajax(`${bg.serviceUrl}/api/keywordData/${entityId}/${adGroupId}?timestamp=${timestamp}`, {
            method: 'PUT',
            jsonData: { aaData: chunk },
            contentType: 'application/json',
        });
    }
}

function getMissingDates(entityId) {
    return bg.ajax(`https://${constants.hostname}/api/campaignData/${entityId}/missingDates`, {
        method: 'GET',
        responseType: 'json',
    });
}

const getCampaignHistory = bg.cache.coMemo(function(entityId, campaignId) { // TODO: date ranges, etc.
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}/${campaignId}`, {
        method: 'GET',
        responseType: 'json'
    });
});

const getAllCampaignData = bg.cache.coMemo(function({ entityId, startTimestamp, endTimestamp }) {
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/data/${entityId}?startTimestamp=${startTimestamp}&endTimestamp=${endTimestamp}`, {
        method: 'GET',
        responseType: 'json'
    });
});

const getDataHistory = bg.cache.coMemo(async function({ entityId, campaignId }) { // TODO: date ranges, etc.
    const snapshots = await getCampaignHistory(entityId, campaignId);
    return common.convertSnapshotsToDeltas(snapshots);
});

const getAggregateCampaignHistory = bg.cache.coMemo(async function({ entityId, campaignIds }) {
    let aggregate = [];
    await bg.parallelQueue(campaignIds, async function(campaignId) {
        try {
            let history = await getDataHistory({ entityId, campaignId });
            aggregate = aggregate.concat(...history);
        }
        catch (ex) {
            if (bg.handleServerErrors(ex) == 'notAllowed') {
                // swallow this
            }
            throw ex;
        }
    });

    return aggregate.sort((a, b) => a.timestamp - b.timestamp);
});

const getKeywordData = bg.cache.coMemo(async function({ domain, entityId, campaignId, adGroupId }) {
    checkEntityId(entityId);
    const url = `${bg.serviceUrl}/api/keywordData/${entityId}/${adGroupId}`;
    const opts = {
        method: 'GET',
        responseType: 'json',
    };
    let data = await bg.ajax(url, opts);

    if (!data || data.length == 0) {
        // Possibly this is the first time we've ever seen this campaign. If so,
        // let's query Amazon and populate our own servers, and then come back.
        // This is very slow but should usually only happen once.

        for (const collector of [spCm(domain, entityId), spRta(domain, entityId)]) {
            try {
                await requestKeywordData(collector, campaignId, adGroupId);
                data = await bg.ajax(url, opts);
                break;
            }
            catch (ex) {
                ga.merror(ex, `context: domain ${domain}, entityId ${entityId}, collector ${collector.name}`);
            }
        }
    }

    return data;
});

const getAggregateKeywordData = bg.cache.coMemo(function({ domain, entityId, adGroupIds }) {
    return bg.parallelQueue(adGroupIds, async function(adGroupId) {
        try {
            return await getKeywordData({ domain, entityId, adGroupId });
        }
        catch (ex) {
            if (bg.handleServerErrors(ex) == 'notAllowed') {
                // swallow this
            }
            throw ex;
        }
    });
});

function storeCampaignMetadata(entityId, campaignId, asin) {
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/campaignMetadata/${entityId}/${campaignId}`, {
        method: 'PUT',
        jsonData: { asin },
    });
}

function storeAdGroupMetadata({ entityId, adGroupId, campaignId }) {
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/adGroupMetadata/${entityId}/${adGroupId}`, {
        method: 'PUT',
        jsonData: { campaignId },
    });
}

function getAdGroups(entityId) {
    checkEntityId(entityId);
    return bg.ajax(`${bg.serviceUrl}/api/adGroups/${entityId}`, {
        method: 'GET',
        responseType: 'json',
    });
}

async function updateKeyword({ domain, entityId, keywordIdList, operation, dataValues }) {
    // TODO: the parameters to the Amazon API imply that you can pass more than
    // 1 keyword at a time, but testing this shows that doing so just generates
    // an error. So we do it the stupid way instead, with a loop.
    const timestamp = Date.now();

    const successes = [];
    await bg.parallelQueue(keywordIdList, async function(id) {
        const response = await bg.ajax(`https://${domain}/api/sponsored-products/updateKeywords/`, {
            method: 'POST',
            formData: Object.assign({operation, entityId, keywordIds: id}, dataValues),
            responseType: 'json',
        });
        if (response.success) {
            successes.push(id);
        }
    });

    for (const page of common.pageArray(successes, 50)) {
        await bg.ajax(`${bg.serviceUrl}/api/keywordData/${entityId}?timestamp=${timestamp}`, {
            method: 'PATCH',
            jsonData: { operation, dataValues, keywordIds: page },
            responseType: 'json',
        });
    }

    if (successes.length)
        getKeywordData.clear();

    // TODO: in the case that we have a lot of these (bulk update), implement
    // progress feedback.
    return { success: successes.length == keywordIdList.length };
}

module.exports = {
    name: 'sp',
    dataGather,
    getAllowedCampaigns,
    getCampaignSummaries,
    getAllCampaignData,
    getDataHistory,
    getAggregateCampaignHistory,
    getKeywordData,
    getAggregateKeywordData,
    storeAdGroupMetadata,
    updateKeyword,
};
<|endoftext|>


<commit_before>var express = require('express'),
    app = express(),
    bodyParser = require('body-parser'),
    nodemailer = require('nodemailer'),
    router = express.Router({mergeParams: true})

router.get('/', function(req, res, next) {
    res.render('index')
});

router.get('/posture', function(req, res, next) {
    res.render('posture')
});

router.post('/contribute', function (req, res) {

    // Create a SMTP transport object
    var transport = nodemailer.createTransport({
            service: 'Gmail',
            auth: {
                user: "jmarinagomez@gmail.com",
                pass: process.env.SECRET
            }
        });

    console.log('SMTP Configured');

    // Message object
    var message = {

        // sender info
        from: 'Keys to Teach',

        // Comma separated list of recipients
        to: ['marina.g16@edu.trinitylaban.ac.uk'],

        // Subject of the message
        subject: 'New contribution from Keys to Teach',

        // plaintext body
        text: 'Title: ' + req.body.title + 'Message: ' + req.body.message + '\n' + 'Name: ' + req.body.name + '\n' + 'Email: ' + req.body.email + 'Checked name: ' + req.body.namecheckbox,

        // HTML body
        html:'Title: ' + req.body.title + 'Message: ' + req.body.message + '\n' + 'Name: ' + req.body.name + '\n' + 'Email: ' + req.body.email + 'Checked name: ' + req.body.namecheckbox,

    };

    console.log('Sending Mail');
    transport.sendMail(message, function(error){
    if(error){
        console.log(error);
            req.flash('error', error);
            res.redirect('/');
        return;
    }
        console.log('Message sent!');
            req.flash('success', 'Thank you for your contribution');
            res.redirect('/');

    // if you don't want to use this transport object anymore, uncomment following line
    //transport.close(); // close the connection pool
    });

});

module.exports = router;<commit_msg>add endpoints / search / addKeys // update contact message<commit_after>var express = require('express'),
    app = express(),
    bodyParser = require('body-parser'),
    nodemailer = require('nodemailer'),
    passport = require('passport'),
    User = require('../models/users'),
    Key = require('../models/keys'),
    middleware = require('../middleware'),
    router = express.Router({mergeParams: true});

// SHOW login form
router.get('/login', function(req, res) {
    res.render('login', {message: req.flash('error')});
});

// handle login logic
router.post('/login', passport.authenticate('local',
    {
        successRedirect: '/',
        failureRedirect: '/login'
    }), function(req, res) {
});

// LOGOUT ROUTE
router.get('/logout', function(req, res) {
    req.logout();
    req.flash('success', 'Logged you out!');
    res.redirect('/');
});

router.get('/', function(req, res, next) {
    res.render('index')
});

router.get('/contact', function(req, res, next) {
    res.render('contact')
});

router.get('/about', function(req, res, next) {
    res.render('about')
});

router.get('/contribute', function(req, res, next) {
    res.render('contribute')
});

router.get('/survey', function(req, res, next) {
    res.render('survey')
});
// router.get("/search", function(req, res) {
//     "use strict";

//     var page = req.query.page ? parseInt(req.query.page) : 0;
//     var query = req.query.query ? req.query.query : "";

//     items.searchItems(query, page, ITEMS_PER_PAGE, function(searchItems) {

//         items.getNumSearchItems(query, function(itemCount) {

//             var numPages = 0;

//             if (itemCount > ITEMS_PER_PAGE) {
//                 numPages = Math.ceil(itemCount / ITEMS_PER_PAGE);
//             }

//             res.render('search', { queryString: query,
//                                     itemCount: itemCount,
//                                     pages: numPages,
//                                     page: page,
//                                     items: searchItems });

//         });
//     });
// });

router.get('/addKeys', middleware.isLoggedIn, function(req, res) {
    res.render('addKeys', {message: req.flash('error')});
});

router.post('/addKeys', middleware.isLoggedIn, function(req, res) {
    // get data from form and add to campgrounds array
    var title = req.body.title;
    var description = req.body.description;
    var source = req.body.source;
    var link = req.body.link;
    var tags = req.body.tags;
    var contributor = req.body.contributor;

    var newArticle = {title: title,
        description: description,
        sourceAuthor: source,
        link: link,
        tags: [tags],
        contributor: contributor,
        isPublic: true
    };
    Key.create(newArticle, function(err, newArticle){
        if (err){
            console.log(err);
        } else {
            res.redirect('/keys');
        }
    });
});

router.post('/contribute', function (req, res) {

    // Create a SMTP transport object
    var transport = nodemailer.createTransport({
            service: 'Gmail',
            auth: {
                user: "jmarinagomez@gmail.com",
                pass: process.env.SECRET
            }
        });

    console.log('SMTP Configured');

    // Message object
    var message = {

        // sender info
        from: 'Keys to Teach',

        // Comma separated list of recipients
        to: ['marina.g16@edu.trinitylaban.ac.uk'],

        // Subject of the message
        subject: 'New contribution from Keys to Teach',

        // plaintext body
        text: 'Title: ' + req.body.title + 'Message: ' + req.body.message + '\n' + 'Name: ' + req.body.name + '\n' + 'Email: ' + req.body.email + 'Checked name: ' + req.body.namecheckbox,

        // HTML body
        html:'Title: ' + req.body.title + 'Message: ' + req.body.message + '\n' + 'Name: ' + req.body.name + '\n' + 'Email: ' + req.body.email + 'Checked name: ' + req.body.namecheckbox,

    };

    transport.sendMail(message, function(error){

    if(error){
        console.log(error);
            req.flash('error', error);
            res.redirect('/');
        return;
    }
        req.flash('success', 'Thank you for contributing and making "Keys to Teach" grow.');
        res.redirect('/');

    });

});

router.get('/keys', function(req, res) {
    Key.find({}, function(err, allKeys){
        if(err){
            console.log(err);
        } else {
            res.render('keys/index', {
                keys: allKeys
            });
        }
    });
});

module.exports = router;<|endoftext|>


<commit_before>var projects = require('../projects.json');

/*
 * GET home page.
 */

exports.view = function(req, res){
	random_num = Math.random();
	console.log(random_num);
	if (random_num > 0.5){
		projects["grid"] = false;
  		res.render('index', projects);
	} else {
		res.redirect('/grid');
	}

};

exports.viewGrid = function(req, res){

	projects["grid"] = true;
  	res.render('index', projects);
};
<commit_msg>change after changing lab directions<commit_after>var projects = require('../projects.json');

/*
 * GET home page.
 */

exports.view = function(req, res){
	random_num = Math.random();
	console.log(random_num);
	if (random_num >= 0){
		projects["grid"] = false;
  		res.render('index', projects);
	} else {
		res.redirect('/grid');
	}

};

exports.viewGrid = function(req, res){

	projects["grid"] = true;
  	res.render('index', projects);
};
<|endoftext|>


<commit_before>/**
 * Restaurant ORM
 *
 * @todo Use JS syntax to outline the structure
 */
var Restaurant = function(id) {
	this.type = 'Restaurant';
	this.id_var = 'id_restaurant';
	this.resource = 'restaurant';

	var
		self = this,
		complete;

	$.extend(self,Orm);

	var complete = arguments[1] || null;
	self.loadError = arguments[2] || null;

	self.categories = function() {
		return self.loadType('Category','categories');
	}

	self.notifications = function() {
		return self.loadType('Notification','notifications');
	}

	self.top = function() {
		var categories = self.categories();

		for (var x in categories) {

			var dishes = categories[x].dishes();

			for (var xx in dishes) {
				if (dishes[xx].top == 1) {
					return dishes[xx];
				}
			}
		}
	}

	self.deliveryDiff = function(total) {
		var diff = parseFloat(self.delivery_min - total).toFixed(2);
		return diff;
	}

	self.meetDeliveryMin = function(total) {
		return total < parseFloat(self.delivery_min) ? true : false;
	}

	self.dateFromItem = function(item, offset) {
		var
			theTime = item.split(':'),
			theDate = new Date();

		theDate.setHours(theTime[0]);
		theDate.setMinutes(theTime[1] + offset);
		return theDate;
	}

	self.deliveryHere = function( distance ){
		return ( distance <= this.delivery_radius )
	}

	self.closedMessage = function(){
		if( self.closed_message != '' ){
			return self.closed_message;
		} else {
			return 'Temporarily closed';
		}

	}

	self.preset = function() {
		return self['_preset'];
	}

	self.finished = function(data) {
		for (x in data) {
			self[x] = data[x];
		}

		self.categories();

		if (App.isPhoneGap) {
			var img = self.image.replace(/^.*\/|\.[^.]*$/g, '');
			// restaurant page image
			self.img = App.imgServer + '630x280/' + img +  '.jpg?crop=1';
			// restaurants page thumbnail
			self.img64 = App.imgServer + '596x596/' + img +  '.jpg';
		}

		if (typeof complete == 'function') {
			complete.call(self);
		}

	}

	self.tagfy = function( tag ){
		if( tag ){
			self._tag = tag;
			if( tag == 'opening' ){
				if( self._opensIn && self._opensIn_formatted != '' ){
					self._tag = tag;
				} else {
					self._tag = 'closed';
				}
			} else {
				self._tag = tag;
			}
			return;
		}

		self._tag = '';
		// Add the tags
		if( !self._open ){
			self._tag = 'closed';
			if( self._closedDueTo ){
				self._tag = 'force_close';
			}
		}
		if( self._open && self._closesIn !== 'false' && self._closesIn <= 15 ){
			self._tag = 'closing';
		}
		// if the restaurant does not have a closed message it has no hours for the week
		if( self.closed_message == '' ){
			self._tag = 'force_close';
		}
	}

	self.getNow = function( now ){
		if( now && now.getTime ){
			return now;
		}
		return dateTime.getNow();
	}

	self.openRestaurantPage = function( now ){
		// See 2662
		now = self.getNow( now );
		if( self.open( now, true ) ){
			return true;
		}
		self.opensIn( now );
		if( self._opensIn && self._opensIn < ( 3600 ) ){
			return true;
		}
		return false;
	}

	/*
	** Open/Close check methods
	*/
	// return true if the restaurant is open
	self.open = function( now, ignoreOpensClosesInCalc ) {

		self.tagfy( 'opening' );
		// if the restaurant has no hours it probably will not be opened for the next 24 hours
		self._hasHours = false;

		now = self.getNow( now );

		self.processHours();
		var now_time = now.getTime();
		// loop to verify if it is open
		self._open = false;
		if( self.hours ){
			for( x in self.hours ){
				self._hasHours = true;
				if( now_time >= self.hours[ x ]._from_time && now_time <= self.hours[ x ]._to_time ){
					if( self.hours[ x ].status == 'open' ){
						self._open = true;
						if( ignoreOpensClosesInCalc ){
							return self._open;
						}
						// if it is open calc closes in
						self.closesIn( now );
						self.tagfy();
						return self._open;
					} else if( self.hours[ x ].status == 'close' ){
						self._closedDueTo = ( self.hours[ x ].notes ) ? self.hours[ x ].notes : false;
						if( ignoreOpensClosesInCalc ){
							return self._open;
						}
						// If it is closed calc opens in
						self.opensIn( now );
						self.tagfy();
						return self._open;
					}
				}
			}
			// If it is closed calc opens in
			self.opensIn( now );
			self.tagfy();
			return self._open;
		} else {
			// if it doesn't have hours it is forced to be closed
			self._tag = 'force_close';
			self._closedDueTo = ' '; // There is no reason, leave it blank
			console.log( self.name, self._tag )
		}

	}

	self.closesIn = function( now ){
		now = self.getNow( now );
		self._closesIn = false;
		self._closesIn_formatted = '';
		self.processHours();
		var now_time = now.getTime();
		if( self.hours ){
			for( x in self.hours ){
				if( self.hours[ x ].status == 'close' ){
					if( now_time <= self.hours[ x ]._from_time ){
						self._closesIn = timestampDiff( self.hours[ x ]._from_time, now_time );
						self._closesIn_formatted = formatTime( self._closesIn );
						return;
					}
				}
			}
		}
		if( self._closesIn == 0 || self._closesIn === false ){
			self._open = false;
		}
	}

	self.opensIn = function( now ){
		now = self.getNow( now );
		self._opensIn = false;
		self._opensIn_formatted = '';
		self.processHours();
		var now_time = now.getTime();
		for( x in self.hours ){
			if( self.hours[ x ].status == 'open' ){
				if( now_time <= self.hours[ x ]._from_time ){
					self._opensIn = timestampDiff( self.hours[ x ]._from_time, now_time );
					self._opensIn_formatted = formatTime( self._opensIn );
					return;
				}
			}
		}
		// it means the restaurant will not be opened for the next 24 hours
		if( self.next_open_time ){
				self._opensIn = timestampDiff( Date.parse( self.next_open_time ), now_time );
				self._opensIn_formatted = formatTime( self._opensIn, self.next_open_time_message );
		}
	}

	// Create javascript date objects to faster comparision
	self.processHours = function(){
		if( !self._hours_processed ){
			for( x in self.hours ){
				self.hours[ x ]._from = Date.parse( self.hours[ x ].from );
				self.hours[ x ]._from_time = self.hours[ x ]._from.getTime();
				self.hours[ x ]._to = Date.parse( self.hours[ x ].to );
				self.hours[ x ]._to_time = self.hours[ x ]._to.getTime();
			}
			self._hours_processed = true;
		}
	}

	// Check the restaurant cache age and reload the hours if it is necessary
	self.reloadHours = function( forceLoad ){
		var load = false;
		var now = ( Math.floor( new Date().getTime() / 1000 ) );
		if( forceLoad ){
			load = true;
		} else {
			var age = Math.floor( now - self.cachedAt ); // age in seconds
			// if the age is more or equals to 23 hours
			load = ( age >= ( ( 60 * 60 ) * 23 ) );
		}
		if( load ){
			var url = App.service + 'restaurant/hours/' + self.id_restaurant;
			App.http.get( url, {
				cache: false
			} ).success( function ( hours ) {
				self.cachedAt = now;
				self.hours = hours;
				self._hours_processed = false;
				self.processHours();
			} );
		}
	}

	self.load(id);

}

App.cached.Restaurant = {};
<commit_msg>opens in hours sometimes doesnt work #2566 - removed the debug :/<commit_after>/**
 * Restaurant ORM
 *
 * @todo Use JS syntax to outline the structure
 */
var Restaurant = function(id) {
	this.type = 'Restaurant';
	this.id_var = 'id_restaurant';
	this.resource = 'restaurant';

	var
		self = this,
		complete;

	$.extend(self,Orm);

	var complete = arguments[1] || null;
	self.loadError = arguments[2] || null;

	self.categories = function() {
		return self.loadType('Category','categories');
	}

	self.notifications = function() {
		return self.loadType('Notification','notifications');
	}

	self.top = function() {
		var categories = self.categories();

		for (var x in categories) {

			var dishes = categories[x].dishes();

			for (var xx in dishes) {
				if (dishes[xx].top == 1) {
					return dishes[xx];
				}
			}
		}
	}

	self.deliveryDiff = function(total) {
		var diff = parseFloat(self.delivery_min - total).toFixed(2);
		return diff;
	}

	self.meetDeliveryMin = function(total) {
		return total < parseFloat(self.delivery_min) ? true : false;
	}

	self.dateFromItem = function(item, offset) {
		var
			theTime = item.split(':'),
			theDate = new Date();

		theDate.setHours(theTime[0]);
		theDate.setMinutes(theTime[1] + offset);
		return theDate;
	}

	self.deliveryHere = function( distance ){
		return ( distance <= this.delivery_radius )
	}

	self.closedMessage = function(){
		if( self.closed_message != '' ){
			return self.closed_message;
		} else {
			return 'Temporarily closed';
		}

	}

	self.preset = function() {
		return self['_preset'];
	}

	self.finished = function(data) {
		for (x in data) {
			self[x] = data[x];
		}

		self.categories();

		if (App.isPhoneGap) {
			var img = self.image.replace(/^.*\/|\.[^.]*$/g, '');
			// restaurant page image
			self.img = App.imgServer + '630x280/' + img +  '.jpg?crop=1';
			// restaurants page thumbnail
			self.img64 = App.imgServer + '596x596/' + img +  '.jpg';
		}

		if (typeof complete == 'function') {
			complete.call(self);
		}

	}

	self.tagfy = function( tag ){
		if( tag ){
			self._tag = tag;
			if( tag == 'opening' ){
				if( self._opensIn && self._opensIn_formatted != '' ){
					self._tag = tag;
				} else {
					self._tag = 'closed';
				}
			} else {
				self._tag = tag;
			}
			return;
		}

		self._tag = '';
		// Add the tags
		if( !self._open ){
			self._tag = 'closed';
			if( self._closedDueTo ){
				self._tag = 'force_close';
			}
		}
		if( self._open && self._closesIn !== 'false' && self._closesIn <= 15 ){
			self._tag = 'closing';
		}
		// if the restaurant does not have a closed message it has no hours for the week
		if( self.closed_message == '' ){
			self._tag = 'force_close';
		}
	}

	self.getNow = function( now ){
		if( now && now.getTime ){
			return now;
		}
		return dateTime.getNow();
	}

	self.openRestaurantPage = function( now ){
		// See 2662
		now = self.getNow( now );
		if( self.open( now, true ) ){
			return true;
		}
		self.opensIn( now );
		if( self._opensIn && self._opensIn < ( 3600 ) ){
			return true;
		}
		return false;
	}

	/*
	** Open/Close check methods
	*/
	// return true if the restaurant is open
	self.open = function( now, ignoreOpensClosesInCalc ) {

		self.tagfy( 'opening' );
		// if the restaurant has no hours it probably will not be opened for the next 24 hours
		self._hasHours = false;

		now = self.getNow( now );

		self.processHours();
		var now_time = now.getTime();
		// loop to verify if it is open
		self._open = false;
		if( self.hours ){
			for( x in self.hours ){
				self._hasHours = true;
				if( now_time >= self.hours[ x ]._from_time && now_time <= self.hours[ x ]._to_time ){
					if( self.hours[ x ].status == 'open' ){
						self._open = true;
						if( ignoreOpensClosesInCalc ){
							return self._open;
						}
						// if it is open calc closes in
						self.closesIn( now );
						self.tagfy();
						return self._open;
					} else if( self.hours[ x ].status == 'close' ){
						self._closedDueTo = ( self.hours[ x ].notes ) ? self.hours[ x ].notes : false;
						if( ignoreOpensClosesInCalc ){
							return self._open;
						}
						// If it is closed calc opens in
						self.opensIn( now );
						self.tagfy();
						return self._open;
					}
				}
			}
			// If it is closed calc opens in
			self.opensIn( now );
			self.tagfy();
			return self._open;
		} else {
			// if it doesn't have hours it is forced to be closed
			self._tag = 'force_close';
			self._closedDueTo = ' '; // There is no reason, leave it blank
		}
	}

	self.closesIn = function( now ){
		now = self.getNow( now );
		self._closesIn = false;
		self._closesIn_formatted = '';
		self.processHours();
		var now_time = now.getTime();
		if( self.hours ){
			for( x in self.hours ){
				if( self.hours[ x ].status == 'close' ){
					if( now_time <= self.hours[ x ]._from_time ){
						self._closesIn = timestampDiff( self.hours[ x ]._from_time, now_time );
						self._closesIn_formatted = formatTime( self._closesIn );
						return;
					}
				}
			}
		}
		if( self._closesIn == 0 || self._closesIn === false ){
			self._open = false;
		}
	}

	self.opensIn = function( now ){
		now = self.getNow( now );
		self._opensIn = false;
		self._opensIn_formatted = '';
		self.processHours();
		var now_time = now.getTime();
		for( x in self.hours ){
			if( self.hours[ x ].status == 'open' ){
				if( now_time <= self.hours[ x ]._from_time ){
					self._opensIn = timestampDiff( self.hours[ x ]._from_time, now_time );
					self._opensIn_formatted = formatTime( self._opensIn );
					return;
				}
			}
		}
		// it means the restaurant will not be opened for the next 24 hours
		if( self.next_open_time ){
				self._opensIn = timestampDiff( Date.parse( self.next_open_time ), now_time );
				self._opensIn_formatted = formatTime( self._opensIn, self.next_open_time_message );
		}
	}

	// Create javascript date objects to faster comparision
	self.processHours = function(){
		if( !self._hours_processed ){
			for( x in self.hours ){
				self.hours[ x ]._from = Date.parse( self.hours[ x ].from );
				self.hours[ x ]._from_time = self.hours[ x ]._from.getTime();
				self.hours[ x ]._to = Date.parse( self.hours[ x ].to );
				self.hours[ x ]._to_time = self.hours[ x ]._to.getTime();
			}
			self._hours_processed = true;
		}
	}

	// Check the restaurant cache age and reload the hours if it is necessary
	self.reloadHours = function( forceLoad ){
		var load = false;
		var now = ( Math.floor( new Date().getTime() / 1000 ) );
		if( forceLoad ){
			load = true;
		} else {
			var age = Math.floor( now - self.cachedAt ); // age in seconds
			// if the age is more or equals to 23 hours
			load = ( age >= ( ( 60 * 60 ) * 23 ) );
		}
		if( load ){
			var url = App.service + 'restaurant/hours/' + self.id_restaurant;
			App.http.get( url, {
				cache: false
			} ).success( function ( hours ) {
				self.cachedAt = now;
				self.hours = hours;
				self._hours_processed = false;
				self.processHours();
			} );
		}
	}

	self.load(id);

}

App.cached.Restaurant = {};
<|endoftext|>


<commit_before>var regex = /^data:.+\/(.+);base64,(.*)$/;

module.exports = function(indico, fs){
  return {
    //render home page
    getHome: function(req, res){
      res.render("home");
    },

    //send example image to client
    getImage: function(req, res){
      fs.readdir('public/images', function (err, imageNames){
        var currentFile = req.query.image;
        console.log(currentFile)
        var index = imageNames.indexOf(currentFile);
        imageNames.splice(index, 1);
        image = imageNames[Math.floor(Math.random()*imageNames.length)];
        fs.readFile('public/example_emotions.json', 'utf8', function (err, data) {
          var emotions = JSON.parse(data)[image]
          res.json({file: image, emotions: emotions});
        })
     })
    },

    //Recieve image from client and send response
    postImage: function(req, res){
      var string = String(req.body.data);
      string=string.split(",")[1];
      indico.fer(string, {detect:true, sensitivity:.8})
      .then(function(data) {
        if (data.length === 1 && 'location' in data[0]){
          data = data[0]['emotions'];
          status = "found"
          console.log("Face!");
          res.json({data:data, status:status});
        } else {
          res.json({data:NaN, status:"not_found"})
        }
      }).catch(function(err) {
        console.warn(err);
      });
    }
  };
};

<commit_msg>debug logs for heroku<commit_after>var regex = /^data:.+\/(.+);base64,(.*)$/;

module.exports = function(indico, fs){
  return {
    //render home page
    getHome: function(req, res){
      res.render("home");
    },

    //send example image to client
    getImage: function(req, res){
      fs.readdir('public/images', function (err, imageNames){
        var currentFile = req.query.image;
        console.log(currentFile)
        var index = imageNames.indexOf(currentFile);
        imageNames.splice(index, 1);
        image = imageNames[Math.floor(Math.random()*imageNames.length)];
        fs.readFile('public/example_emotions.json', 'utf8', function (err, data) {
          var emotions = JSON.parse(data)[image]
          res.json({file: image, emotions: emotions});
        })
     })
    },

    //Recieve image from client and send response
    postImage: function(req, res){
      var string = String(req.body.data);
      string=string.split(",")[1];
      indico.fer(string, {detect:true, sensitivity:.8})
      .then(function(data) {
        if (data.length === 1 && 'location' in data[0]){
          data = data[0]['emotions'];
          status = "found"
          console.log("Face!");
          res.json({data:data, status:status});
        } else {
          console.log("No Face!");
          res.json({data:NaN, status:"not_found"})
        }
      }).catch(function(err) {
        console.warn(err);
      });
    }
  };
};

<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var wechat = require('wechat');
var api = require('../wechat/wechat_api.js');
var config = require('../profile.json');
var fs = require('fs');

var request = require('request');

var gm = require('gm').subClass({ imageMagick: true });

var menu = JSON.stringify(require('../menu.json'));
api.createMenu(menu, function (err, result) { });

/* GET home page. */
router.get('/', function (req, res, next) {
  res.render('index', { title: 'Express' });
});

var Customer = require(config.models_factary)("customer");

router.get('/meetconfig', wechat(config, function (req, res, next) { }));
router.post('/meetconfig', wechat(config, function (req, res, next) {

  console.log("消息判断和事件响应");

  var message = req.weixin;
  console.log(message);

  switch (message.MsgType) {
    case "text": {
      if (message.Content === 'diaosi') {
        res.reply('hehe');
      } else if (message.Content === 'getUserList') {
        let c= finish_customer_create();
        console.log(c);
        if (c) {
          res.reply('保存成功');
        }
        else {
          res.reply('保存失败');
        }

      }
      else if (message.Content === 'qr') {
        api.createTmpQRCode("x", 100, function (err, data, response) {
          console.log(data);
          var path_wechat = "/home/userp/meet_quick/wechat/wechat_temp_qr/";
          var qucodemedia = api.showQRCodeURL(data.ticket);
          console.log("showQRCodeURL:" + qucodemedia);
          var qr_path = path_wechat + message.FromUserName + message.CreateTime + '.png';
          var a_path = path_wechat + 'a.jpg';
          var b_path = path_wechat + 'b.jpg';
          var c_path = path_wechat + 'c.png';
          var qr_path_out_resize = path_wechat + message.FromUserName + message.CreateTime + '_out1.png';
          var qr_path_out = path_wechat + message.FromUserName + message.CreateTime + '_out2.png';

          //测试用
          // var fileReadStream = fs.createReadStream(a_path);

          var fileWriteStream = fs.createWriteStream(qr_path);
          console.log("qr_path:" + qr_path);
          request(qucodemedia).pipe(fileWriteStream);
          // fileReadStream.pipe(fileWriteStream);
          fileWriteStream.on('close', function () {
            console.log('copy over');

            gm(qr_path)
              .resize(126, 126)
              .noProfile()
              .write(qr_path_out_resize, function (err) {
                if (!err) console.log('done');

                gm(a_path)
                  .composite(qr_path_out_resize)
                  .geometry('+130+67')
                  .write(qr_path_out, function (err) {
                    if (!err) console.log("Written composite image.");

                    api.uploadMedia(qr_path_out, "image", function (err, result) {

                      // gm(a_path)
                      //   .resize(480, 240)
                      //   .noProfile()
                      //   .write(qr_path_out, function (err) {
                      //     console.log(err);
                      //     if (!err) console.log('done');
                      //   });

                      // gm(a_path)
                      //   .composite(b_path)
                      //   .geometry('+100+150')
                      //   .write(qr_path_out, function (err) {
                      //     if (!err) console.log("Written composite image.");
                      //   });

                      console.log("result:" + result);
                      console.log("err:" + err);
                      res.reply({
                        type: "image",
                        content: {
                          mediaId: result.media_id
                        }
                      });
                    });
                  });
              });
          });
        });
      }
      else if (message.Content === 'hehe') {
        // 回复音乐
        res.reply({
          type: "music",
          content: {
            title: "来段音乐吧",
            description: "一无所有",
            musicUrl: "http://mp3.com/xx.mp3",
            hqMusicUrl: "http://mp3.com/xx.mp3",
            thumbMediaId: "thisThumbMediaId"
          }
        });
      }
      else {
        //图文回复
        res.reply([
          {
            title: 'meet_test_shell',
            description: 'meet_test_shell',
            picurl: 'http://nodeapi.cloudfoundry.com/qrcode.jpg',
            url: 'http://www.yangtz.com'
          }
        ]);
      }
    }; break;
    case "event": {
      switch (message.Event) {
        case "subscribe": {
          res.reply('subscribe');
          api.getUser(message.FromUserName, function (err, data, res) {
            for (key in data) {
              console.log(key + ":" + data[key]); // { errcode: 0, errmsg: 'ok' }
            }
          });
        }; break;
        case "unsubscribe": {
          res.reply('unsubscribe');
        }; break;
        case "SCAN": {
          res.reply('感谢您关注米特学院，么么哒，目前该功能还不完善，更多功能需要和彭老师一起定制哟' + message.EventKey);
        }; break;
      }
    }; break;
  }
}));

module.exports = router;

function getFollower() {
  return new Promise((resolve, reject) => {
    api.getFollowers(function (err, data, response) {
      resolve(data.data.openid);
    });
  });
};

function getBatchGetUsers(openids) {
  return new Promise((resolve, reject) => {
    api.batchGetUsers(openids, function (err, data, responses) {
      resolve(data["user_info_list"]);
    });
  });
};

function customer_create(alldatas) {
  return new Promise((resolve, reject) => {
    Customer.create(alldatas, function (err, response) {
      if (err) {
        console.log("保存失败:" + err);
        resolve(false);
      }
      else {
        console.log("保存成功:" + response);
        resolve(true);
      }
    });
  });
}

async function finish_customer_create() {
  let openids = await getFollower();
  let alldatas = await getBatchGetUsers(openids);
  // let check_create_success = await customer_create(alldatas);

  return await customer_create(alldatas);

  // Customer.create(alldatas, function (err, jellybean, snickers) {
  //   if (err) {
  //     console.log("保存失败" + err);
  //     res.reply('保存失败');
  //   }
  //   else {
  //     console.log("Res:" + jellybean);
  //     console.log("Res:" + snickers);
  //     res.reply('保存成功');
  //   }
  // });
}
<commit_msg>test promise try catch<commit_after>var express = require('express');
var router = express.Router();
var wechat = require('wechat');
var api = require('../wechat/wechat_api.js');
var config = require('../profile.json');
var fs = require('fs');

var request = require('request');

var gm = require('gm').subClass({ imageMagick: true });

var menu = JSON.stringify(require('../menu.json'));
api.createMenu(menu, function (err, result) { });

/* GET home page. */
router.get('/', function (req, res, next) {
  res.render('index', { title: 'Express' });
});

var Customer = require(config.models_factary)("customer");

router.get('/meetconfig', wechat(config, function (req, res, next) { }));
router.post('/meetconfig', wechat(config, function (req, res, next) {

  console.log("消息判断和事件响应");

  var message = req.weixin;
  console.log(message);

  switch (message.MsgType) {
    case "text": {
      if (message.Content === 'diaosi') {
        res.reply('hehe');
      } else if (message.Content === 'getUserList') {
        let c = finish_customer_create();
        console.log(c);
        if (c) {
          res.reply('保存成功');
        }
        else {
          res.reply('保存失败');
        }
      }
      else if (message.Content === 'qr') {
        api.createTmpQRCode("x", 100, function (err, data, response) {
          console.log(data);
          var path_wechat = "/home/userp/meet_quick/wechat/wechat_temp_qr/";
          var qucodemedia = api.showQRCodeURL(data.ticket);
          console.log("showQRCodeURL:" + qucodemedia);
          var qr_path = path_wechat + message.FromUserName + message.CreateTime + '.png';
          var a_path = path_wechat + 'a.jpg';
          var b_path = path_wechat + 'b.jpg';
          var c_path = path_wechat + 'c.png';
          var qr_path_out_resize = path_wechat + message.FromUserName + message.CreateTime + '_out1.png';
          var qr_path_out = path_wechat + message.FromUserName + message.CreateTime + '_out2.png';

          //测试用
          // var fileReadStream = fs.createReadStream(a_path);

          var fileWriteStream = fs.createWriteStream(qr_path);
          console.log("qr_path:" + qr_path);
          request(qucodemedia).pipe(fileWriteStream);
          // fileReadStream.pipe(fileWriteStream);
          fileWriteStream.on('close', function () {
            console.log('copy over');

            gm(qr_path)
              .resize(126, 126)
              .noProfile()
              .write(qr_path_out_resize, function (err) {
                if (!err) console.log('done');

                gm(a_path)
                  .composite(qr_path_out_resize)
                  .geometry('+130+67')
                  .write(qr_path_out, function (err) {
                    if (!err) console.log("Written composite image.");

                    api.uploadMedia(qr_path_out, "image", function (err, result) {

                      // gm(a_path)
                      //   .resize(480, 240)
                      //   .noProfile()
                      //   .write(qr_path_out, function (err) {
                      //     console.log(err);
                      //     if (!err) console.log('done');
                      //   });

                      // gm(a_path)
                      //   .composite(b_path)
                      //   .geometry('+100+150')
                      //   .write(qr_path_out, function (err) {
                      //     if (!err) console.log("Written composite image.");
                      //   });

                      console.log("result:" + result);
                      console.log("err:" + err);
                      res.reply({
                        type: "image",
                        content: {
                          mediaId: result.media_id
                        }
                      });
                    });
                  });
              });
          });
        });
      }
      else if (message.Content === 'hehe') {
        // 回复音乐
        res.reply({
          type: "music",
          content: {
            title: "来段音乐吧",
            description: "一无所有",
            musicUrl: "http://mp3.com/xx.mp3",
            hqMusicUrl: "http://mp3.com/xx.mp3",
            thumbMediaId: "thisThumbMediaId"
          }
        });
      }
      else {
        //图文回复
        res.reply([
          {
            title: 'meet_test_shell',
            description: 'meet_test_shell',
            picurl: 'http://nodeapi.cloudfoundry.com/qrcode.jpg',
            url: 'http://www.yangtz.com'
          }
        ]);
      }
    }; break;
    case "event": {
      switch (message.Event) {
        case "subscribe": {
          res.reply('subscribe');
          api.getUser(message.FromUserName, function (err, data, res) {
            for (key in data) {
              console.log(key + ":" + data[key]); // { errcode: 0, errmsg: 'ok' }
            }
          });
        }; break;
        case "unsubscribe": {
          res.reply('unsubscribe');
        }; break;
        case "SCAN": {
          res.reply('感谢您关注米特学院，么么哒，目前该功能还不完善，更多功能需要和彭老师一起定制哟' + message.EventKey);
        }; break;
      }
    }; break;
  }
}));

function getFollower() {
  return new Promise((resolve, reject) => {
    api.getFollowers(function (err, data, response) {
      resolve(data.data.openid);
    });
  });
};

function getBatchGetUsers(openids) {
  return new Promise((resolve, reject) => {
    api.batchGetUsers(openids, function (err, data, responses) {
      if (err) {
        console.log("批量获取数据失败:" + err);
        reject(false);
      }
      else {
        console.log("批量获取数据成功:");
        resolve(data["user_info_list"]);
      }
    });
  });
};

function customer_create(alldatas) {
  return new Promise((resolve, reject) => {
    Customer.create(alldatas, function (err, response) {
      if (err) {
        console.log("保存失败:" + err);
        reject(false);
      }
      else {
        console.log("保存成功:" + response);
        resolve(true);
      }
    });
  });
}

async function finish_customer_create() {
  try {
    let openids = await getFollower();
    let alldatas = await getBatchGetUsers(openids);
    return await customer_create(alldatas);
  } catch (err) {
    return false;
  }
};

module.exports = router;<|endoftext|>


<commit_before>controllers.MainMenu = {
	init: function() {
		var me = this;
		me.bindEvents();
	},
	bindEvents: function() {
		var me = this,
		view = views.MainMenu;

		view.on('touchstart', '.button.play', me.onPlay);
                view.on('touchstart', '.button.score', me.onScore);
                view.on('touchstart', '.button.help', me.onHelp);
	},
	onPlay: function() {
		controllers.Map.refreshCircles();
		views.Map.show(200);
		views.MainMenu.hide(200);

                controllers.Common.switchNavigationBar(
			"KARTA",
			"left-button back-from-map",
			"right-button info",
			"fa fa-chevron-left",
			"fa fa-info"
		);
	},
        onScore: function() {
            controllers.Score.setScoreBoard();

            views.Score.show(200);
            views.MainMenu.hide(200);

            controllers.Common.switchNavigationBar(
			"BODOVI",
			"left-button back-from-score",
			"right-button info",
			"fa fa-chevron-left",
			"fa fa-info"
            );
        },
        onHelp: function() {
            views.Help.show(200);
            views.MainMenu.hide(200);

            controllers.Common.switchNavigationBar(
			"POMOĆ",
			"left-button back-from-help",
			"right-button info",
			"fa fa-chevron-left",
			"fa fa-info"
            );
        }
};

<commit_msg>Dodano je da se pokrene zvuk, isključi i uključi<commit_after>var zvuk;

controllers.MainMenu = {
	init: function() {
		var me = this;
		controllers.zvuk = new Audio("sound/music.mp3");
		controllers.zvuk.loop = true;
		controllers.zvuk.play();
		me.bindEvents();
	},
	bindEvents: function() {
		var me = this,
		view = views.MainMenu;

		view.on('touchstart', '.button.play', me.onPlay);
                view.on('touchstart', '.button.score', me.onScore);
                view.on('touchstart', '.button.help', me.onHelp);
                view.on('touchstart', '.button.soundOn', me.onSound);
		view.on('touchstart', '.button.soundOff', me.onSound);
	},
	onPlay: function() {
		controllers.Map.refreshCircles();
		views.Map.show(200);
		views.MainMenu.hide(200);

                controllers.Common.switchNavigationBar(
			"KARTA",
			"left-button back-from-map",
			"right-button info",
			"fa fa-chevron-left",
			"fa fa-info"
		);
	},
        onScore: function() {
            controllers.Score.setScoreBoard();

            views.Score.show(200);
            views.MainMenu.hide(200);

            controllers.Common.switchNavigationBar(
			"BODOVI",
			"left-button back-from-score",
			"right-button info",
			"fa fa-chevron-left",
			"fa fa-info"
            );
        },
        onHelp: function() {
            views.Help.show(200);
            views.MainMenu.hide(200);

            controllers.Common.switchNavigationBar(
			"POMOĆ",
			"left-button back-from-help",
			"right-button info",
			"fa fa-chevron-left",
			"fa fa-info"
            );
        },
        onSound: function() {
		var soundButton = document.getElementById("sound");
		if(controllers.zvuk.paused){
			controllers.zvuk.play();
			soundButton.className = "button soundOn";
			}
		else{
			controllers.zvuk.pause();
			soundButton.className = "button soundOff";
			}
	}
};

<|endoftext|>


<commit_before>var routes = require('express').Router();

var School = require('../models/school');

var schools = require('./schools'),
    school_types = require('./school_types'),
    school_regions = require('./school_regions'),
    tasks = require('./tasks'),
    task_types = require('./task_types'),
    users = require('./users'),
    html = require('./html'),
    init = require('./init'),
    update = require('./update'),
    submit = require('./submit');

function isUniversity(school) {
    return school.level === 'vysoká škola';
}

function isHigherSchool(school) {
    return school.level === 'vyšší odborná škola';
}

routes.get('/', function(req, res, next) {
    console.log(req.ip);
    console.log(req.headers['user-agent']);
    School.where({ soft_deleted: false }).fetchAll().then(function(collection) {
        collection.load(['type', 'region']).then(function(loadedCollection) {
            var json = loadedCollection.toJSON();
            var universities = json.filter(isUniversity);
            var higherSchools = json.filter(isHigherSchool);

            res.render('index', {
                title: 'Dotazník',
                page: 'questionnaire',
                universities: universities,
                higherSchools: higherSchools
            });
        });
    }).catch(function(error) {
        res.render('error', {
            page: 'error',
            error: error
        });
    });
});

routes.get('/results', function(req, res, next) {
    res.render('results', {
        title: 'Výsledky',
        page: 'results'
    });
});

routes.post('/submit', submit);

routes.use('/schools', schools);
routes.use('/school-types', school_types);
routes.use('/school-regions', school_regions);
routes.use('/tasks', tasks);
routes.use('/task-types', task_types);
routes.use('/users', users);
routes.use('/html/task', html);
routes.use('/init', init);
routes.use('/update', update);

module.exports = routes;
<commit_msg>removed log<commit_after>var routes = require('express').Router();

var School = require('../models/school');

var schools = require('./schools'),
    school_types = require('./school_types'),
    school_regions = require('./school_regions'),
    tasks = require('./tasks'),
    task_types = require('./task_types'),
    users = require('./users'),
    html = require('./html'),
    init = require('./init'),
    update = require('./update'),
    submit = require('./submit');

function isUniversity(school) {
    return school.level === 'vysoká škola';
}

function isHigherSchool(school) {
    return school.level === 'vyšší odborná škola';
}

routes.get('/', function(req, res, next) {
    School.where({ soft_deleted: false }).fetchAll().then(function(collection) {
        collection.load(['type', 'region']).then(function(loadedCollection) {
            var json = loadedCollection.toJSON();
            var universities = json.filter(isUniversity);
            var higherSchools = json.filter(isHigherSchool);

            res.render('index', {
                title: 'Dotazník',
                page: 'questionnaire',
                universities: universities,
                higherSchools: higherSchools
            });
        });
    }).catch(function(error) {
        res.render('error', {
            page: 'error',
            error: error
        });
    });
});

routes.get('/results', function(req, res, next) {
    res.render('results', {
        title: 'Výsledky',
        page: 'results'
    });
});

routes.post('/submit', submit);

routes.use('/schools', schools);
routes.use('/school-types', school_types);
routes.use('/school-regions', school_regions);
routes.use('/tasks', tasks);
routes.use('/task-types', task_types);
routes.use('/users', users);
routes.use('/html/task', html);
routes.use('/init', init);
routes.use('/update', update);

module.exports = routes;
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var mdb = require('moviedb')('1046d0e8bf3b7860228747333688b85d');
var http = require('http');
var moviesService = require('../services/movies-service');
var locale = require('../locale/en_gb');
var downloader = require('downloader');

var movieData, location,
	imgDir = 'public/images/w342/',
	thumbDir = 'public/images/w92/';

/* GET home page. */
router.route('/')
.get(function (aRequest, aResponse) {
	moviesService.getAllMovies({}, function (aError, aMovies) {
		return aResponse.render('index', {
			homeView: true,
			lang: locale,
			movies : aMovies
		});
	});
})
.post(function (aRequest, aResponse) {
	var searchQuery = aRequest.body.search,
		searchQuery = encodeURIComponent(searchQuery);

	aResponse.redirect('/search-results/tmdb/' + searchQuery);
});

router.route('/collection')
.get(function (aRequest, aResponse) {
	moviesService.getAllMoviesCollection({}, function (aError, aMovies) {
		return aResponse.render('index', {
			searchView: true,
			searchable: true,
			lang: locale,
			movies : aMovies
		});
	});
})
.post(function (aRequest, aResponse) {
	var searchQuery = aRequest.body.search,
		searchQuery = encodeURIComponent(searchQuery);

	aResponse.redirect('/search-results/collection/' + searchQuery);
});

router.route('/movie-details/:id')
.get(function (aRequest, aResponse) {
	moviesService.findMovie(aRequest.params.id, function (aError, aResults) {
		movieData = aResults;

		if(!movieData.local_img) {
			downloader.download('http://image.tmdb.org/t/p/w342' + movieData.poster_path, imgDir);
			downloader.on('done', function (aResponse) {
				moviesService.updateImg(aRequest.params.id, function (aError, aResults) {});
			});
		}

		if (!movieData.local_thumb) {
			downloader.download('http://image.tmdb.org/t/p/w92' + movieData.poster_path, thumbDir);
			downloader.on('done', function (aResponse) {
				moviesService.updateThumb(aRequest.params.id, function (aError, aResults) {});
			});
		}

		if (!aResults) {
			mdb.movieInfo({id: aRequest.params.id  }, function(aError, aResults){
				movieData = aResults;
				return aResponse.render('index', {
					detailsView: true,
					lang: locale,
					movie : aResults
				});
			});
		} else {
			return aResponse.render('index', {
				detailsView: true,
				inCollection: true,
				lang: locale,
				movie : aResults
			});
		}

	});
})
.post(function (aRequest, aResponse) {
	moviesService.addMovie(movieData, aRequest.body, function (aError, aMovie) {
		if (aError) {
			return aResponse.render('index', {
				detailsView: true,
				movie: movieData,
				lang: locale,
				error: aError
			});
		}

		return aResponse.redirect('/movie-details/' + aRequest.params.id);
	});
});

router.route('/movie-details/:id/edit')
.get(function (aRequest, aResponse) {
	moviesService.findMovie(aRequest.params.id, function (aError, aResults) {
		movieData = aResults
		return aResponse.render('index', {
			detailsView: true,
			inCollection: true,
			editable: true,
			lang: locale,
			movie: aResults
		});
	});
})
.post(function (aRequest, aResponse) {
	moviesService.updateMovie(aRequest.params.id, aRequest.body, function (aError, aResults) {
		if (aError) {
			return aResponse.render('index', {
				detailsView: true,
				inCollection: true,
				editable: true,
				lang: locale,
				movie: aResults
			});
		}

		return aResponse.redirect('/movie-details/' + aRequest.params.id);
	})
});

router.route('/delete/:id')
.get(function (aRequest, aResponse) {
	moviesService.deleteTitle(aRequest.params.id, function (aError) {
		if (aError) {
			return aResponse.render('index', {
				detailsView: true,
				inCollection: true,
				editable: true,
				lang: locale,
				movie: aResults,
				error: aError
			});
		}

		return aResponse.redirect('/collection');
	});
});

router.route('/search-results/:location/:search')
.get(function (aRequest, aResponse) {
	location = aRequest.params.location;
	if (location == 'tmdb') {
		mdb.searchMovie({query: aRequest.params.search  }, function(aError, aResults){
		  return aResponse.render('index', {
		  	searchView: true,
		  	searchable: true,
		  	searchResults: true,
		  	lang: locale,
		  	movies : aResults.results
		  });
		});
	} else {
		moviesService.searchCollection(aRequest.params.search, function (aError, aResults) {
			if (aError) {
				console.log(aError);
				return aResponse.render('index', {
					detailsView: true,
					lang: locale,
					movie: movieData,
					error: aError
				});
			}

			return aResponse.render('index', {
				searchView: true,
				searchable: true,
				searchResults: true,
				lang: locale,
				movies : aResults
			});
		});
	}
})
.post(function (aRequest, aResponse) {
	var searchQuery = aRequest.body.search,
		searchQuery = encodeURIComponent(searchQuery);

	aResponse.redirect('/search-results/' + location + '/' + searchQuery);
})

module.exports = router;
<commit_msg>v0.4.0: Uncommented download code as it does not function on Heroku's read-only instance.<commit_after>var express = require('express');
var router = express.Router();
var mdb = require('moviedb')('1046d0e8bf3b7860228747333688b85d');
var http = require('http');
var moviesService = require('../services/movies-service');
var locale = require('../locale/en_gb');
var downloader = require('downloader');

var movieData, location,
	imgDir = 'public/images/w342/',
	thumbDir = 'public/images/w92/';

/* GET home page. */
router.route('/')
.get(function (aRequest, aResponse) {
	moviesService.getAllMovies({}, function (aError, aMovies) {
		return aResponse.render('index', {
			homeView: true,
			lang: locale,
			movies : aMovies
		});
	});
})
.post(function (aRequest, aResponse) {
	var searchQuery = aRequest.body.search,
		searchQuery = encodeURIComponent(searchQuery);

	aResponse.redirect('/search-results/tmdb/' + searchQuery);
});

router.route('/collection')
.get(function (aRequest, aResponse) {
	moviesService.getAllMoviesCollection({}, function (aError, aMovies) {
		return aResponse.render('index', {
			searchView: true,
			searchable: true,
			lang: locale,
			movies : aMovies
		});
	});
})
.post(function (aRequest, aResponse) {
	var searchQuery = aRequest.body.search,
		searchQuery = encodeURIComponent(searchQuery);

	aResponse.redirect('/search-results/collection/' + searchQuery);
});

router.route('/movie-details/:id')
.get(function (aRequest, aResponse) {
	moviesService.findMovie(aRequest.params.id, function (aError, aResults) {
		movieData = aResults;

		// Does not persist on Heroku instance
		// if(!movieData.local_img) {
		// 	downloader.download('http://image.tmdb.org/t/p/w342' + movieData.poster_path, imgDir);
		// 	downloader.on('done', function (aResponse) {
		// 		moviesService.updateImg(aRequest.params.id, function (aError, aResults) {});
		// 	});
		// }

		// if (!movieData.local_thumb) {
		// 	downloader.download('http://image.tmdb.org/t/p/w92' + movieData.poster_path, thumbDir);
		// 	downloader.on('done', function (aResponse) {
		// 		moviesService.updateThumb(aRequest.params.id, function (aError, aResults) {});
		// 	});
		// }

		if (!aResults) {
			mdb.movieInfo({id: aRequest.params.id  }, function(aError, aResults){
				movieData = aResults;
				return aResponse.render('index', {
					detailsView: true,
					lang: locale,
					movie : aResults
				});
			});
		} else {
			return aResponse.render('index', {
				detailsView: true,
				inCollection: true,
				lang: locale,
				movie : aResults
			});
		}

	});
})
.post(function (aRequest, aResponse) {
	moviesService.addMovie(movieData, aRequest.body, function (aError, aMovie) {
		if (aError) {
			return aResponse.render('index', {
				detailsView: true,
				movie: movieData,
				lang: locale,
				error: aError
			});
		}

		return aResponse.redirect('/movie-details/' + aRequest.params.id);
	});
});

router.route('/movie-details/:id/edit')
.get(function (aRequest, aResponse) {
	moviesService.findMovie(aRequest.params.id, function (aError, aResults) {
		movieData = aResults
		return aResponse.render('index', {
			detailsView: true,
			inCollection: true,
			editable: true,
			lang: locale,
			movie: aResults
		});
	});
})
.post(function (aRequest, aResponse) {
	moviesService.updateMovie(aRequest.params.id, aRequest.body, function (aError, aResults) {
		if (aError) {
			return aResponse.render('index', {
				detailsView: true,
				inCollection: true,
				editable: true,
				lang: locale,
				movie: aResults
			});
		}

		return aResponse.redirect('/movie-details/' + aRequest.params.id);
	})
});

router.route('/delete/:id')
.get(function (aRequest, aResponse) {
	moviesService.deleteTitle(aRequest.params.id, function (aError) {
		if (aError) {
			return aResponse.render('index', {
				detailsView: true,
				inCollection: true,
				editable: true,
				lang: locale,
				movie: aResults,
				error: aError
			});
		}

		return aResponse.redirect('/collection');
	});
});

router.route('/search-results/:location/:search')
.get(function (aRequest, aResponse) {
	location = aRequest.params.location;
	if (location == 'tmdb') {
		mdb.searchMovie({query: aRequest.params.search  }, function(aError, aResults){
		  return aResponse.render('index', {
		  	searchView: true,
		  	searchable: true,
		  	searchResults: true,
		  	lang: locale,
		  	movies : aResults.results
		  });
		});
	} else {
		moviesService.searchCollection(aRequest.params.search, function (aError, aResults) {
			if (aError) {
				console.log(aError);
				return aResponse.render('index', {
					detailsView: true,
					lang: locale,
					movie: movieData,
					error: aError
				});
			}

			return aResponse.render('index', {
				searchView: true,
				searchable: true,
				searchResults: true,
				lang: locale,
				movies : aResults
			});
		});
	}
})
.post(function (aRequest, aResponse) {
	var searchQuery = aRequest.body.search,
		searchQuery = encodeURIComponent(searchQuery);

	aResponse.redirect('/search-results/' + location + '/' + searchQuery);
})

module.exports = router;
<|endoftext|>


<commit_before>const express = require('express')
const router = express.Router()
const api = require('./api')

const { FACEBOOK_APP_ID, APP_URL, APP_TITLE, APP_DESCRIPTION, APP_IMAGE } = process.env

/* GET Home page. */
router.get('/', function (req, res) {
  res.render('index', { FACEBOOK_APP_ID, APP_URL, APP_TITLE, APP_DESCRIPTION, APP_IMAGE })
})

router.use('/api', api)

module.exports = router
<commit_msg>Update meta data for query a name<commit_after>const express = require('express')
const router = express.Router()
const api = require('./api')

const { FACEBOOK_APP_ID, APP_URL, APP_TITLE, APP_DESCRIPTION, APP_IMAGE } = process.env

/* GET Home page. */
router.get('/', function (req, res) {
  const name = req.query.name
  if (name) {
    return res.render('index', {
      FACEBOOK_APP_ID,
      APP_URL  : `${APP_URL}${req.url}`,
      APP_TITLE: `${name} on ${APP_TITLE}`,
      APP_DESCRIPTION,
      APP_IMAGE
    })
  }

  res.render('index', { FACEBOOK_APP_ID, APP_URL, APP_TITLE, APP_DESCRIPTION, APP_IMAGE })
})

router.use('/api', api)

module.exports = router
<|endoftext|>


<commit_before>var express = require('express');
var async   = require('async');
var session = require('../libs/session');
var flarum  = require('../libs/flarum');

var router = express.Router();

router.get('/', function(req, res, next) {
  session.settings(req, res, { shouldBeLogged:false }, function( settings ) {
    settings.title += "Connexion";
    res.render('login', settings);
  });
});

router.post('/login', function(req, res, next) {
  session.settings(req, res, { shouldBeLogged:false }, function( settings ) {

    req.checkBody('username', "Valeur invalide").notEmpty();
    req.checkBody('password', "Valeur invalide").notEmpty();

    var errors = req.validationErrors( true );

    async.waterfall([
      // Vérification du formulaire
      function( callback ) {
        if( errors )
          callback("Veuillez saisir vos identifiants mondedie.fr - flarum");
        else
          callback();
      },
      // Authentification via l'API
      function( callback ) {
        flarum.login(req.body, next, function( user ) {
          if( user )
            callback( null, user );
          else
            callback("Identifiant ou mot de passe incorrect.");
        });
      },
      // Préparation de la session
      function( user, callback ) {
        flarum.user(user, next, function( userInfos ) {
          if( userInfos ) {
            req.session.user = {
              id:userInfos.data.id,
              name:userInfos.data.attributes.username,
              groupName:( userInfos.included ) ? userInfos.included[0].attributes.namePlural : null,
              groupColor:( userInfos.included ) ? userInfos.included[0].attributes.color : null,
              avatar:process.env.FLARUM_URL + userInfos.data.attributes.avatarUrl
            };
            callback();
          } else {
            callback("Impossible d'initialiser la session utilisateur.");
          }
        });
      }
    ], function( err ) {
      if( err ) {
        settings.formMessage = err;
        return res.render('login', settings);
      } else {
        return res.redirect('/chatroom');
      }
    });
  });
});

router.get('/chatroom', function(req, res, next) {
  session.settings(req, res, { shouldBeLogged:true }, function( settings ) {
    settings.title += "Chatroom";
    res.render('chatroom', settings);
  });
});

module.exports = router;<commit_msg>Fix de l'url de l'avatar<commit_after>var express = require('express');
var async   = require('async');
var session = require('../libs/session');
var flarum  = require('../libs/flarum');

var router = express.Router();

router.get('/', function(req, res, next) {
  session.settings(req, res, { shouldBeLogged:false }, function( settings ) {
    settings.title += "Connexion";
    res.render('login', settings);
  });
});

router.post('/login', function(req, res, next) {
  session.settings(req, res, { shouldBeLogged:false }, function( settings ) {

    req.checkBody('username', "Valeur invalide").notEmpty();
    req.checkBody('password', "Valeur invalide").notEmpty();

    var errors = req.validationErrors( true );

    async.waterfall([
      // Vérification du formulaire
      function( callback ) {
        if( errors )
          callback("Veuillez saisir vos identifiants mondedie.fr - flarum");
        else
          callback();
      },
      // Authentification via l'API
      function( callback ) {
        flarum.login(req.body, next, function( user ) {
          if( user )
            callback( null, user );
          else
            callback("Identifiant ou mot de passe incorrect.");
        });
      },
      // Préparation de la session
      function( user, callback ) {
        flarum.user(user, next, function( userInfos ) {
          if( userInfos ) {
            req.session.user = {
              id:userInfos.data.id,
              name:userInfos.data.attributes.username,
              groupName:( userInfos.included ) ? userInfos.included[0].attributes.namePlural : null,
              groupColor:( userInfos.included ) ? userInfos.included[0].attributes.color : null,
              avatar:userInfos.data.attributes.avatarUrl
            };
            callback();
          } else {
            callback("Impossible d'initialiser la session utilisateur.");
          }
        });
      }
    ], function( err ) {
      if( err ) {
        settings.formMessage = err;
        return res.render('login', settings);
      } else {
        return res.redirect('/chatroom');
      }
    });
  });
});

router.get('/chatroom', function(req, res, next) {
  session.settings(req, res, { shouldBeLogged:true }, function( settings ) {
    settings.title += "Chatroom";
    res.render('chatroom', settings);
  });
});

module.exports = router;<|endoftext|>