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

    if(!global.cloudcmd)
        return console.log(
            '# commander.js'                                   + '\n'  +
            '# -----------'                                    + '\n'  +
            '# Module is part of Cloud Commander,'             + '\n'  +
            '# used for getting dir content.'                  + '\n'  +
            '# and forming html content'                       + '\n'  +
            '# http://coderaiser.github.com/cloudcmd'          + '\n');

    var main                = global.cloudcmd.main,
        fs                  = main.fs,
        CloudFunc           = main.cloudfunc,
        DIR                 = main.DIR,
        LIBDIR              = main.LIBDIR,
        HTMLDIR             = main.HTMLDIR,
        Util                = main.util,
        url                 = main.url,
        querystring         = main.querystring,
        zlib                = main.zlib,

        FILE_NOT_FOUND      = 404,
        OK                  = 200,

        FS                  = CloudFunc.FS,
        NO_JS               = CloudFunc.NOJS,

        INDEX               = null,
        REQUEST             = 'request',
        RESPONSE            = 'response',

        IndexProcessingFunc = null;

    exports.sendContent = function(pParams){
        var lRet = Util.checkObj(pParams,
            ['processing'],
            [REQUEST, RESPONSE, 'index']);

        if(lRet){
            var p       = pParams,
                lPath   = getCleanPath(p.request);

            INDEX   = p.index;
            IndexProcessingFunc = pParams.processing;

            fs.stat(lPath, function(pError, pStat){
                if(!pError)
                    if(pStat.isDirectory())
                        fs.readdir(lPath, Util.call(readDir, pParams) );
                    else
                        main.sendFile({
                            name        : lPath,
                            request     : p.request,
                            response    : p.response
                        });
                else
                    sendResponse({
                        status      : FILE_NOT_FOUND,
                        data        : pError.toString(),
                        request     : p.request,
                        response    : p.response
                    });
            });

            lRet = true;
        }

        return lRet;
    };

    /**
     * Функция читает ссылку или выводит информацию об ошибке
     * @param pError
     * @param pFiles
     */
    function readDir(pParams){
        var lRet,
            lError, lFiles, lHTTP,
            lReq, lRes;

        if(pParams){
            lError  = pParams.error;
            lFiles  = pParams.data;
            lHTTP   = pParams.params;

            if(lHTTP){
                lReq    = lHTTP.request,
                lRes    = lHTTP.response;
                lRet    = true;
            }
        }

        if(lRet && !lError && lFiles){
            lFiles = lFiles.sort();

            /* Получаем информацию о файлах */
            var n       = lFiles.length,
                lStats  = {},
                lFilesData = {
                    files       : lFiles,
                    stats       : lStats,
                    request     : lReq,
                    response    : lRes
                },

                lFill   = function(){
                    fillJSON(lFilesData);
                };

            if(n){
                var i, lDirPath = getCleanPath(lReq);

                for(i = 0; i < n; i++){
                    var lName = lDirPath + lFiles[i],
                        lParams =  {
                            callback    : lFill,
                            count       : n,
                            name        : lFiles[i],
                            stats       : lStats,
                        };

                    fs.stat( lName, Util.call(getFilesStat, lParams) );
                }
            }
            else
                fillJSON(lFilesData);
        }
        else
            sendResponse({
                status  : FILE_NOT_FOUND,
                data    : lError.toString(),
                request : lReq,
                response: lRes
            });
    }

    /**
     * async getting file states
     * and putting it to lStats object
     */
    function getFilesStat(pParams){
        var lRet = Util.checkObj(pParams,
                ['error', 'data', 'params'])    &&

            Util.checkObj(pParams.params,
                ['callback'], ['stats', 'name', 'count']);

        if(lRet){
            var p = pParams,
                c = p.params;

            if(c.stats)
                c.stats[c.name] = !p.error ? p.data   : {
                    'mode'          : 0,
                    'size'          : 0,
                    'isDirectory'   : Util.retFalse
                };

            if(c.count === Object.keys(c.stats).length)
                Util.exec(c.callback);
        }
    }

    /**
     * Function fill JSON by file stats
     *
     * @param pStats - object, contain file stats.
     *          example {'1.txt': stat}
     *
     * @param pFiles - array of files of current directory
     */
    function fillJSON(pParams){
        var lFiles, lAllStats,
            i, n, lReq, lRes;

        if(pParams){
            lFiles      = pParams.files;
            lFiles &&(n = lFiles.length || 0);
            lAllStats   = pParams.stats;
            lReq        = pParams.request,
            lRes        = pParams.response;
        }
        /* данные о файлах в формате JSON*/
        var lJSON       = [],
            lJSONFile   = {},
            lList,
            lDirPath = getCleanPath(lReq);

        lJSON[0]        = {
            path    : lDirPath,
            size    : 'dir'
        };

        var lName, lStats, lMode, lIsDir;
        for( i = 0; i < n; i++ ){
            /* Переводим права доступа в 8-ричную систему */
            lName   = lFiles[i],
            lStats  = lAllStats[lName];

            if(lStats){
                lMode   = (lStats.mode - 0).toString(8),
                lIsDir  = lStats.isDirectory();
            }

            /* Если папка - выводим пиктограмму папки   *
             * В противоположном случае - файла         */
            lJSONFile = {
                'name'  : lFiles[i],
                'size'  : lIsDir ? 'dir' : lStats.size,
                'uid'   : lStats.uid,
                'mode'  : lMode
            };

            lJSON[i+1] = lJSONFile;
        }

        /* если js недоступен
         * или отключен выcылаем html-код
         * и прописываем соответствующие заголовки
         */
        if( noJS(lReq) ){
            var lPanel  = CloudFunc.buildFromJSON(lJSON);
            lList       = '
'  + lPanel + '
' +
                          '
' + lPanel + '
';

            fs.readFile(INDEX, Util.call(readFile, {
                    list     : lList,
                    request  : lReq,
                    response : lRes
                })
            );

        }else{
            lDirPath = lDirPath.substr(lDirPath, lDirPath.lastIndexOf('/') );

            /* в обычном режиме(когда js включен
             * высылаем json-структуру файлов
             * с соответствующими заголовками
             */
            lList   = JSON.stringify(lJSON);

            sendResponse({
                name    : lDirPath + '.json',
                data    : lList,
                request : lReq,
                response: lRes
            });

        }
    }

    /**
     * Функция генерирует функцию считывания файла
     * таким образом, что бы у нас было
     * имя считываемого файла
     * @param pName - полное имя файла
     */
    function readFile(pParams){
        var lRet =  Util.checkObj(pParams,
            ['error', 'data', 'params'])    &&

        Util.checkObjTrue(pParams.params,
            [REQUEST, RESPONSE, 'list']);

        if(lRet){
            var p           = pParams,
                c           = pParams.params;

            p.data = p.data.toString();

            var lParams     = {
                    request : c.request,
                    response: c.response
                },

                lProccessed = Util.exec(IndexProcessingFunc, {
                    data        : p.data,
                    additional  : c.list
                });

            if(lProccessed)
                p.data = lProccessed;

            if (!p.Error){
                lParams.name      = INDEX;
                lParams.data      = p.data;

                Util.log('file ' + c.name + ' readed');
            }
            else{
                lParams.status    = FILE_NOT_FOUND;
                lParams.data      = p.error.toString();
            }

            sendResponse(lParams);
        }
    }
          /**
     * Функция высылает ответ серверу
     * @param pHead     - заголовок
     * @param Data      - данные
     * @param pName     - имя отсылаемого файла
     */
    function sendResponse(pParams){
         var lRet = Util.checkObjTrue(pParams,
            ['name', 'data', REQUEST, RESPONSE]);

        if(lRet){
            var p = pParams;

            var lPath       = p.name || getCleanPath(p.request),
                lQuery      = getQuery(p.request),
                /* download, json */
                lGzip       = isGZIP(p.request),
                lHead       = main.generateHeaders(lPath, lGzip, lQuery);

            /* если браузер поддерживает gzip-сжатие - сжимаем данные*/
            Util.ifExec(!lGzip,
                function(pParams){
                    var lRet = Util.checkObj(pParams, ['data']);

                    if(lRet){
                        p.status    = pParams.status;
                        p.data      = pParams.data;
                    }

                    p.response.writeHead(p.status || OK, lHead);
                    p.response.end(p.data);

                    Util.log(lPath + ' sended');
                    Util.log( p.status === FILE_NOT_FOUND && p.data );
                },

                function(pCallBack){
                    zlib.gzip (p.data, Util.call(gzipData, {
                        callback    : pCallBack
                    }));
                });
        }
    }

       /**
     * Функция получает сжатые данные
     * @param pHeader - заголовок файла
     * @pName
     */
    function gzipData(pParams){
        var lRet = Util.checkObj(pParams,
            ['error', 'data', 'params']);

        if(lRet)
            lRet = Util.checkObj(pParams.params,
                ['callback']);

        if(lRet){
            var p           = pParams,
                c           = pParams.params,
                lParams       = {};

            if(!p.error)
                lParams.data      = p.data;
            else{
                lParams.status    = FILE_NOT_FOUND;
                lParams.data      = p.error.toString();
            }

            Util.exec(c.callback, lParams);
        }
    }

    function getQuery(pReq){
        var lQuery, lParsedUrl;

        if(pReq){
            lParsedUrl  = url.parse(pReq.url);
            lQuery      = lParsedUrl.query;
        }

        return lQuery;
    }

    function getPath(pReq){
        var lParsedUrl  = url.parse(pReq.url),
            lPath       = lParsedUrl.pathname;

        lPath           = querystring.unescape(lPath);
        return lPath;
    }

    function getCleanPath(pReq){
        var lPath = getPath(pReq),
            lRet = Util.removeStr(lPath, [NO_JS, FS]) || main.SLASH;

        if(lRet !== '/')
            lRet += '/';

        return lRet;
    }

    function noJS(pReq){
        var lNoJS, lPath;

        if(pReq){
            lPath = getPath(pReq);

            lNoJS = Util.isContainStr(lPath, NO_JS)
                || lPath === '/' || getQuery() == 'json';
        }

        return lNoJS;
    }

    function isGZIP(pReq){
        var lEnc, lGZIP;
        if(pReq){
            lEnc        = pReq.headers['accept-encoding'] || '',
            lGZIP       = lEnc.match(/\bgzip\b/);
        }

        return lGZIP;
    }

})();<commit_msg>minor changes<commit_after>(function(){
    'use strict';

    if(!global.cloudcmd)
        return console.log(
            '# commander.js'                                   + '\n'  +
            '# -----------'                                    + '\n'  +
            '# Module is part of Cloud Commander,'             + '\n'  +
            '# used for getting dir content.'                  + '\n'  +
            '# and forming html content'                       + '\n'  +
            '# http://coderaiser.github.com/cloudcmd'          + '\n');

    var main                = global.cloudcmd.main,
        fs                  = main.fs,
        CloudFunc           = main.cloudfunc,
        DIR                 = main.DIR,
        LIBDIR              = main.LIBDIR,
        HTMLDIR             = main.HTMLDIR,
        Util                = main.util,
        url                 = main.url,
        querystring         = main.querystring,
        zlib                = main.zlib,

        FILE_NOT_FOUND      = 404,
        OK                  = 200,

        FS                  = CloudFunc.FS,
        NO_JS               = CloudFunc.NOJS,

        INDEX               = null,
        REQUEST             = 'request',
        RESPONSE            = 'response',

        IndexProcessingFunc = null;

    exports.sendContent = function(pParams){
        var lRet = Util.checkObj(pParams,
            ['processing'],
            [REQUEST, RESPONSE, 'index']);

        if(lRet){
            var p       = pParams,
                lPath   = getCleanPath(p.request);

            INDEX   = p.index;
            IndexProcessingFunc = pParams.processing;

            fs.stat(lPath, function(pError, pStat){
                if(!pError)
                    if(pStat.isDirectory())
                        fs.readdir(lPath, Util.call(readDir, pParams) );
                    else
                        main.sendFile({
                            name        : lPath,
                            request     : p.request,
                            response    : p.response
                        });
                else
                    sendResponse({
                        status      : FILE_NOT_FOUND,
                        data        : pError.toString(),
                        request     : p.request,
                        response    : p.response
                    });
            });

            lRet = true;
        }

        return lRet;
    };

    /**
     * Функция читает ссылку или выводит информацию об ошибке
     * @param pError
     * @param pFiles
     */
    function readDir(pParams){
        var lRet,
            lError, lFiles, lHTTP,
            lReq, lRes;

        if(pParams){
            lError  = pParams.error;
            lFiles  = pParams.data;
            lHTTP   = pParams.params;

            if(lHTTP){
                lReq    = lHTTP.request,
                lRes    = lHTTP.response;
                lRet    = true;
            }
        }

        if(lRet && !lError && lFiles){
            lFiles = lFiles.sort();

            /* Получаем информацию о файлах */
            var n       = lFiles.length,
                lStats  = {},
                lFilesData = {
                    files       : lFiles,
                    stats       : lStats,
                    request     : lReq,
                    response    : lRes
                },

                lFill   = function(){
                    fillJSON(lFilesData);
                };

            if(n){
                var i, lDirPath = getDirPath(lReq);

                for(i = 0; i < n; i++){
                    var lName = lDirPath + lFiles[i],
                        lParams =  {
                            callback    : lFill,
                            count       : n,
                            name        : lFiles[i],
                            stats       : lStats,
                        };

                    fs.stat( lName, Util.call(getFilesStat, lParams) );
                }
            }
            else
                fillJSON(lFilesData);
        }
        else
            sendResponse({
                status  : FILE_NOT_FOUND,
                data    : lError.toString(),
                request : lReq,
                response: lRes
            });
    }

    /**
     * async getting file states
     * and putting it to lStats object
     */
    function getFilesStat(pParams){
        var lRet = Util.checkObj(pParams,
                ['error', 'data', 'params'])    &&

            Util.checkObj(pParams.params,
                ['callback'], ['stats', 'name', 'count']);

        if(lRet){
            var p = pParams,
                c = p.params;

            if(c.stats)
                c.stats[c.name] = !p.error ? p.data   : {
                    'mode'          : 0,
                    'size'          : 0,
                    'isDirectory'   : Util.retFalse
                };

            if(c.count === Object.keys(c.stats).length)
                Util.exec(c.callback);
        }
    }

    /**
     * Function fill JSON by file stats
     *
     * @param pStats - object, contain file stats.
     *          example {'1.txt': stat}
     *
     * @param pFiles - array of files of current directory
     */
    function fillJSON(pParams){
        var lFiles, lAllStats,
            i, n, lReq, lRes;

        if(pParams){
            lFiles      = pParams.files;
            lFiles &&(n = lFiles.length || 0);
            lAllStats   = pParams.stats;
            lReq        = pParams.request,
            lRes        = pParams.response;
        }
        /* данные о файлах в формате JSON*/
        var lJSON       = [],
            lJSONFile   = {},
            lList;

        lJSON[0]        = {
            path    : getDirPath(lReq),
            size    : 'dir'
        };

        var lName, lStats, lMode, lIsDir;
        for( i = 0; i < n; i++ ){
            /* Переводим права доступа в 8-ричную систему */
            lName   = lFiles[i],
            lStats  = lAllStats[lName];

            if(lStats){
                lMode   = (lStats.mode - 0).toString(8),
                lIsDir  = lStats.isDirectory();
            }

            /* Если папка - выводим пиктограмму папки   *
             * В противоположном случае - файла         */
            lJSONFile = {
                'name'  : lFiles[i],
                'size'  : lIsDir ? 'dir' : lStats.size,
                'uid'   : lStats.uid,
                'mode'  : lMode
            };

            lJSON[i+1] = lJSONFile;
        }

        /* если js недоступен
         * или отключен выcылаем html-код
         * и прописываем соответствующие заголовки
         */
        if( noJS(lReq) ){
            var lPanel  = CloudFunc.buildFromJSON(lJSON);
            lList       = '
'  + lPanel + '
' +
                          '
' + lPanel + '
';

            fs.readFile(INDEX, Util.call(readFile, {
                    list     : lList,
                    request  : lReq,
                    response : lRes
                })
            );

        }else{
            lDirPath = lDirPath.substr(lDirPath, lDirPath.lastIndexOf('/') );

            /* в обычном режиме(когда js включен
             * высылаем json-структуру файлов
             * с соответствующими заголовками
             */
            lList   = JSON.stringify(lJSON);

            sendResponse({
                name    : lDirPath + '.json',
                data    : lList,
                request : lReq,
                response: lRes
            });

        }
    }

    /**
     * Функция генерирует функцию считывания файла
     * таким образом, что бы у нас было
     * имя считываемого файла
     * @param pName - полное имя файла
     */
    function readFile(pParams){
        var lRet =  Util.checkObj(pParams,
            ['error', 'data', 'params'])    &&

        Util.checkObjTrue(pParams.params,
            [REQUEST, RESPONSE, 'list']);

        if(lRet){
            var p           = pParams,
                c           = pParams.params;

            p.data = p.data.toString();

            var lParams     = {
                    request : c.request,
                    response: c.response
                },

                lProccessed = Util.exec(IndexProcessingFunc, {
                    data        : p.data,
                    additional  : c.list
                });

            if(lProccessed)
                p.data = lProccessed;

            if (!p.Error){
                lParams.name      = INDEX;
                lParams.data      = p.data;

                Util.log('file ' + c.name + ' readed');
            }
            else{
                lParams.status    = FILE_NOT_FOUND;
                lParams.data      = p.error.toString();
            }

            sendResponse(lParams);
        }
    }
          /**
     * Функция высылает ответ серверу
     * @param pHead     - заголовок
     * @param Data      - данные
     * @param pName     - имя отсылаемого файла
     */
    function sendResponse(pParams){
         var lRet = Util.checkObjTrue(pParams,
            ['name', 'data', REQUEST, RESPONSE]);

        if(lRet){
            var p = pParams;

            var lPath       = p.name || getCleanPath(p.request),
                lQuery      = getQuery(p.request),
                /* download, json */
                lGzip       = isGZIP(p.request),
                lHead       = main.generateHeaders(lPath, lGzip, lQuery);

            /* если браузер поддерживает gzip-сжатие - сжимаем данные*/
            Util.ifExec(!lGzip,
                function(pParams){
                    var lRet = Util.checkObj(pParams, ['data']);

                    if(lRet){
                        p.status    = pParams.status;
                        p.data      = pParams.data;
                    }

                    p.response.writeHead(p.status || OK, lHead);
                    p.response.end(p.data);

                    Util.log(lPath + ' sended');
                    Util.log( p.status === FILE_NOT_FOUND && p.data );
                },

                function(pCallBack){
                    zlib.gzip (p.data, Util.call(gzipData, {
                        callback    : pCallBack
                    }));
                });
        }
    }

       /**
     * Функция получает сжатые данные
     * @param pHeader - заголовок файла
     * @pName
     */
    function gzipData(pParams){
        var lRet = Util.checkObj(pParams,
            ['error', 'data', 'params']);

        if(lRet)
            lRet = Util.checkObj(pParams.params,
                ['callback']);

        if(lRet){
            var p           = pParams,
                c           = pParams.params,
                lParams       = {};

            if(!p.error)
                lParams.data      = p.data;
            else{
                lParams.status    = FILE_NOT_FOUND;
                lParams.data      = p.error.toString();
            }

            Util.exec(c.callback, lParams);
        }
    }

    function getQuery(pReq){
        var lQuery, lParsedUrl;

        if(pReq){
            lParsedUrl  = url.parse(pReq.url);
            lQuery      = lParsedUrl.query;
        }

        return lQuery;
    }

    function getPath(pReq){
        var lParsedUrl  = url.parse(pReq.url),
            lPath       = lParsedUrl.pathname;

        lPath           = querystring.unescape(lPath);
        return lPath;
    }

    function getCleanPath(pReq){
        var lPath = getPath(pReq),
            lRet = Util.removeStr(lPath, [NO_JS, FS]) || main.SLASH;

        return lRet;
    }

    function getDirPath(pReq){
        var lRet = getCleanPath(pReq);

        if(lRet !== '/')
            lRet += '/';

        return lRet;
    }

    function noJS(pReq){
        var lNoJS, lPath;

        if(pReq){
            lPath = getPath(pReq);

            lNoJS = Util.isContainStr(lPath, NO_JS)
                || lPath === '/' || getQuery() == 'json';
        }

        return lNoJS;
    }

    function isGZIP(pReq){
        var lEnc, lGZIP;
        if(pReq){
            lEnc        = pReq.headers['accept-encoding'] || '',
            lGZIP       = lEnc.match(/\bgzip\b/);
        }

        return lGZIP;
    }

})();<|endoftext|>


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

    var main            = global.cloudcmd.main,
        JSONDIR         = main.JSONDIR,

        fs              = main.fs,
        path            = main.path,
        Util            = main.util,

        CHANGESNAME     = JSONDIR       + 'changes',
        CHANGES_JSON    = CHANGESNAME   + '.json',

        Times           = main.require(CHANGESNAME) || [];

    exports.isFileChanged = function(pFileName, pCallBack){
        var lReadedTime, lData,
            i, n = Times.length;

        for(i = 0; i < n; i++){
            lData = Times[i];

            /* if founded row with file name - save hash */
            if(lData.name === pFileName){
                lReadedTime = lData.time;
                break;
            }
        }

        fs.stat(pFileName, function(pError, pStat){
            var lTimeChanged, lFileTime;

            if (!pError){
                lFileTime = pStat.mtime.getTime();

                if(lReadedTime !== lFileTime)
                    lTimeChanged = Times[i]        = {
                        name: pFileName,
                        time: lFileTime
                    };
            }
            else
                lTimeChanged = Util.log(pError);

            if(lTimeChanged)
                writeFile(CHANGES_JSON, Util.stringifyJSON(Times));

            Util.exec(pCallBack, lTimeChanged);
        });
    };

    /*
     * Функция записывает файла
     * и выводит ошибку или сообщает,
     * что файл успешно записан
     */
    function writeFile(pFileName, pData){
        fs.writeFile(pFileName, pData, function(pError){
            if(pError)
                Util.log(pError);
            else
                Util.log('file ' + path.basename(pFileName) + ' writed...');
        });
    }
})();<commit_msg>fix(ischanged) drop lTimeChanged init on error<commit_after>(function(){
    'use strict';

    var main            = global.cloudcmd.main,
        JSONDIR         = main.JSONDIR,

        fs              = main.fs,
        path            = main.path,
        Util            = main.util,

        CHANGESNAME     = JSONDIR       + 'changes',
        CHANGES_JSON    = CHANGESNAME   + '.json',

        Times           = main.require(CHANGESNAME) || [];

    exports.isFileChanged = function(pFileName, pCallBack){
        var lReadedTime, lData,
            i, n = Times.length;

        for(i = 0; i < n; i++){
            lData = Times[i];

            /* if founded row with file name - save hash */
            if(lData.name === pFileName){
                lReadedTime = lData.time;
                break;
            }
        }

        fs.stat(pFileName, function(pError, pStat){
            var lTimeChanged, lFileTime;

            if (!pError){
                lFileTime = pStat.mtime.getTime();

                if(lReadedTime !== lFileTime)
                    lTimeChanged = Times[i]        = {
                        name: pFileName,
                        time: lFileTime
                    };
            }
            else
                Util.log(pError);

            if(lTimeChanged)
                writeFile(CHANGES_JSON, Util.stringifyJSON(Times));

            Util.exec(pCallBack, lTimeChanged);
        });
    };

    /*
     * Функция записывает файла
     * и выводит ошибку или сообщает,
     * что файл успешно записан
     */
    function writeFile(pFileName, pData){
        fs.writeFile(pFileName, pData, function(pError){
            if(pError)
                Util.log(pError);
            else
                Util.log('file ' + path.basename(pFileName) + ' writed...');
        });
    }
})();<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var http = require('http');
var url = require('url');
var log = require('util/log');
var ps = require('util/pubsub');
var async = require('extern/async');
var version = require('util/version');
var sprintf = require('extern/sprintf').sprintf;
var category_map = require('categories').package_categories;
var sys = require('sys');

var config = require('util/config');
var db = require('util/db');

var NPM_BASE = 'http://registry.npmjs.org';
var INDEXER_WAIT_TIME = 10 * 60 * 1000;
var INDEXER_PACKAGE_DELAY = 1 * 1000;

/**
 * A -really- primitive HTTP GETter
 */
function http_get(uri, cb) {
  var parsed = url.parse(uri);
  var port = parsed.port || 80;
  var host = parsed.host;
  var path = parsed.pathname;

  var client = http.createClient(port, host);
  var request = client.request('GET', path, {host: host, 'User-Agent': version.toString()});
  request.end();

  request.on('response', function(response) {
    log.info(uri + " returned " + response.statusCode);
    var chunks = [];
    response.on('data', function(data) {
      chunks.push(data);
    });
    response.on('end', function() {
      var data = JSON.parse(chunks.join(''));
      return cb(response, data);
    });
  });
}

function npm_get(path, cb) {
  http_get(NPM_BASE + path, cb);
}

/**
 * Index packages.
 */
function PackageIndexer() {
  this.timeout_id = null;
}

/**
 * Schedule an indexer run. Will publish events on the app-wide pubsub as it
 * finishes indexing individual packages, and when the full run is complete.
 *
 * @param {Number} ms How many milliseconds from now to kick off the run
 */
PackageIndexer.prototype.schedule = function(ms) {
  var self = this;
  var time = (ms !== undefined) ? ms : INDEXER_WAIT_TIME;

  self.cancel();

  self.timeout_id = setTimeout(function() {
    self.run();
  }, time);
};

/**
 * Schedule a pending indexer run.
 */
PackageIndexer.prototype.cancel = function() {
  var self = this;
  if (self.timeout_id) {
    clearTimeout(self.timeout_id);
    self.timeout_id = null;
  }
};

/**
 * Do useful stuff.
 */
PackageIndexer.prototype.run = function() {
  var self = this;
  self.timeout_id = null;
  ps.emit('indexer.indexing.begin');

  npm_get('/', function(response, data) {
    self.handle_root(data);
  });
};

/**
 * Grab details about each package.
 */
PackageIndexer.prototype.handle_root = function(root) {
  var self = this;
  var names = Object.getOwnPropertyNames(root);

  // Grab details on each package in series - we're in no hurry
  async.forEachSeries(names, function(name, callback) {
    if (!root[name] || !root[name].url) {
      log.err("Skipping package, no URL: " + name);
      return callback();
    }

    var categories = category_map[name] || ["Uncategorized"];
    var pkg = {basics: root[name], categories: categories};

    // Get details from NPM
    http_get(root[name].url, function(response, data) {
      if (response.statusCode !== 200) {
        // Skip this package
        log.err("Error fetching package data from NPM: " + name);
        return callback();
      }
      else {
        pkg.details = data;
        self.index_package(pkg, callback);
      }
    });
  },

  // When we're done let everyone know
  function(err) {
    ps.emit('indexer.indexing.completed');
    self.schedule();
  });
};

PackageIndexer.prototype.index_package = function(pkg, cb) {
  var self = this;
  var package_data;

  function finish() {
    setTimeout(function() {
      cb();
    }, INDEXER_PACKAGE_DELAY);
  }

  try {
    package_data = db.format_package_data_for_storage(pkg);
  }
  catch (err) {
    log.err("Error formatting package for storage: " + err);
    return finish();
  }

  var query = {
    '_id': package_data._id,
    'latest_version': package_data.latest_version
  };

  db.collection.findOne(query, function(err, doc) {
    if (!doc || err) {
      // Data for this version is not yet saved, update it in the database
      db.collection.update({'_id': package_data._id}, package_data, {upsert: true}, function(err, doc) {
        if (err) {
          log.err("Error saving package data: " + err.message);
        }
        else {
          log.debug(sprintf('Saved package %s, version: %s', package_data._id, package_data.latest_version));
          ps.emit('indexer.indexed.package', pkg.basics.name);
        }
        return finish();
      });
    }
    else {
      return finish();
    }
  });
};

exports.indexer = new PackageIndexer();

exports.load = function() {
  ps.on(ps.STATE_START, function() {
    exports.indexer.schedule(0);
  });

  ps.on(ps.STATE_STOP, function() {
    exports.indexer.cancel();
  });
};
<commit_msg>Improved indexer skips up to date packages<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var http = require('http');
var url = require('url');
var log = require('util/log');
var ps = require('util/pubsub');
var async = require('extern/async');
var version = require('util/version');
var sprintf = require('extern/sprintf').sprintf;
var category_map = require('categories').package_categories;
var sys = require('sys');

var config = require('util/config');
var db = require('util/db');

var NPM_BASE = 'http://registry.npmjs.org';
var INDEXER_WAIT_TIME = 60 * 1000;
var INDEXER_PACKAGE_DELAY = 1 * 1000;

/**
 * A -really- primitive HTTP GETter
 */
function http_get(uri, cb) {
  var parsed = url.parse(uri);
  var port = parsed.port || 80;
  var host = parsed.host;
  var path = parsed.pathname;

  var client = http.createClient(port, host);
  var request = client.request('GET', path, {host: host, 'User-Agent': version.toString()});
  request.end();

  request.on('response', function(response) {
    log.info(uri + " returned " + response.statusCode);
    var chunks = [];
    response.on('data', function(data) {
      chunks.push(data);
    });
    response.on('end', function() {
      var data = JSON.parse(chunks.join(''));
      return cb(response, data);
    });
  });
}

function npm_get(path, cb) {
  http_get(NPM_BASE + path, cb);
}

/**
 * Index packages.
 */
function PackageIndexer() {
  this.timeout_id = null;
}

/**
 * Schedule an indexer run. Will publish events on the app-wide pubsub as it
 * finishes indexing individual packages, and when the full run is complete.
 *
 * @param {Number} ms How many milliseconds from now to kick off the run
 */
PackageIndexer.prototype.schedule = function(ms) {
  var self = this;
  var time = (ms !== undefined) ? ms : INDEXER_WAIT_TIME;

  self.cancel();

  self.timeout_id = setTimeout(function() {
    self.run();
  }, time);
};

/**
 * Schedule a pending indexer run.
 */
PackageIndexer.prototype.cancel = function() {
  var self = this;
  if (self.timeout_id) {
    clearTimeout(self.timeout_id);
    self.timeout_id = null;
  }
};

/**
 * Do useful stuff.
 */
PackageIndexer.prototype.run = function() {
  var self = this;
  self.timeout_id = null;
  ps.emit('indexer.indexing.begin');

  npm_get('/', function(response, data) {
    self.handle_root(data);
  });
};

/**
 * Grab details about each package.
 */
PackageIndexer.prototype.handle_root = function(root) {
  var self = this;
  var names = Object.getOwnPropertyNames(root);

  // Grab details on each package in series - we're in no hurry
  async.forEachSeries(names, function(name, callback) {
    if (!root[name] || !root[name].url) {
      log.err("Skipping package, no URL: " + name);
      return callback();
    }

    db.collection.findOne({'_id': name, 'mtime': root[name].mtime}, function(err, doc) {
      if (err || !doc) {
        log.info("Package out of date: " + name);
        var categories = category_map[name] || ["Uncategorized"];
        var pkg = {basics: root[name], categories: categories};

        // Get details from NPM
        http_get(root[name].url, function(response, data) {
          if (response.statusCode !== 200) {
            // Skip this package
            log.err("Error fetching package data from NPM: " + name);
            return callback();
          }
          else {
            pkg.details = data;
            self.index_package(pkg, callback);
          }
        });
      }
      else {
        return callback();
      }
    });

  },

  // When we're done let everyone know
  function(err) {
    ps.emit('indexer.indexing.completed');
    self.schedule();
  });
};

PackageIndexer.prototype.index_package = function(pkg, cb) {
  var self = this;
  var package_data;

  function finish() {
    setTimeout(function() {
      cb();
    }, INDEXER_PACKAGE_DELAY);
  }

  try {
    package_data = db.format_package_data_for_storage(pkg);
  }
  catch (err) {
    log.err("Error formatting package for storage: " + err);
    return finish();
  }

  var query = {
    '_id': package_data._id,
    'latest_version': package_data.latest_version
  };

  db.collection.findOne(query, function(err, doc) {
    if (!doc || err) {
      // Data for this version is not yet saved, update it in the database
      db.collection.update({'_id': package_data._id}, package_data, {upsert: true}, function(err, doc) {
        if (err) {
          log.err("Error saving package data: " + err.message);
        }
        else {
          log.debug(sprintf('Saved package %s, version: %s', package_data._id, package_data.latest_version));
          ps.emit('indexer.indexed.package', pkg.basics.name);
        }
        return finish();
      });
    }
    else {
      return finish();
    }
  });
};

exports.indexer = new PackageIndexer();

exports.load = function() {
  ps.on(ps.STATE_START, function() {
    exports.indexer.schedule(0);
  });

  ps.on(ps.STATE_STOP, function() {
    exports.indexer.cancel();
  });
};
<|endoftext|>


<commit_before>define([
	'jquery',
	'underscore',
	'backbone',

	'backendServiceM',
	],
	function ($, _, Backbone, backendServiceM) {
		var FormV = Backbone.View.extend({
			currentTabName: null,
			el: '#form-wrapper',
			events: {
				'keypress :input': 'submit',
				'click :input[type="submit"]': 'submit',
				'click .nav-tabs a': 'changeTab',
			},
			model: backendServiceM,

			initialize: function () {
				this.currentTabName = this.model.startTabName;
				this.listenTo(this.model, 'change:formData', this.render);
			},
			changeTab: function(evt) {
				evt.preventDefault();
				var tabName = $(evt.target).data('tab-name');
				if (tabName === this.currentTabName) {
					return;
				}
				var $form = this.$el.find('form');
				var formDataStr = $form.serialize();
				this.model.saveForm(this.currentTabName, formDataStr, $.proxy(function() {
					this.model.fetchForm(tabName, $.proxy(this.model.simulate, this.model));
				}, this));
				this.currentTabName = tabName;
			},
			render: function () {
				var data = this.model.get('formData');
				this.$el.html(data);
				return this;
			},
			submit: function(evt) {
				if (evt.type == 'keypress' && evt.keyCode !== 13) {
					return;
				}
				evt.preventDefault();
				var $form = this.$el.find('form');
				var formDataStr = $form.serialize();
				if (evt.type == 'click') {
					// Add clicked button to form data.
					var $button = $(evt.target);
					var name = $button.attr('name');
					if ( ! _.isUndefined(name)) {
						var value = $button.attr('value');
						formDataStr += '&' + name + '=' + value;
					}
				}
				this.model.saveForm(this.currentTabName, formDataStr, $.proxy(function() {
					this.model.fetchForm(this.currentTabName, $.proxy(this.model.simulate, this.model));
				}, this));
			}
		});
		return FormV;
	}
);
<commit_msg>Submit form on input change.<commit_after>define([
	'jquery',
	'underscore',
	'backbone',

	'backendServiceM',
	],
	function ($, _, Backbone, backendServiceM) {
		var FormV = Backbone.View.extend({
			currentTabName: null,
			el: '#form-wrapper',
			events: {
				'change :input': 'submit',
				'click :input[type="submit"]': 'submit',
				'click .nav-tabs a': 'changeTab',
				'keypress :input': 'submit'
			},
			model: backendServiceM,

			initialize: function () {
				this.currentTabName = this.model.startTabName;
				this.listenTo(this.model, 'change:formData', this.render);
			},
			changeTab: function(evt) {
				evt.preventDefault();
				var tabName = $(evt.target).data('tab-name');
				if (tabName === this.currentTabName) {
					return;
				}
				var $form = this.$el.find('form');
				var formDataStr = $form.serialize();
				this.model.saveForm(this.currentTabName, formDataStr, $.proxy(function() {
					this.model.fetchForm(tabName, $.proxy(this.model.simulate, this.model));
				}, this));
				this.currentTabName = tabName;
			},
			render: function () {
				var data = this.model.get('formData');
				this.$el.html(data);
				return this;
			},
			submit: function(evt) {
				if (evt.type == 'keypress' && evt.keyCode !== 13) {
					return;
				}
				evt.preventDefault();
				var $form = this.$el.find('form');
				var formDataStr = $form.serialize();
				if (evt.type == 'click') {
					// Add clicked button to form data.
					var $button = $(evt.target);
					var name = $button.attr('name');
					if ( ! _.isUndefined(name)) {
						var value = $button.attr('value');
						formDataStr += '&' + name + '=' + value;
					}
				}
				this.model.saveForm(this.currentTabName, formDataStr, $.proxy(function() {
					this.model.fetchForm(this.currentTabName, $.proxy(this.model.simulate, this.model));
				}, this));
			}
		});
		return FormV;
	}
);
<|endoftext|>


<commit_before>/**
 * CareWheels - Group Status Controller
 *
 */
angular.module('careWheels').controller('groupStatusController',
  function ($scope, $interval, $state, GroupInfo) {

    /******************** TESTING *****************************/
    //var usergroup = $scope.data = angular.fromJson(window.localStorage['UserGroup']);

    /* TODO find a better solution */
    // the groupInfo object is not available immediately, spin until available
    var triggerGroupInfo = setInterval(function(){
      var groupArray = GroupInfo.groupInfo();
      if ( groupArray[0] != null ){
        clearInterval(triggerGroupInfo);
        console.log(groupArray);
        for (var i = 0; i < groupArray.length; i++){
          $scope.group[i].image = groupArray[i].photoUrl;
          $scope.group[i].username = groupArray[i].username;
        }
      }
    }, 500);

    setInterval(function(){

      var groupArray = GroupInfo.groupInfo();
      for (var i = 0; i < groupArray.length; i ++){
        try{
          $scope.group[i].status = getAlertColor(groupArray[i].analysisData.fridgeAlertLevel, groupArray[i].analysisData.medsAlertLevel);
        }
        catch(Exception) {
          $scope.group[i].status = 'blue';
        }
      }
    }, 2000);

    function getAlertColor(fridge, meds){
      fridge = parseInt(fridge);
      meds = parseInt(meds);
      if (fridge == 3 || meds == 3)
        return 'red';
      else if (fridge == 2 || meds == 2)
        return 'yellow';
      else
        console.log('blue alert');
        return 'blue';
    }

    /************** END TEST BLOCK ***************************/

    /* TODO: this is currently mocked data */
    $scope.group = [
      { // center, self
        username: '',
        credits: "0.0",
        debits: "0.0",
        image: ''
      },
      { // top left
        username: '',
        status: '',
        image: ''
      },
      { // top right
        username: '',
        status: '',
        image: ''
      },
      { // bottom left
        username: '',
        status: '',
        image: ''
      },
      { // bottom right
        username: '',
        status: '',
        image: ''
      }
    ];

    /* click/press events */
    $scope.clickTopLeft = function () {
      //todo: goto individualStatus.html for this user
      console.log('clicked top left');
      $state.go('app.individualStatus');
      var groupArray = GroupInfo.groupInfo();
      console.log('GroupInfo:', groupArray);
    };
    $scope.clickTopRight = function () {
      console.log('clicked top right');
      $state.go('app.individualStatus');

    };
    $scope.clickBottomLeft = function () {
      console.log('clicked bottom left');
      $state.go('app.individualStatus');

    };
    $scope.clickBottomRight = function () {
      console.log('clicked bottom right');
      $state.go('app.individualStatus');

    };
    $scope.clickCenter = function () {
      console.log('clicked center');
    };
    $scope.clickCareBank = function () {
      console.log('clicked carebank');
    };

    /** automatically go through each user square, and
     *  find each 'red' alert, and fade that element in
     *  and out. (flashing effect)
     * */
    $interval(function (){
      var alertArray = [
        $('#topLeftAlert'),
        $('#topRightAlert'),
        $('#bottomLeftAlert'),
        $('#bottomRightAlert')
      ];
      for(var i =0; i < alertArray.length; i++){
        if(alertArray[i].css('background-color') === 'rgb(255, 0, 0)'){
          alertArray[i].fadeOut("slow");
          alertArray[i].fadeIn("slow");
        }
      }
    }, 2000)

  });
<commit_msg>cleaned up sensor data implementation<commit_after>/**
 * CareWheels - Group Status Controller
 *
 */
angular.module('careWheels').controller('groupStatusController',
  function ($scope, $interval, $state, GroupInfo) {

    /******************** TESTING *****************************/

    /* TODO find a better solution */
    // the groupInfo object is not available immediately, spin until available
    var triggerGroupInfo = setInterval(function(){
      var groupArray = GroupInfo.groupInfo();
      if ( groupArray[0] != null ){
        clearInterval(triggerGroupInfo);
        console.log(groupArray);
        for (var i = 0; i < groupArray.length; i++){
          $scope.group[i].image = groupArray[i].photoUrl;
          $scope.group[i].username = groupArray[i].username;
        }
      }
    }, 50);

    setInterval(function(){
      var groupArray = GroupInfo.groupInfo();
      for (var i = 0; i < groupArray.length; i ++){
        try{
          var fridgeAlert = groupArray[i].analysisData.fridgeAlertLevel;
          var medsAlert = groupArray[i].analysisData.medsAlertLevel;
          $scope.group[i].status = getAlertColor(fridgeAlert, medsAlert);
        }
        catch(Exception) {
          $scope.group[i].status = 'blue';
        }
      }
    }, 50);

    function getAlertColor(fridge, meds){
      fridge = parseInt(fridge);
      meds = parseInt(meds);
      if (fridge == 3 || meds == 3)
        return 'red';
      else if (fridge == 2 || meds == 2)
        return 'yellow';
      else
        console.log('blue alert');
        return 'blue';
    }

    /************** END TEST BLOCK ***************************/

    /* TODO: this is currently mocked data */
    $scope.group = [
      { // center, self
        username: '',
        credits: "0.0",
        debits: "0.0",
        image: ''
      },
      { // top left
        username: '',
        status: '',
        image: ''
      },
      { // top right
        username: '',
        status: '',
        image: ''
      },
      { // bottom left
        username: '',
        status: '',
        image: ''
      },
      { // bottom right
        username: '',
        status: '',
        image: ''
      }
    ];

    /* click/press events */
    $scope.clickTopLeft = function () {
      //todo: goto individualStatus.html for this user
      console.log('clicked top left');
      $state.go('app.individualStatus');
      var groupArray = GroupInfo.groupInfo();
      console.log('GroupInfo:', groupArray);
    };
    $scope.clickTopRight = function () {
      console.log('clicked top right');
      $state.go('app.individualStatus');

    };
    $scope.clickBottomLeft = function () {
      console.log('clicked bottom left');
      $state.go('app.individualStatus');

    };
    $scope.clickBottomRight = function () {
      console.log('clicked bottom right');
      $state.go('app.individualStatus');

    };
    $scope.clickCenter = function () {
      console.log('clicked center');
    };
    $scope.clickCareBank = function () {
      console.log('clicked carebank');
    };

    /** automatically go through each user square, and
     *  find each 'red' alert, and fade that element in
     *  and out. (flashing effect)
     * */
    $interval(function (){
      var alertArray = [
        $('#topLeftAlert'),
        $('#topRightAlert'),
        $('#bottomLeftAlert'),
        $('#bottomRightAlert')
      ];
      for(var i =0; i < alertArray.length; i++){
        if(alertArray[i].css('background-color') === 'rgb(255, 0, 0)'){
          alertArray[i].fadeOut("slow");
          alertArray[i].fadeIn("slow");
        }
      }
    }, 2000)

  });
<|endoftext|>


<commit_before>import R from "ramda";
import Promise from "bluebird";
import pm2 from "./pm2";
import prettyBytes from "pretty-bytes";
import { promises } from "./util";
import log from "./log";

export default (apps) => {
  const processNameToAppId = (name) => name.split(":")[0];
  const getApp = (id) => {
    id = processNameToAppId(id);
    return R.find(app => app.id === id, apps);
  };

  const getAppStatus = (app, processItem) => {
      return new Promise((resolve, reject) => {
          if (!app || !processItem) {
            resolve();
            return;
          }

          const status = {
              id: app.id,
              status: processItem.pm2_env.status,
              route: `${ app.route.toString() } ⇨ ${ app.port }`,
              repository: `${ app.repo.name }:${ app.branch }`,
              resources: {
                memory: prettyBytes(processItem.monit.memory),
                cpu: processItem.monit.cpu
              }
          };

          const gettingVersion = app.version().catch(err => reject(err));
          gettingVersion.then(version => {
              status.version = {
                local: version.local,
                remote: version.remote
              };
              if (version.isUpdateRequired) { status.version.isUpdateRequired = true; }
              if (version.isDependenciesChanged) { status.version.isDependenciesChanged = true; }
              if (version.isDownloading) {
                status.status += `, updating to v${ version.remote }`;
                status.version.isDownloading = true;
              }
              resolve(status);
            });
      });
    };

  const getRunningApps = () => {
        return new Promise((resolve, reject) => {
          Promise.coroutine(function*() {
            const processes = yield pm2.apps();
            let { results } = yield promises(processes.map(item => getAppStatus(getApp(item.name), item))).catch(err => reject(err));
            results = R.reject(R.isNil)(results);
            results = R.sortBy(R.prop("id"))(results);
            resolve(results);
          })();
        });
      };

  return {
    getStatuses(req, res) {
      getRunningApps()
        .then(appsStatus => res.send({ apps: appsStatus }))
        .catch(err => {
            log.error(err);
            res.status(500).send({
              error: "Failed while getting the status of running applications",
              message: err.message
            });
        });
    },

    getAppStatus(req, res) {
      Promise.coroutine(function*() {
        const id = req.params.app;
        const app = getApp(id);
        const sendFail = (err) => res.status(500).send({ message: `Failed while getting the status of the application '${ id }'.`, err: err.message });
        if (!app) {
          res.status(404).send({ error: `The application '${ id }' does not exist.` });
        } else {
          const processes = yield pm2
              .apps(item => processNameToAppId(item.name) === id)
              .catch(err => sendFail(err));

          const item = processes[0];
          const status = yield getAppStatus(getApp(item.name), item).catch(err => sendFail(err));
          res.send(status);
        }
      })();
    }
  };
};
<commit_msg>Process HOSTNAME on API status JSON.<commit_after>import R from "ramda";
import Promise from "bluebird";
import pm2 from "./pm2";
import prettyBytes from "pretty-bytes";
import { promises } from "./util";
import log from "./log";

const HOST_NAME = process.env["HOSTNAME"] || "unknown";

export default (apps) => {
  const processNameToAppId = (name) => name.split(":")[0];
  const getApp = (id) => {
    id = processNameToAppId(id);
    return R.find(app => app.id === id, apps);
  };

  const getAppStatus = (app, processItem) => {
      return new Promise((resolve, reject) => {
          if (!app || !processItem) {
            resolve();
            return;
          }

          const status = {
              id: app.id,
              status: processItem.pm2_env.status,
              route: `${ app.route.toString() } ⇨ ${ app.port }`,
              repository: `${ app.repo.name }:${ app.branch }`,
              resources: {
                memory: prettyBytes(processItem.monit.memory),
                cpu: processItem.monit.cpu
              }
          };

          const gettingVersion = app.version().catch(err => reject(err));
          gettingVersion.then(version => {
              status.version = {
                local: version.local,
                remote: version.remote
              };
              if (version.isUpdateRequired) { status.version.isUpdateRequired = true; }
              if (version.isDependenciesChanged) { status.version.isDependenciesChanged = true; }
              if (version.isDownloading) {
                status.status += `, updating to v${ version.remote }`;
                status.version.isDownloading = true;
              }
              resolve(status);
            });
      });
    };

  const getRunningApps = () => {
        return new Promise((resolve, reject) => {
          Promise.coroutine(function*() {
            const processes = yield pm2.apps();
            let { results } = yield promises(processes.map(item => getAppStatus(getApp(item.name), item))).catch(err => reject(err));
            results = R.reject(R.isNil)(results);
            results = R.sortBy(R.prop("id"))(results);
            resolve(results);
          })();
        });
      };

  return {
    getStatuses(req, res) {
      getRunningApps()
        .then(appsStatus => res.send({ host: HOST_NAME, apps: appsStatus }))
        .catch(err => {
            log.error(err);
            res.status(500).send({
              error: "Failed while getting the status of running applications",
              message: err.message
            });
        });
    },

    getAppStatus(req, res) {
      Promise.coroutine(function*() {
        const id = req.params.app;
        const app = getApp(id);
        const sendFail = (err) => res.status(500).send({ message: `Failed while getting the status of the application '${ id }'.`, err: err.message });
        if (!app) {
          res.status(404).send({ error: `The application '${ id }' does not exist.` });
        } else {
          const processes = yield pm2
              .apps(item => processNameToAppId(item.name) === id)
              .catch(err => sendFail(err));

          const item = processes[0];
          const status = yield getAppStatus(getApp(item.name), item).catch(err => sendFail(err));
          res.send(status);
        }
      })();
    }
  };
};
<|endoftext|>


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

    window.Pixfinder = {

        getObject: function(options) {
            var opt = _getCommonDefaults(options),
                canv = Pixfinder.Util.Canvas.wrapImgByCanvas(opt.img),
                ctx = canv.getContext('2d'),
                imgSize = { w: canv.width, h: canv.height },
                imgCols = ctx.getImageData(0, 0, imgSize.w, imgSize.h).data,
                colPos = Pixfinder.Util.Canvas.getColorPositionByPixel(opt.startPixel, imgSize),
                pxCol = [imgCols[colPos], imgCols[colPos+1], imgCols[colPos+2], imgCols[colPos+3]],
                isStartPxInObject = false,
                borderPxs = [];

            isStartPxInObject = _isColorInColors(
                Pixfinder.Util.Color.areSimilar,
                pxCol,
                opt.colors,
                opt.tolerance
            );
            if (!isStartPxInObject) { return []; }

            borderPxs = _getBorderPxsWithOffset([opt.startPixel], borderPxs, canv, ctx, imgSize, imgCols, opt);

            borderPxs = borderPxs.map(function(px) {
                return [px.x, px.y];
            });
            borderPxs = hull(borderPxs, 5);
            borderPxs = borderPxs.map(function(px) {
                return {x: px[0], y: px[1]};
            });

            return borderPxs;
        },

        getObjects: function(options) {
            var canv,
                objects,
                regionsPxs,
                opt = _getCommonDefaults(options);

            opt.clearNoise = opt.clearNoise || false;

            canv = Pixfinder.Util.Canvas.wrapImgByCanvas(opt.img);

            regionsPxs = _getRegionsPixels(
                canv,
                opt.colors,
                opt.accuracy,
                opt.tolerance,
                opt.fill
            );

            objects = _splitByDist(regionsPxs, opt.distance);

            objects = objects.map(function(object) {
                return poly2cw(object, 'tsp');
            });

            objects = opt.clearNoise ?
                _clearNoise(objects, opt.clearNoise) : objects;

            return objects;
        }
    };

    var blacklist = [],
        blacklistHash = {};
    function _getBorderPxs(px, canvas, options) { // (Pixel, HTMLCanvasElement, Object) -> Object
        var result = [];

        bfs(canvas, px, {
            onvisit: function(e) {
                blacklist.push(e.pixel.coord);
                blacklistHash[e.pixel.coord.x + '-' + e.pixel.coord.y] = true;
                if (!_isColorInColors(
                    Pixfinder.Util.Color.areSimilar,
                    e.pixel.color,
                    options.colors,
                    options.tolerance
                )) {
                    result.push(e.pixel.coord);
                    e.skip();
                }
            }
        }, blacklist);

        // ctx1.fillStyle="red";
        // for (var i = 0; i < result.length; i++) {
        //     ctx1.beginPath();
        //     ctx1.arc(result[i].x, result[i].y, 1, 0, 2 * Math.PI, true);
        //     ctx1.fill();
        //     ctx1.closePath();
        // }

        return result;
    }

    var pixelsAroundBorderBlacklist = {};
    function _getPixelsAroundBorder(borderPxs, imgSize) {
        var result = [];

        Pixfinder.Util.Obj.extend(pixelsAroundBorderBlacklist, blacklistHash);
        function _notInBlacklist(px) {
            return pixelsAroundBorderBlacklist[px.x + '-' + px.y] !== true;
        }

        borderPxs.forEach(function(px) {
            var nPxs = Pixfinder.Util.Canvas.getNeighborPixels(px, imgSize).filter(_notInBlacklist);
            nPxs.forEach(function(p) {
                 pixelsAroundBorderBlacklist[p.x + '-' + p.y] = true;
            });
            result = result.concat(nPxs);
        });

        // ctx1.fillStyle="blue";
        // for (var i = 0; i < result.length; i++) {
        //     ctx1.beginPath();
        //     ctx1.arc(result[i].x, result[i].y, 1, 0, 2 * Math.PI, true);
        //     ctx1.fill();
        //     ctx1.closePath();
        // }

        return result;
    }

    function _insideRegion(px, imgSize, imgCols, options) {
        var colPos = Pixfinder.Util.Canvas.getColorPositionByPixel(px, imgSize),
            pxCol = [imgCols[colPos], imgCols[colPos+1], imgCols[colPos+2], imgCols[colPos+3]];
        return _isColorInColors(
            Pixfinder.Util.Color.areSimilar,
            pxCol,
            options.colors,
            options.tolerance
        );
    }

    // var calls = 0;
    function _getBorderPxsWithOffset(queue, borderPxs, canvas, ctx, imgSize, imgCols, options) {
        // calls++;

        // console.time('_getBorderPxs');
        var borderPxs = borderPxs.concat(_getBorderPxs(queue.pop(), canvas, options));
        // console.timeEnd('_getBorderPxs');

        // console.time('queue.filter');
        queue = queue.filter(function(px) {
            return blacklistHash[px.x + '-' + px.y] !== true;
        });
        // console.timeEnd('queue.filter');

        // console.time('pxsAroundBorder');
        var pxsAroundBorder = _getPixelsAroundBorder(borderPxs, imgSize, options.distance);
        for (var i = 0; i < options.distance; i++) {
            pxsAroundBorder = pxsAroundBorder.concat(_getPixelsAroundBorder(pxsAroundBorder, imgSize));
        }
        // console.timeEnd('pxsAroundBorder');

        // console.time('pxsAroundBorder.filter');
        pxsAroundBorder = pxsAroundBorder.filter(function(px) {
            return _insideRegion(px, imgSize, imgCols, options);
        });
        // console.timeEnd('pxsAroundBorder.filter');

        // ctx1.fillStyle="green";
        // for (var i = 0; i < pxsAroundBorder.length; i++) {
        //     ctx1.beginPath();
        //     ctx1.arc(pxsAroundBorder[i].x, pxsAroundBorder[i].y, 1, 0, 2 * Math.PI, true);
        //     ctx1.fill();
        //     ctx1.closePath();
        // }

        // console.time('queue.concat');
        queue = queue.concat(pxsAroundBorder);
        // console.timeEnd('queue.concat');

        // console.log(queue.length);
        if (queue.length > 0) {
            return _getBorderPxsWithOffset(queue, borderPxs, canvas, ctx, imgSize, imgCols, options);
        }

        return borderPxs;
    }

    ///

    // (Object) -> Object
    function _getCommonDefaults(options) {
        var opt = options;

        opt.accuracy = opt.accuracy || 2;
        opt.distance = opt.distance || 10;
        opt.tolerance = opt.tolerance || 50;
        opt.fill = opt.fill || false;
        opt.colors = opt.colors.map(Pixfinder.Util.Color.toRGB);

        return opt;
    }

    // (HTMLCanvasElement, Array, Number, Number, Boolean) -> Array
    function _getRegionsPixels(canvas, colors, accuracy, tolerance, fill) {
        var res = [],
            ctx = canvas.getContext('2d'),
            imgSize = {
                w: canvas.width,
                h: canvas.height
            },
            imgCols = ctx.getImageData(0, 0, imgSize.w, imgSize.h).data;

        for (var i = 0; i < imgCols.length; i+=(4*accuracy)) { // 4 - rgba
            var pxCol = [imgCols[i], imgCols[i+1], imgCols[i+2], imgCols[i+3]],
                nPxCols = Pixfinder.Util.Canvas.getNeighborPixelsColors(i, imgCols, {
                    w: canvas.width,
                    h: canvas.height
                }),
                px = Pixfinder.Util.Canvas.getPixelByColorPosition(i, imgSize);

            // skip if px is inner pixel of the feature (not fill)
            if (!fill &&
                _areColorsEqualToColor(
                    Pixfinder.Util.Color.areSimilar,
                    nPxCols,
                    pxCol,
                    tolerance) === true) {
                continue;
            }

            // is it pixel of the feature?
            if(_isColorInColors(
                Pixfinder.Util.Color.areSimilar,
                pxCol,
                colors,
                tolerance
            )) {
                res.push(px);
            }
        }

        return res;
    }

    // (Function, Array, Array, Number) -> Boolean
    function _areColorsEqualToColor(checkingFunc, cols, col, tolerance) {
        for (var i = 0; i < cols.length; i++) {
            if (checkingFunc(col, cols[i], tolerance) === false) {
                return false;
            }
        }
        return true;
    }

    // (Function, Array, Array, Number) -> Boolean
    function _isColorInColors(checkingFunc, col, cols, tolerance) {
        for (var i = 0; i < cols.length; i++) {
            if (checkingFunc(col, cols[i], tolerance) === true) {
                return true;
            }
        }
        return false;
    }

    // (Array, Number) -> Array
    function _splitByDist(pixels, dist) {
        var set = disjointSet(),
            res;

        // TODO: O(N^2) should be optimized
        // May be there is reason to rethink algorithm and use
        // Shared Nearest Neighbor Clustering instead of _splitByDist?
        for (var i = 0; i < pixels.length; i++) {
            set.add(pixels[i]);
            for (var j = i; j >= 0; j--) {
                if (Pixfinder.Util.Math.getDistance(pixels[i], pixels[j]) <= dist) {
                    if (!set.connected(pixels[i], pixels[j])) {
                        set.union(pixels[i], pixels[j]);
                    }
                }
            }
        }

        res = set.extract();

        set.destroy();
        return res;
    }

    // (Array, Number) -> Array
    function _clearNoise(objects, noise) {
        return objects.filter(function(el) {
            return el.length >= noise;
        });
    }

})();<commit_msg>write some minds about better algo<commit_after>(function() { 'use strict';

    window.Pixfinder = {

        getObject: function(options) {
            var opt = _getCommonDefaults(options),
                canv = Pixfinder.Util.Canvas.wrapImgByCanvas(opt.img),
                ctx = canv.getContext('2d'),
                imgSize = { w: canv.width, h: canv.height },
                imgCols = ctx.getImageData(0, 0, imgSize.w, imgSize.h).data,
                colPos = Pixfinder.Util.Canvas.getColorPositionByPixel(opt.startPixel, imgSize),
                pxCol = [imgCols[colPos], imgCols[colPos+1], imgCols[colPos+2], imgCols[colPos+3]],
                isStartPxInObject = false,
                borderPxs = [];

            isStartPxInObject = _isColorInColors(
                Pixfinder.Util.Color.areSimilar,
                pxCol,
                opt.colors,
                opt.tolerance
            );
            if (!isStartPxInObject) { return []; }

            borderPxs = _getBorderPxsWithOffset([opt.startPixel], borderPxs, canv, ctx, imgSize, imgCols, opt);

            borderPxs = borderPxs.map(function(px) {
                return [px.x, px.y];
            });
            borderPxs = hull(borderPxs, 5);
            borderPxs = borderPxs.map(function(px) {
                return {x: px[0], y: px[1]};
            });

            return borderPxs;
        },

        getObjects: function(options) {
            var canv,
                objects,
                regionsPxs,
                opt = _getCommonDefaults(options);

            opt.clearNoise = opt.clearNoise || false;

            canv = Pixfinder.Util.Canvas.wrapImgByCanvas(opt.img);

            regionsPxs = _getRegionsPixels(
                canv,
                opt.colors,
                opt.accuracy,
                opt.tolerance,
                opt.fill
            );

            objects = _splitByDist(regionsPxs, opt.distance);

            objects = objects.map(function(object) {
                return poly2cw(object, 'tsp');
            });

            objects = opt.clearNoise ?
                _clearNoise(objects, opt.clearNoise) : objects;

            return objects;
        }
    };

    var blacklist = [],
        blacklistHash = {};
    function _getBorderPxs(px, canvas, options) { // (Pixel, HTMLCanvasElement, Object) -> Object
        var result = [];

        bfs(canvas, px, {
            onvisit: function(e) {
                blacklist.push(e.pixel.coord);
                blacklistHash[e.pixel.coord.x + '-' + e.pixel.coord.y] = true;
                if (!_isColorInColors(
                    Pixfinder.Util.Color.areSimilar,
                    e.pixel.color,
                    options.colors,
                    options.tolerance
                )) {
                    result.push(e.pixel.coord);
                    e.skip();
                }
            }
        }, blacklist);

        // ctx1.fillStyle="red";
        // for (var i = 0; i < result.length; i++) {
        //     ctx1.beginPath();
        //     ctx1.arc(result[i].x, result[i].y, 1, 0, 2 * Math.PI, true);
        //     ctx1.fill();
        //     ctx1.closePath();
        // }

        return result;
    }

    var pixelsAroundBorderBlacklist = {};
    function _getPixelsAroundBorder(borderPxs, imgSize) {
        var result = [];

        Pixfinder.Util.Obj.extend(pixelsAroundBorderBlacklist, blacklistHash);
        function _notInBlacklist(px) {
            return pixelsAroundBorderBlacklist[px.x + '-' + px.y] !== true;
        }

        borderPxs.forEach(function(px) {
            var nPxs = Pixfinder.Util.Canvas.getNeighborPixels(px, imgSize).filter(_notInBlacklist);
            nPxs.forEach(function(p) {
                 pixelsAroundBorderBlacklist[p.x + '-' + p.y] = true;
            });
            result = result.concat(nPxs);
        });

        // ctx1.fillStyle="blue";
        // for (var i = 0; i < result.length; i++) {
        //     ctx1.beginPath();
        //     ctx1.arc(result[i].x, result[i].y, 1, 0, 2 * Math.PI, true);
        //     ctx1.fill();
        //     ctx1.closePath();
        // }

        return result;
    }

    function _insideRegion(px, imgSize, imgCols, options) {
        var colPos = Pixfinder.Util.Canvas.getColorPositionByPixel(px, imgSize),
            pxCol = [imgCols[colPos], imgCols[colPos+1], imgCols[colPos+2], imgCols[colPos+3]];
        return _isColorInColors(
            Pixfinder.Util.Color.areSimilar,
            pxCol,
            options.colors,
            options.tolerance
        );
    }

    // var calls = 0;
    function _getBorderPxsWithOffset(queue, borderPxs, canvas, ctx, imgSize, imgCols, options) {
        // calls++;

        // console.time('_getBorderPxs');
        var borderPxs = borderPxs.concat(_getBorderPxs(queue.pop(), canvas, options));
        // console.timeEnd('_getBorderPxs');

        // console.time('queue.filter');
        queue = queue.filter(function(px) {
            return blacklistHash[px.x + '-' + px.y] !== true;
        });
        // console.timeEnd('queue.filter');

        // console.time('pxsAroundBorder');
        var pxsAroundBorder = _getPixelsAroundBorder(borderPxs, imgSize, options.distance);
        for (var i = 0; i < options.distance; i++) {
            pxsAroundBorder = pxsAroundBorder.concat(_getPixelsAroundBorder(pxsAroundBorder, imgSize));
        }
        // console.timeEnd('pxsAroundBorder');

        // console.time('pxsAroundBorder.filter');
        pxsAroundBorder = pxsAroundBorder.filter(function(px) {
            return _insideRegion(px, imgSize, imgCols, options);
        });
        // console.timeEnd('pxsAroundBorder.filter');

        // ctx1.fillStyle="green";
        // for (var i = 0; i < pxsAroundBorder.length; i++) {
        //     ctx1.beginPath();
        //     ctx1.arc(pxsAroundBorder[i].x, pxsAroundBorder[i].y, 1, 0, 2 * Math.PI, true);
        //     ctx1.fill();
        //     ctx1.closePath();
        // }

        // console.time('queue.concat');
        queue = queue.concat(pxsAroundBorder);
        // console.timeEnd('queue.concat');

        // console.log(queue.length);
        if (queue.length > 0) {
            return _getBorderPxsWithOffset(queue, borderPxs, canvas, ctx, imgSize, imgCols, options);
        }

        return borderPxs;
    }

    ///

    // (Object) -> Object
    function _getCommonDefaults(options) {
        var opt = options;

        opt.accuracy = opt.accuracy || 2;
        opt.distance = opt.distance || 10;
        opt.tolerance = opt.tolerance || 50;
        opt.fill = opt.fill || false;
        opt.colors = opt.colors.map(Pixfinder.Util.Color.toRGB);

        return opt;
    }

    // (HTMLCanvasElement, Array, Number, Number, Boolean) -> Array
    function _getRegionsPixels(canvas, colors, accuracy, tolerance, fill) {
        var res = [],
            ctx = canvas.getContext('2d'),
            imgSize = {
                w: canvas.width,
                h: canvas.height
            },
            imgCols = ctx.getImageData(0, 0, imgSize.w, imgSize.h).data;

        for (var i = 0; i < imgCols.length; i+=(4*accuracy)) { // 4 - rgba
            var pxCol = [imgCols[i], imgCols[i+1], imgCols[i+2], imgCols[i+3]],
                nPxCols = Pixfinder.Util.Canvas.getNeighborPixelsColors(i, imgCols, {
                    w: canvas.width,
                    h: canvas.height
                }),
                px = Pixfinder.Util.Canvas.getPixelByColorPosition(i, imgSize);

            // skip if px is inner pixel of the feature (not fill)
            if (!fill &&
                _areColorsEqualToColor(
                    Pixfinder.Util.Color.areSimilar,
                    nPxCols,
                    pxCol,
                    tolerance) === true) {
                continue;
            }

            // is it pixel of the feature?
            if(_isColorInColors(
                Pixfinder.Util.Color.areSimilar,
                pxCol,
                colors,
                tolerance
            )) {
                res.push(px);
            }
        }

        return res;
    }

    // (Function, Array, Array, Number) -> Boolean
    function _areColorsEqualToColor(checkingFunc, cols, col, tolerance) {
        for (var i = 0; i < cols.length; i++) {
            if (checkingFunc(col, cols[i], tolerance) === false) {
                return false;
            }
        }
        return true;
    }

    // (Function, Array, Array, Number) -> Boolean
    function _isColorInColors(checkingFunc, col, cols, tolerance) {
        for (var i = 0; i < cols.length; i++) {
            if (checkingFunc(col, cols[i], tolerance) === true) {
                return true;
            }
        }
        return false;
    }

    // (Array, Number) -> Array
    function _splitByDist(pixels, dist) {
        var set = disjointSet(),
            res;

        // TODO: O(N^2) should be optimized
        // May be there is reason to rethink algorithm and use
        // Shared Nearest Neighbor Clustering instead of _splitByDist?
        for (var i = 0; i < pixels.length; i++) {
            set.add(pixels[i]);
            for (var j = i; j >= 0; j--) {
                if (Pixfinder.Util.Math.getDistance(pixels[i], pixels[j]) <= dist) {
                    if (!set.connected(pixels[i], pixels[j])) {
                        set.union(pixels[i], pixels[j]);
                    }
                }
            }
        }

        res = set.extract();

        set.destroy();
        return res;
    }

    // (Array, Number) -> Array
    function _clearNoise(objects, noise) {
        return objects.filter(function(el) {
            return el.length >= noise;
        });
    }

})();

/*
 1. запускаем bfs
 2. if (пиксель в объекте){
        добавляем его пространственное дерево
    } else {
        ищем в дереве в радиусе dist ближайшего соседа, который в объекте
        if (соседа нет) {
            e.skip();
        }
    }
*/<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import createResource from './createResource';

/**
 * Author object.
 *
 * @typedef {Object} Author Media3p media author.
 * @property {string} url The url for the asset.
 * @property {?string} imageName A name to identify this particular image url.
 * Currently not being used.
 * @property {number} width The width of this asset.
 * @property {number} height The height of this asset.
 */

/**
 * ImageUrl object.
 *
 * @typedef {Object} ImageUrl image url object.
 * @property {string} displayName The display name of the author of the media.
 * @property {?string} url A url to link to for the media author.
 */

/**
 * Media3pMedia object.
 *
 * @typedef {Object} Media3pMedia Media3p media object.
 * @property {string} name The name of the media object. Format is
 * 'media/{provider}:{id}.
 * @property {string} provider The provider, currently only 'UNSPLASH'.
 * @property {string} type The type of media, currently only 'IMAGE'.
 * @property {Author} author The metadata about the author of the media object.
 * @property {?string} title The displayable title of the media item.
 * @property {?string} description A description of the media item.
 * @property {string} createTime The creation time of the media element.
 * @property {string} updateTime The last update time of the media element.
 * @property {string} registerUsageUrl The URL to call when the media element
 * is added to a story.
 * @property {ImageUrl[]|undefined} imageUrls If the media element is an
 * image, an array of urls with different size assets.
 */

/**
 * Converts the image or video urls in a Media3P Media object to the "sizes"
 * object required for a Resource.
 *
 * @param {Media3pMedia} m The Media3P Media object.
 * @return {Object} The array of "sizes"-type objects.
 */
function getUrls(m) {
  if (m.type.toLowerCase() === 'image') {
    return Object.fromEntries(
      new Map(
        m.imageUrls.map((u) => [
          u.imageName,
          {
            file: m.name,
            source_url: u.url,
            mime_type: u.mimeType,
            width: u.width,
            height: u.height,
          },
        ])
      )
    );
  }
  throw new Error('Invalid media type.');
}

/**
 * Returns the ImageUrl object for the largest image (the full asset).
 *
 * @param {Media3pMedia} m The Media3P Media object.
 * @return {*} An ImageUrl object.
 */
function getFullAsset(m) {
  if (m.type.toLowerCase() === 'image') {
    if (!m.imageUrls.length) {
      throw new Error('No imageUrls for media resource: ' + m);
    }
    // Reverse sort and get the largest width to determine the full asset.
    return m.imageUrls.sort((el1, el2) => el2.width - el1.width)[0];
  }
  throw new Error('Invalid media type for media resource: ' + m);
}

/**
 * Generates a resource object from a Media3P object from the API.
 *
 * @param {Media3pMedia} m A Media3P Media object.
 * @return {import('./createResource.js').Resource} Resource object.
 */
function getResourceFromMedia3p(m) {
  const urls = getUrls(m);
  const fullAsset = getFullAsset(m);
  return createResource({
    type: m.type.toLowerCase(),
    mimeType: urls.full.mime_type,
    creationDate: m.createTime,
    src: fullAsset.url,
    width: fullAsset.width,
    height: fullAsset.height,
    poster: null, // TODO: Implement for videos.
    posterId: null, // TODO: Implement for videos.
    id: m.name,
    length: null, // TODO: Implement for videos.
    lengthFormatted: null, // TODO: Implement for videos.
    title: m.description,
    alt: null,
    local: false, // TODO: How does this interact with the rest?
    sizes: urls, // TODO: Map with expected keys for canvas.
    attribution: m.author && {
      author: {
        displayName: m.author.displayName,
        url: m.author.url,
      },
    },
  });
}

export default getResourceFromMedia3p;
<commit_msg>Update getResourceFromMedia3p.js<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import createResource from './createResource';

/**
 * Author object.
 *
 * @typedef {Object} Author Media3p media author.
 * @property {string} url The url for the asset.
 * @property {?string} imageName A name to identify this particular image url.
 * Currently not being used.
 * @property {number} width The width of this asset.
 * @property {number} height The height of this asset.
 */

/**
 * ImageUrl object.
 *
 * @typedef {Object} ImageUrl image url object.
 * @property {string} displayName The display name of the author of the media.
 * @property {?string} url A url to link to for the media author.
 */

/**
 * Media3pMedia object.
 *
 * @typedef {Object} Media3pMedia Media3p media object.
 * @property {string} name The name of the media object. Format is
 * 'media/{provider}:{id}.
 * @property {string} provider The provider, currently only 'UNSPLASH'.
 * @property {string} type The type of media, currently only 'IMAGE'.
 * @property {Author} author The metadata about the author of the media object.
 * @property {?string} title The displayable title of the media item.
 * @property {?string} description A description of the media item.
 * @property {string} createTime The creation time of the media element.
 * @property {string} updateTime The last update time of the media element.
 * @property {string} registerUsageUrl The URL to call when the media element
 * is added to a story.
 * @property {ImageUrl[]|undefined} imageUrls If the media element is an
 * image, an array of urls with different size assets.
 */

/**
 * Converts the image or video urls in a Media3P Media object to the "sizes"
 * object required for a Resource.
 *
 * @param {Media3pMedia} m The Media3P Media object.
 * @return {Object} The array of "sizes"-type objects.
 */
function getUrls(m) {
  if (m.type.toLowerCase() === 'image') {
    // The rest of the application expects 3 named "sizes": "full", "large" and
    // "web_stories_thumbnail". We use the biggest as "full", the next biggest
    // as "large", and the smallest as "web_stories_thumbnail". The rest are
    // named according to their size.
    const sizesFromBiggest = m.imageUrls
      .sort((el1, el2) => el2.width - el1.width)
      .map((u) => {
        return {
          file: m.name,
          source_url: u.url,
          mime_type: u.mimeType,
          width: u.width,
          height: u.height,
        };
      });
    const namedSizes = [
      ['full', sizesFromBiggest[0]],
      ['large', sizesFromBiggest[1]],
      ...sizesFromBiggest
        .slice(2, sizesFromBiggest.length - 1)
        .map((u) => [u.width + '_' + u.height, u]),
      ['web_stories_thumbnail', sizesFromBiggest[sizesFromBiggest.length - 1]],
    ];
    return Object.fromEntries(new Map(namedSizes));
  }
  throw new Error('Invalid media type.');
}

/**
 * Generates a resource object from a Media3P object from the API.
 *
 * @param {Media3pMedia} m A Media3P Media object.
 * @return {import('./createResource.js').Resource} Resource object.
 */
function getResourceFromMedia3p(m) {
  const urls = getUrls(m);
  return createResource({
    type: m.type.toLowerCase(),
    mimeType: urls.full.mime_type,
    creationDate: m.createTime,
    src: urls.full.source_url,
    width: urls.full.width,
    height: urls.full.height,
    poster: null, // TODO: Implement for videos.
    posterId: null, // TODO: Implement for videos.
    id: m.name,
    length: null, // TODO: Implement for videos.
    lengthFormatted: null, // TODO: Implement for videos.
    title: m.description,
    alt: null,
    local: false, // TODO: How does this interact with the rest?
    sizes: urls, // TODO: Map with expected keys for canvas.
    attribution: m.author && {
      author: {
        displayName: m.author.displayName,
        url: m.author.url,
      },
    },
  });
}

export default getResourceFromMedia3p;
<|endoftext|>


<commit_before>import { PropTypes } from 'react';

export const lineInterpolation = PropTypes.oneOf([
    'linear',          // piecewise linear segments, as in a polyline.
    'linear-closed',   // close the linear segments to form a polygon.
    'step',            // alternate between horizontal and vertical segments, as in a step function.
    'step-before',     // alternate between vertical and horizontal segments, as in a step function.
    'step-after',      // alternate between horizontal and vertical segments, as in a step function.
    'basis',           // a B-spline, with control point duplication on the ends.
    'basis-open',      // an open B-spline; may not intersect the start or end.
    'basis-closed',    // a closed B-spline, as in a loop.
    'bundle',          // equivalent to basis, except the tension parameter is used to straighten the spline.
    'cardinal',        // a Cardinal spline, with control point duplication on the ends.
    'cardinal-open',   // an open Cardinal spline; may not intersect the start or end, but will intersect other control points.
    'cardinal-closed', // a closed Cardinal spline, as in a loop.
    'monotone'         // cubic interpolation that preserves monotonicity in y.
]);
<commit_msg>chore(propTypes): add custom margin propType<commit_after>import { PropTypes } from 'react';

export const lineInterpolation = PropTypes.oneOf([
    'linear',          // piecewise linear segments, as in a polyline.
    'linear-closed',   // close the linear segments to form a polygon.
    'step',            // alternate between horizontal and vertical segments, as in a step function.
    'step-before',     // alternate between vertical and horizontal segments, as in a step function.
    'step-after',      // alternate between horizontal and vertical segments, as in a step function.
    'basis',           // a B-spline, with control point duplication on the ends.
    'basis-open',      // an open B-spline; may not intersect the start or end.
    'basis-closed',    // a closed B-spline, as in a loop.
    'bundle',          // equivalent to basis, except the tension parameter is used to straighten the spline.
    'cardinal',        // a Cardinal spline, with control point duplication on the ends.
    'cardinal-open',   // an open Cardinal spline; may not intersect the start or end, but will intersect other control points.
    'cardinal-closed', // a closed Cardinal spline, as in a loop.
    'monotone'         // cubic interpolation that preserves monotonicity in y.
]);

export const margin = PropTypes.shape({
    top:    PropTypes.number,
    right:  PropTypes.number,
    bottom: PropTypes.number,
    left:   PropTypes.number
}).isRequired;
<|endoftext|>


<commit_before>/*
 * Copyright © 2015 Cask Data, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

angular.module(PKG.name + '.feature.hydrator')
  .controller('HydratorDetailCanvasController', function(rPipelineDetail, BottomPanelStore, NodesActionsFactory, HydratorService, NodesStore, ConfigStore, PipelineNodeConfigActionFactory, DetailNonRunsStore, MetricsStore) {
    this.ConfigStore = ConfigStore;
    this.NodesStore = NodesStore;
    this.DetailNonRunsStore = DetailNonRunsStore;
    this.PipelineNodeConfigActionFactory = PipelineNodeConfigActionFactory;
    this.HydratorService = HydratorService;
    this.MetricsStore = MetricsStore;

    try{
      rPipelineDetail.config = JSON.parse(rPipelineDetail.configuration);
    } catch(e) {
      console.log('ERROR in configuration from backend: ', e);
      return;
    }
    this.setState = function() {
      this.setScroll = (BottomPanelStore.getPanelState() === 0 ? false: true);
    };
    this.setState();
    BottomPanelStore.registerOnChangeListener(this.setState.bind(this));
    var obj = DetailNonRunsStore.getDAGConfig();
    NodesActionsFactory.createGraphFromConfig(obj.nodes, obj.connections);

    this.updateNodesAndConnections = function () {
      var activeNode = this.NodesStore.getActiveNodeId();
      if (!activeNode) {
        this.deleteNode();
      } else {
        this.setActiveNode();
      }
    };

    this.setActiveNode = function() {
      var nodeId = this.NodesStore.getActiveNodeId();
      if (!nodeId) {
        return;
      }
      this.PipelineNodeConfigActionFactory.choosePlugin(this.DetailNonRunsStore.getPluginObject(nodeId));
    };

    this.deleteNode = function() {
      this.PipelineNodeConfigActionFactory.removePlugin();
    };

    this.generateSchemaOnEdge = function (sourceId) {
      return this.HydratorService.generateSchemaOnEdge(sourceId);
    };

    function convertMetricsArrayIntoObject(arr, nodes) {
      var obj = {};

      angular.forEach(arr, function (item) {
        obj[nodes.name] = {
          recordsOut: item.recordsOut,
          recordsIn: item.recordsIn
        };
      });

      return obj;
    }
    var nodes = this.NodesStore.getNodes();
    this.metrics = convertMetricsArrayIntoObject(this.MetricsStore.getMetrics(), nodes);

    this.MetricsStore.registerOnChangeListener(function () {
      this.metrics = convertMetricsArrayIntoObject(this.MetricsStore.getMetrics(), nodes);
    }.bind(this));

    NodesStore.registerOnChangeListener(this.updateNodesAndConnections.bind(this));
  });
<commit_msg>fix metrics on label and popover<commit_after>/*
 * Copyright © 2015 Cask Data, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

angular.module(PKG.name + '.feature.hydrator')
  .controller('HydratorDetailCanvasController', function(rPipelineDetail, BottomPanelStore, NodesActionsFactory, HydratorService, NodesStore, ConfigStore, PipelineNodeConfigActionFactory, DetailNonRunsStore, MetricsStore) {
    this.ConfigStore = ConfigStore;
    this.NodesStore = NodesStore;
    this.DetailNonRunsStore = DetailNonRunsStore;
    this.PipelineNodeConfigActionFactory = PipelineNodeConfigActionFactory;
    this.HydratorService = HydratorService;
    this.MetricsStore = MetricsStore;

    try{
      rPipelineDetail.config = JSON.parse(rPipelineDetail.configuration);
    } catch(e) {
      console.log('ERROR in configuration from backend: ', e);
      return;
    }
    this.setState = function() {
      this.setScroll = (BottomPanelStore.getPanelState() === 0 ? false: true);
    };
    this.setState();
    BottomPanelStore.registerOnChangeListener(this.setState.bind(this));
    var obj = DetailNonRunsStore.getDAGConfig();
    NodesActionsFactory.createGraphFromConfig(obj.nodes, obj.connections);

    this.updateNodesAndConnections = function () {
      var activeNode = this.NodesStore.getActiveNodeId();
      if (!activeNode) {
        this.deleteNode();
      } else {
        this.setActiveNode();
      }
    };

    this.setActiveNode = function() {
      var nodeId = this.NodesStore.getActiveNodeId();
      if (!nodeId) {
        return;
      }
      this.PipelineNodeConfigActionFactory.choosePlugin(this.DetailNonRunsStore.getPluginObject(nodeId));
    };

    this.deleteNode = function() {
      this.PipelineNodeConfigActionFactory.removePlugin();
    };

    this.generateSchemaOnEdge = function (sourceId) {
      return this.HydratorService.generateSchemaOnEdge(sourceId);
    };

    function convertMetricsArrayIntoObject(arr) {
      var obj = {};

      angular.forEach(arr, function (item) {
        obj[item.nodeName] = {
          recordsOut: item.recordsOut,
          recordsIn: item.recordsIn
        };
      });

      return obj;
    }
    this.metrics = convertMetricsArrayIntoObject(this.MetricsStore.getMetrics());

    this.MetricsStore.registerOnChangeListener(function () {
      this.metrics = convertMetricsArrayIntoObject(this.MetricsStore.getMetrics());
    }.bind(this));

    NodesStore.registerOnChangeListener(this.updateNodesAndConnections.bind(this));
  });
<|endoftext|>


<commit_before>(function($){

var getUrl = function(object){
  if (!(object && object.url)) return null;
  return $.isFunction(object.url) ? object.url() : object.url;
};

var methodMap = {
  "create":  "POST",
  "update":  "PUT",
  "destroy": "DELETE",
  "read":    "GET"
};

var urlError = function() {
  throw new Error("A 'url' property or function must be specified");
};

var ajaxSync = function(method, record){

  var params = {
    type:          methodMap[method],
    contentType:  "application/json",
    dataType:     "json",
    processData:  false
  };

  if (Spine.Model._noSync) return;

  params.url = getUrl(record);
  if (!params.url) throw("Invalid URL");

  if (method == "create" || method == "update")
    params.data = JSON.stringify(record);

  if (method == "read")
    params.success = function(data){
      (record.populate || record.load)(data);
    };

  params.error = function(e){
    record.trigger("error", e);
  };

  $.ajax(params);
};

Spine.Model.Ajax = {
  extended: function(){
    this.sync(ajaxSync);
    this.fetch(this.proxy(function(){
      ajaxSync("read", this);
    }));
  }
};

Spine.Model.extend({
  url: function() {
    return "/" + this.name.toLowerCase() + "s"
  },

  noSync: function(callback){
    Spine.Model._noSync = true;
    callback.apply(callback, arguments);
    Spine.Model._noSync = false;
  }
});

Spine.Model.include({
  url: function(){
    var base = getUrl(this.parent);
    base += (base.charAt(base.length - 1) == "/" ? "" : "/");
    base += encodeURIComponent(this.id);
    return base;
  }
});

})(jQuery);<commit_msg>function is refresh not populate<commit_after>(function($){

var getUrl = function(object){
  if (!(object && object.url)) return null;
  return $.isFunction(object.url) ? object.url() : object.url;
};

var methodMap = {
  "create":  "POST",
  "update":  "PUT",
  "destroy": "DELETE",
  "read":    "GET"
};

var urlError = function() {
  throw new Error("A 'url' property or function must be specified");
};

var ajaxSync = function(method, record){

  var params = {
    type:          methodMap[method],
    contentType:  "application/json",
    dataType:     "json",
    processData:  false
  };

  if (Spine.Model._noSync) return;

  params.url = getUrl(record);
  if (!params.url) throw("Invalid URL");

  if (method == "create" || method == "update")
    params.data = JSON.stringify(record);

  if (method == "read")
    params.success = function(data){
      (record.refresh || record.load).call(record, data);
    };

  params.error = function(e){
    record.trigger("error", e);
  };

  $.ajax(params);
};

Spine.Model.Ajax = {
  extended: function(){
    this.sync(ajaxSync);
    this.fetch(this.proxy(function(){
      ajaxSync("read", this);
    }));
  }
};

Spine.Model.extend({
  url: function() {
    return "/" + this.name.toLowerCase() + "s"
  },

  noSync: function(callback){
    Spine.Model._noSync = true;
    callback.apply(callback, arguments);
    Spine.Model._noSync = false;
  }
});

Spine.Model.include({
  url: function(){
    var base = getUrl(this.parent);
    base += (base.charAt(base.length - 1) == "/" ? "" : "/");
    base += encodeURIComponent(this.id);
    return base;
  }
});

})(jQuery);<|endoftext|>