<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2015, Joyent, Inc.
 */

/*
 * The 'sdcadm experimental cns' CLI subcommand.
 */

var util = require('util'),
    format = util.format;
var vasync = require('vasync');

var common = require('../common');
var errors = require('../errors');
var DownloadImages = require('../procedures/download-images').DownloadImages;
var shared = require('../procedures/shared');
var steps = require('../steps');

function do_cns(subcmd, opts, args, cb) {
    var self = this;
    if (opts.help) {
        this.do_help('help', {}, [subcmd], cb);
        return;
    } else if (args.length > 0) {
        return cb(new errors.UsageError('too many args: ' + args));
    }

    var start = Date.now();
    var svcData = {
        name: 'cns',
        params: {
            package_name: 'sdc_1024',
            billing_id: 'TO_FILL_IN', // filled in from 'package_name'
            image_uuid: 'TO_FILL_IN',
            archive_on_delete: true,
            delegate_dataset: true,
            maintain_resolvers: true,
            networks: [
                {name: 'admin'}
            ],
            firewall_enabled: false,
            tags: {
                smartdc_role: 'cns',
                smartdc_type: 'core'
            }
        },
        metadata: {
            SERVICE_NAME: 'cns',
            SERVICE_DOMAIN: 'TO_FILL_IN',
            'user-script': 'TO_FILL_IN'
        }
    };

    var context = {
        imgsToDownload: []
    };
    vasync.pipeline({arg: context, funcs: [
        /* @field ctx.cnsPkg */
        function getPkg(ctx, next) {
            var filter = {name: svcData.params.package_name,
                active: true};
            self.sdcadm.papi.list(filter, {}, function (err, pkgs) {
                if (err) {
                    return next(err);
                } else if (pkgs.length !== 1) {
                    return next(new errors.InternalError({
                        message: format('%d "%s" packages found', pkgs.length,
                            svcData.params.package_name)
                    }));
                }
                ctx.cnsPkg = pkgs[0];
                next();
            });
        },

        function ensureSapiMode(_, next) {
            // Bail if SAPI not in 'full' mode.
            self.sdcadm.sapi.getMode(function (err, mode) {
                if (err) {
                    next(new errors.SDCClientError(err, 'sapi'));
                } else if (mode !== 'full') {
                    next(new errors.UpdateError(format(
                        'SAPI is not in "full" mode: mode=%s', mode)));
                } else {
                    next();
                }
            });
        },

        function getSvc(ctx, next) {
            self.sdcadm.sapi.listServices({
                name: 'cns',
                application_uuid: self.sdcadm.sdc.uuid
            }, function (svcErr, svcs) {
                if (svcErr) {
                    return next(svcErr);
                } else if (svcs.length) {
                    ctx.cnsSvc = svcs[0];
                }
                next();
            });
        },

        /*
         * @field ctx.cnsInst
         * @field ctx.cnsVm
         */
        function getCnsInst(ctx, next) {
            if (!ctx.cnsSvc) {
                return next();
            }
            var filter = {
                service_uuid: ctx.cnsSvc.uuid
            };
            self.sdcadm.sapi.listInstances(filter, function (err, insts) {
                if (err) {
                    return next(new errors.SDCClientError(err, 'sapi'));
                } else if (insts && insts.length) {
                    // Note this doesn't handle multiple insts.
                    ctx.cnsInst = insts[0];
                    self.sdcadm.vmapi.getVm({uuid: ctx.cnsInst.uuid},
                            function (vmErr, cnsVm) {
                        if (vmErr) {
                            return next(vmErr);
                        }
                        ctx.cnsVm = cnsVm;
                        next();
                    });
                } else {
                    next();
                }
            });
        },

        function getLatestCnsImage(ctx, next) {
            var filter = {name: 'cns'};
            self.sdcadm.updates.listImages(filter, function (err, images) {
                if (err) {
                    next(err);
                } else if (images && images.length) {
                    // TODO presuming sorted
                    ctx.cnsImg = images[images.length - 1];
                    next();
                } else {
                    next(new errors.UpdateError('no "cns" image found'));
                }
            });
        },

        function haveCnsImageAlready(ctx, next) {
            self.sdcadm.imgapi.getImage(ctx.cnsImg.uuid,
                    function (err, img_) {
                if (err && err.body && err.body.code === 'ResourceNotFound') {
                    ctx.imgsToDownload.push(ctx.cnsImg);
                } else if (err) {
                    return next(err);
                }
                next();
            });
        },

        function importImages(ctx, next) {
            if (ctx.imgsToDownload.length === 0) {
                return next();
            }
            var proc = new DownloadImages({images: ctx.imgsToDownload});
            proc.execute({
                sdcadm: self.sdcadm,
                log: self.log,
                progress: self.progress
            }, next);
        },

        /* @field ctx.userString */
        shared.getUserScript,

        function createCnsSvc(ctx, next) {
            if (ctx.cnsSvc) {
                return next();
            }

            var domain = self.sdcadm.sdc.metadata.datacenter_name + '.' +
                    self.sdcadm.sdc.metadata.dns_domain;
            var svcDomain = svcData.name + '.' + domain;

            self.progress('Creating "cns" service');
            svcData.params.image_uuid = ctx.cnsImg.uuid;
            svcData.metadata['user-script'] = ctx.userScript;
            svcData.metadata['SERVICE_DOMAIN'] = svcDomain;
            svcData.params.billing_id = ctx.cnsPkg.uuid;
            delete svcData.params.package_name;

            self.sdcadm.sapi.createService('cns', self.sdcadm.sdc.uuid,
                    svcData, function (err, svc) {
                if (err) {
                    return next(new errors.SDCClientError(err, 'sapi'));
                }
                ctx.cnsSvc = svc;
                self.log.info({svc: svc}, 'created cns svc');
                next();
            });
        },

        /* @field ctx.headnode */
        function getHeadnode(ctx, next) {
            self.sdcadm.cnapi.listServers({
                headnode: true
            }, function (err, servers) {
                if (err) {
                    return next(new errors.SDCClientError(err, 'cnapi'));
                }
                ctx.headnode = servers[0];
                return next();
            });
        },
        function createCnsInst(ctx, next) {
            if (ctx.cnsInst) {
                return next();
            }
            self.progress('Creating "cns" instance');
            var instOpts = {
                params: {
                    alias: 'cns0',
                    server_uuid: ctx.headnode.uuid
                }
            };
            self.sdcadm.sapi.createInstance(ctx.cnsSvc.uuid, instOpts,
                    function (err, inst) {
                if (err) {
                    return next(new errors.SDCClientError(err, 'sapi'));
                }
                self.progress('Created VM %s (%s)', inst.uuid,
                    inst.params.alias);
                ctx.newCnsInst = inst;
                next();
            });
        },

        function done(_, next) {
            self.progress('Added "cns" service and instance (%ds)',
                Math.floor((Date.now() - start) / 1000));
            next();
        }
    ]}, cb);
}

do_cns.options = [
    {
        names: ['help', 'h'],
        type: 'bool',
        help: 'Show this help.'
    }
];
do_cns.help = (
    'Create the "cns" service and a first instance.\n' +
    '\n' +
    'Usage:\n' +
    '     {{name}} cns\n' +
    '\n' +
    '{{options}}'
);

// --- exports

module.exports = {
    do_cns: do_cns
};
<commit_msg>TOOLS-1295: would be nice if 'sdcadm experimental cns' said nothing if it does nothing<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2015, Joyent, Inc.
 */

/*
 * The 'sdcadm experimental cns' CLI subcommand.
 */

var util = require('util'),
    format = util.format;
var vasync = require('vasync');

var common = require('../common');
var errors = require('../errors');
var DownloadImages = require('../procedures/download-images').DownloadImages;
var shared = require('../procedures/shared');
var steps = require('../steps');

function do_cns(subcmd, opts, args, cb) {
    var self = this;
    if (opts.help) {
        this.do_help('help', {}, [subcmd], cb);
        return;
    } else if (args.length > 0) {
        return cb(new errors.UsageError('too many args: ' + args));
    }

    var start = Date.now();
    var svcData = {
        name: 'cns',
        params: {
            package_name: 'sdc_1024',
            billing_id: 'TO_FILL_IN', // filled in from 'package_name'
            image_uuid: 'TO_FILL_IN',
            archive_on_delete: true,
            delegate_dataset: true,
            maintain_resolvers: true,
            networks: [
                {name: 'admin'}
            ],
            firewall_enabled: false,
            tags: {
                smartdc_role: 'cns',
                smartdc_type: 'core'
            }
        },
        metadata: {
            SERVICE_NAME: 'cns',
            SERVICE_DOMAIN: 'TO_FILL_IN',
            'user-script': 'TO_FILL_IN'
        }
    };

    var context = {
        imgsToDownload: [],
        didSomething: false
    };
    vasync.pipeline({arg: context, funcs: [
        /* @field ctx.cnsPkg */
        function getPkg(ctx, next) {
            var filter = {name: svcData.params.package_name,
                active: true};
            self.sdcadm.papi.list(filter, {}, function (err, pkgs) {
                if (err) {
                    return next(err);
                } else if (pkgs.length !== 1) {
                    return next(new errors.InternalError({
                        message: format('%d "%s" packages found', pkgs.length,
                            svcData.params.package_name)
                    }));
                }
                ctx.cnsPkg = pkgs[0];
                next();
            });
        },

        function ensureSapiMode(_, next) {
            // Bail if SAPI not in 'full' mode.
            self.sdcadm.sapi.getMode(function (err, mode) {
                if (err) {
                    next(new errors.SDCClientError(err, 'sapi'));
                } else if (mode !== 'full') {
                    next(new errors.UpdateError(format(
                        'SAPI is not in "full" mode: mode=%s', mode)));
                } else {
                    next();
                }
            });
        },

        function getSvc(ctx, next) {
            self.sdcadm.sapi.listServices({
                name: 'cns',
                application_uuid: self.sdcadm.sdc.uuid
            }, function (svcErr, svcs) {
                if (svcErr) {
                    return next(svcErr);
                } else if (svcs.length) {
                    ctx.cnsSvc = svcs[0];
                }
                next();
            });
        },

        /*
         * @field ctx.cnsInst
         * @field ctx.cnsVm
         */
        function getCnsInst(ctx, next) {
            if (!ctx.cnsSvc) {
                return next();
            }
            var filter = {
                service_uuid: ctx.cnsSvc.uuid
            };
            self.sdcadm.sapi.listInstances(filter, function (err, insts) {
                if (err) {
                    return next(new errors.SDCClientError(err, 'sapi'));
                } else if (insts && insts.length) {
                    // Note this doesn't handle multiple insts.
                    ctx.cnsInst = insts[0];
                    self.sdcadm.vmapi.getVm({uuid: ctx.cnsInst.uuid},
                            function (vmErr, cnsVm) {
                        if (vmErr) {
                            return next(vmErr);
                        }
                        ctx.cnsVm = cnsVm;
                        next();
                    });
                } else {
                    next();
                }
            });
        },

        function getLatestCnsImage(ctx, next) {
            var filter = {name: 'cns'};
            self.sdcadm.updates.listImages(filter, function (err, images) {
                if (err) {
                    next(err);
                } else if (images && images.length) {
                    // TODO presuming sorted
                    ctx.cnsImg = images[images.length - 1];
                    next();
                } else {
                    next(new errors.UpdateError('no "cns" image found'));
                }
            });
        },

        function haveCnsImageAlready(ctx, next) {
            self.sdcadm.imgapi.getImage(ctx.cnsImg.uuid,
                    function (err, img_) {
                if (err && err.body && err.body.code === 'ResourceNotFound') {
                    ctx.imgsToDownload.push(ctx.cnsImg);
                } else if (err) {
                    return next(err);
                }
                next();
            });
        },

        function importImages(ctx, next) {
            if (ctx.imgsToDownload.length === 0) {
                return next();
            }
            var proc = new DownloadImages({images: ctx.imgsToDownload});
            proc.execute({
                sdcadm: self.sdcadm,
                log: self.log,
                progress: self.progress
            }, next);
        },

        /* @field ctx.userString */
        shared.getUserScript,

        function createCnsSvc(ctx, next) {
            if (ctx.cnsSvc) {
                return next();
            }

            var domain = self.sdcadm.sdc.metadata.datacenter_name + '.' +
                    self.sdcadm.sdc.metadata.dns_domain;
            var svcDomain = svcData.name + '.' + domain;

            self.progress('Creating "cns" service');
            ctx.didSomething = true;
            svcData.params.image_uuid = ctx.cnsImg.uuid;
            svcData.metadata['user-script'] = ctx.userScript;
            svcData.metadata['SERVICE_DOMAIN'] = svcDomain;
            svcData.params.billing_id = ctx.cnsPkg.uuid;
            delete svcData.params.package_name;

            self.sdcadm.sapi.createService('cns', self.sdcadm.sdc.uuid,
                    svcData, function (err, svc) {
                if (err) {
                    return next(new errors.SDCClientError(err, 'sapi'));
                }
                ctx.cnsSvc = svc;
                self.log.info({svc: svc}, 'created cns svc');
                next();
            });
        },

        /* @field ctx.headnode */
        function getHeadnode(ctx, next) {
            self.sdcadm.cnapi.listServers({
                headnode: true
            }, function (err, servers) {
                if (err) {
                    return next(new errors.SDCClientError(err, 'cnapi'));
                }
                ctx.headnode = servers[0];
                return next();
            });
        },
        function createCnsInst(ctx, next) {
            if (ctx.cnsInst) {
                return next();
            }
            self.progress('Creating "cns" instance');
            ctx.didSomething = true;
            var instOpts = {
                params: {
                    alias: 'cns0',
                    server_uuid: ctx.headnode.uuid
                }
            };
            self.sdcadm.sapi.createInstance(ctx.cnsSvc.uuid, instOpts,
                    function (err, inst) {
                if (err) {
                    return next(new errors.SDCClientError(err, 'sapi'));
                }
                self.progress('Created VM %s (%s)', inst.uuid,
                    inst.params.alias);
                ctx.newCnsInst = inst;
                next();
            });
        },

        function done(ctx, next) {
            if (ctx.didSomething) {
                self.progress('Setup "cns" (%ds)',
                    Math.floor((Date.now() - start) / 1000));
            }
            next();
        }
    ]}, cb);
}

do_cns.options = [
    {
        names: ['help', 'h'],
        type: 'bool',
        help: 'Show this help.'
    }
];
do_cns.help = (
    'Create the "cns" service and a first instance.\n' +
    '\n' +
    'Usage:\n' +
    '     {{name}} cns\n' +
    '\n' +
    '{{options}}'
);

// --- exports

module.exports = {
    do_cns: do_cns
};
<|endoftext|>


<commit_before>var CloudCmd, Util, DOM;

(function(CloudCmd, Util, DOM) {
    'use strict';

    var Info    = DOM.CurrentInfo,
        Events  = DOM.Events,
        Buffer  = DOM.Buffer,

        Chars   = [],
        KEY     = {
            BACKSPACE   : 8,
            TAB         : 9,
            ENTER       : 13,
            ESC         : 27,

            SPACE       : 32,
            PAGE_UP     : 33,
            PAGE_DOWN   : 34,
            END         : 35,
            HOME        : 36,
            UP          : 38,
            DOWN        : 40,

            INSERT      : 45,
            DELETE      : 46,

            ZERO        : 48,

            A           : 65,

            C           : 67,
            D           : 68,

            G           : 71,

            O           : 79,
            Q           : 81,
            R           : 82,
            S           : 83,
            T           : 84,

            V           : 86,

            X           : 88,

            Z           : 90,

            INSERT_MAC  : 96,

            ASTERISK    : 106,
            PLUS        : 107,
            MINUS       : 109,

            F1          : 112,
            F2          : 113,
            F3          : 114,
            F4          : 115,
            F5          : 116,
            F6          : 117,
            F7          : 118,
            F8          : 119,
            F9          : 120,
            F10         : 121,

            DOT         : 190,
            SLASH       : 191,
            TRA         : 192, /* Typewritten Reverse Apostrophe (`) */
            BACKSLASH   : 220
        };

    KeyProto.prototype = KEY;
    CloudCmd.Key = KeyProto;

    function KeyProto() {
        var Key = this,
            Binded;

        this.isBind     = function() {
            return Binded;
        };

        this.setBind    = function() {
            Binded = true;
        };

        this.unsetBind  = function() {
            Binded = false;
        };

        this.bind   = function() {
            Events.addKey(listener);
            Binded = true;
        };

        function listener(event) {
            /* получаем выдленный файл*/
            var keyCode         = event.keyCode,
                alt             = event.altKey,
                ctrl            = event.ctrlKey,
                meta            = event.metaKey,
                keyIdentifier   = event.keyIdentifier,
                isBetween       = keyCode >= KEY.ZERO && keyCode <= KEY.Z,
                char            = '';

            if (keyIdentifier)
                char = fromCharCode(keyIdentifier);
            else
                char = event.key;

            /* если клавиши можно обрабатывать*/
            if (Binded) {
                if (!alt && !ctrl && !meta && (isBetween || keyCode === KEY.DOT))
                    setCurrentByLetter(char);
                else {
                    Chars       = [];
                    switchKey(event);
                }

                /* устанавливаем все обработчики
                 * нажатий клавиш
                 */
                } else if (keyCode === Key.S && alt) {
                /* обрабатываем нажатия на клавиши*/
                Binded = true;
                Util.log('keybinds enabled');

                Events.preventDefault(event);
            }
        }

        function fromCharCode(keyIdentifier) {
            var code    = keyIdentifier.substring(2),
                hex     = parseInt(code, 16),
                char    = String.fromCharCode(hex);

            return char;
        }

        function setCurrentByLetter(char) {
            var i, n, name, isMatch, byName, firstByName,
                skipCount   = 0,
                skipN       = 0,
                setted      = false,
                current     = Info.element,
                files       = Info.files,
                escapeChar  = Util.escapeRegExp(char),
                regExp      = new RegExp('^' + escapeChar + '.*$', 'i');

            n               = Chars.length;
            for (i = 0; i < n; i++)
                if (char !== Chars[i])
                    break;

            if (!i)
                Chars = [];

            skipN           = skipCount = i;
            Chars.push(char);

            n               = files.length;
            for (i = 0; i < n; i++) {
                current     = files[i];
                name        = DOM.getCurrentName(current);
                isMatch     = name.match(regExp);

                if (isMatch) {
                    byName = DOM.getCurrentByName(name);

                    if (!skipCount) {
                        setted = true;
                        DOM.setCurrentFile(byName);
                        break;
                    } else {
                        if (skipN === skipCount)
                            firstByName = byName;

                        --skipCount;
                    }
                }
            }

            if (!setted) {
                DOM.setCurrentFile(firstByName);
                Chars = [char];
            }
        }

        function switchKey(event) {
            var i, obj, name, isSelected, isDir, prev, next,
                current         = Info.element,
                panel           = Info.panel,
                path            = Info.path,
                keyCode         = event.keyCode,
                shift           = event.shiftKey,
                alt             = event.altKey,
                ctrl            = event.ctrlKey,
                meta            = event.metaKey,
                ctrlMeta        = ctrl || meta;

            if (current) {
                prev            = current.previousSibling;
                next            = current.nextSibling;
            }

            switch (keyCode) {
            case Key.TAB:
                DOM.changePanel();
                Events.preventDefault(event);
                break;

            case Key.INSERT:
                DOM .toggleSelectedFile(current)
                    .setCurrentFile(next);
                break;

            case Key.INSERT_MAC:
                DOM .toggleSelectedFile(current)
                    .setCurrentFile(next);
                break;

            case Key.DELETE:
                if (shift)
                    DOM.sendDelete();
                else
                    DOM.promptDelete(current);
                break;

            case Key.ASTERISK:
                DOM.toggleAllSelectedFiles(current);
                break;

            case Key.PLUS:
                DOM.expandSelection();
                break;

            case Key.MINUS:
                DOM.shrinkSelection();
                break;

            case Key.F1:
                CloudCmd.Help.show();
                Events.preventDefault(event);
                break;

            case Key.F2:
                DOM.renameCurrent(current);
                break;

            case Key.F3:
                if (shift)
                    CloudCmd.Markdown.show(path);
                else
                    CloudCmd.View.show();

                Events.preventDefault(event);
                break;

            case Key.F4:
                CloudCmd.Edit.show();
                Events.preventDefault(event);
                break;

            case Key.F5:
                DOM.copyFiles();
                Events.preventDefault(event);
                break;

            case Key.F6:
                DOM.moveFiles();
                Events.preventDefault(event);
                break;

            case Key.F7:
                if (shift)
                    DOM.promptNewFile();
                else
                    DOM.promptNewDir();

                Events.preventDefault(event);
                break;

            case Key.F8:
                DOM.promptDelete(current);
                break;

            case Key.F9:
                CloudCmd.Menu.show();
                Events.preventDefault(event);

                break;

            case Key.F10:
                CloudCmd.Config.show();
                Events.preventDefault(event);

                break;

            case Key.TRA:
                DOM.Images.showLoad({top: true});

                if (shift)
                    obj = CloudCmd.Terminal;
                else
                    obj = CloudCmd.Konsole;

                if (obj && obj.show)
                    obj.show();

                Events.preventDefault(event);

                break;

            case Key.SPACE:
                isDir   = Info.isDir,
                name    = Info.name;

                if (!isDir || name === '..')
                    isSelected    = true;
                else
                    isSelected    = DOM.isSelected(current);

                Util.exec.if(isSelected, function() {
                    DOM.toggleSelectedFile(current);
                }, function(callback) {
                    DOM.loadCurrentSize(callback, current);
                });

                Events.preventDefault(event);
                break;

            /* навигация по таблице файлов  *
             * если нажали клавишу вверх    *
             * выделяем предыдущую строку   */
            case Key.UP:
                if (shift)
                     DOM.toggleSelectedFile(current);

                DOM.setCurrentFile(prev);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу в низ - выделяем следующую строку    */
            case Key.DOWN:
                if (shift)
                     DOM.toggleSelectedFile(current);

                DOM.setCurrentFile(next);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу Home     *
             * переходим к самому верхнему  *
             * элементу                     */
            case Key.HOME:
                DOM.setCurrentFile(Info.first);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу End выделяем последний элемент   */
            case Key.END:
                DOM.setCurrentFile(Info.last);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу page down проматываем экран */
            case Key.PAGE_DOWN:
                DOM.scrollByPages(panel, 1);

                for (i = 0; i < 30; i++) {

                    if (!current.nextSibling)
                        break;

                    current = current.nextSibling;
                }
                DOM.setCurrentFile(current);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу page up проматываем экран */
            case Key.PAGE_UP:
                DOM.scrollByPages(panel, -1);

                var tryCatch    = function(pCurrentFile) {
                        Util.exec.try(function() {
                            return pCurrentFile
                                    .previousSibling
                                        .previousSibling
                                            .previousSibling
                                                .previousSibling;
                        });
                    };

                for (i = 0; i < 30; i++) {
                    if (!current.previousSibling || tryCatch(current) )
                        break;

                    current = current.previousSibling;
                }

                DOM.setCurrentFile(current);
                Events.preventDefault(event);
                break;

            /* открываем папку*/
            case Key.ENTER:
                if (Info.isDir)
                    CloudCmd.loadDir({
                        path: DOM.getCurrentPath()
                    });
                break;

            case Key.BACKSPACE:
                CloudCmd.goToParentDir();
                Events.preventDefault(event);
                break;

            case Key.BACKSLASH:
                if (command)
                    CloudCmd.loadDir({
                        path: '/'
                    });
                break;

            case Key.A:
                if (ctrlMeta)
                    DOM.toggleAllSelectedFiles();
                    Events.preventDefault(event);

                break;

            /*
             * обновляем страницу,
             * загружаем содержимое каталога
             * при этом данные берём всегда с
             * сервера, а не из кэша
             * (обновляем кэш)
             */
            case Key.R:
                if (ctrlMeta) {
                    Util.log('reloading page...\n');

                    CloudCmd.refresh();
                    Events.preventDefault(event);
                }
                break;

            case Key.C:
                if (ctrlMeta)
                    Buffer.copy();
                break;

            case Key.X:
                if (ctrlMeta)
                    Buffer.cut();
                break;

            case Key.V:
                if (ctrlMeta)
                   Buffer.paste();
                break;

            case Key.Z:
                if (ctrlMeta)
                    Buffer.clear();
                break;

            /* чистим хранилище */
            case Key.D:
                if (ctrlMeta) {
                    Util.log('clearing storage...');

                    DOM.Storage.clear();
                    Events.preventDefault();
                }
                break;

            /* убираем все обработчики нажатий клавиш */
            case Key.Q:
                if (alt) {
                    Util.log('keybindings disabled');

                    Binded = false;
                    Events.preventDefault(event);
                }
                break;
            }
        }
    }

})(CloudCmd, Util, DOM);
<commit_msg>feature(key) add chaining<commit_after>var CloudCmd, Util, DOM;

(function(CloudCmd, Util, DOM) {
    'use strict';

    var Info    = DOM.CurrentInfo,
        Events  = DOM.Events,
        Buffer  = DOM.Buffer,

        Chars   = [],
        KEY     = {
            BACKSPACE   : 8,
            TAB         : 9,
            ENTER       : 13,
            ESC         : 27,

            SPACE       : 32,
            PAGE_UP     : 33,
            PAGE_DOWN   : 34,
            END         : 35,
            HOME        : 36,
            UP          : 38,
            DOWN        : 40,

            INSERT      : 45,
            DELETE      : 46,

            ZERO        : 48,

            A           : 65,

            C           : 67,
            D           : 68,

            G           : 71,

            O           : 79,
            Q           : 81,
            R           : 82,
            S           : 83,
            T           : 84,

            V           : 86,

            X           : 88,

            Z           : 90,

            INSERT_MAC  : 96,

            ASTERISK    : 106,
            PLUS        : 107,
            MINUS       : 109,

            F1          : 112,
            F2          : 113,
            F3          : 114,
            F4          : 115,
            F5          : 116,
            F6          : 117,
            F7          : 118,
            F8          : 119,
            F9          : 120,
            F10         : 121,

            DOT         : 190,
            SLASH       : 191,
            TRA         : 192, /* Typewritten Reverse Apostrophe (`) */
            BACKSLASH   : 220
        };

    KeyProto.prototype = KEY;
    CloudCmd.Key = KeyProto;

    function KeyProto() {
        var Key = this,
            Binded;

        this.isBind     = function() {
            return Binded;
        };

        this.setBind    = function() {
            Binded = true;

            return Key;
        };

        this.unsetBind  = function() {
            Binded = false;

            return Key;
        };

        this.bind   = function() {
            Events.addKey(listener);
            Binded = true;

            return Key;
        };

        function listener(event) {
            /* получаем выдленный файл*/
            var keyCode         = event.keyCode,
                alt             = event.altKey,
                ctrl            = event.ctrlKey,
                meta            = event.metaKey,
                keyIdentifier   = event.keyIdentifier,
                isBetween       = keyCode >= KEY.ZERO && keyCode <= KEY.Z,
                char            = '';

            if (keyIdentifier)
                char = fromCharCode(keyIdentifier);
            else
                char = event.key;

            /* если клавиши можно обрабатывать*/
            if (Binded) {
                if (!alt && !ctrl && !meta && (isBetween || keyCode === KEY.DOT))
                    setCurrentByLetter(char);
                else {
                    Chars       = [];
                    switchKey(event);
                }

                /* устанавливаем все обработчики
                 * нажатий клавиш
                 */
                } else if (keyCode === Key.S && alt) {
                /* обрабатываем нажатия на клавиши*/
                Binded = true;
                Util.log('keybinds enabled');

                Events.preventDefault(event);
            }
        }

        function fromCharCode(keyIdentifier) {
            var code    = keyIdentifier.substring(2),
                hex     = parseInt(code, 16),
                char    = String.fromCharCode(hex);

            return char;
        }

        function setCurrentByLetter(char) {
            var i, n, name, isMatch, byName, firstByName,
                skipCount   = 0,
                skipN       = 0,
                setted      = false,
                current     = Info.element,
                files       = Info.files,
                escapeChar  = Util.escapeRegExp(char),
                regExp      = new RegExp('^' + escapeChar + '.*$', 'i');

            n               = Chars.length;
            for (i = 0; i < n; i++)
                if (char !== Chars[i])
                    break;

            if (!i)
                Chars = [];

            skipN           = skipCount = i;
            Chars.push(char);

            n               = files.length;
            for (i = 0; i < n; i++) {
                current     = files[i];
                name        = DOM.getCurrentName(current);
                isMatch     = name.match(regExp);

                if (isMatch) {
                    byName = DOM.getCurrentByName(name);

                    if (!skipCount) {
                        setted = true;
                        DOM.setCurrentFile(byName);
                        break;
                    } else {
                        if (skipN === skipCount)
                            firstByName = byName;

                        --skipCount;
                    }
                }
            }

            if (!setted) {
                DOM.setCurrentFile(firstByName);
                Chars = [char];
            }
        }

        function switchKey(event) {
            var i, obj, name, isSelected, isDir, prev, next,
                current         = Info.element,
                panel           = Info.panel,
                path            = Info.path,
                keyCode         = event.keyCode,
                shift           = event.shiftKey,
                alt             = event.altKey,
                ctrl            = event.ctrlKey,
                meta            = event.metaKey,
                ctrlMeta        = ctrl || meta;

            if (current) {
                prev            = current.previousSibling;
                next            = current.nextSibling;
            }

            switch (keyCode) {
            case Key.TAB:
                DOM.changePanel();
                Events.preventDefault(event);
                break;

            case Key.INSERT:
                DOM .toggleSelectedFile(current)
                    .setCurrentFile(next);
                break;

            case Key.INSERT_MAC:
                DOM .toggleSelectedFile(current)
                    .setCurrentFile(next);
                break;

            case Key.DELETE:
                if (shift)
                    DOM.sendDelete();
                else
                    DOM.promptDelete(current);
                break;

            case Key.ASTERISK:
                DOM.toggleAllSelectedFiles(current);
                break;

            case Key.PLUS:
                DOM.expandSelection();
                break;

            case Key.MINUS:
                DOM.shrinkSelection();
                break;

            case Key.F1:
                CloudCmd.Help.show();
                Events.preventDefault(event);
                break;

            case Key.F2:
                DOM.renameCurrent(current);
                break;

            case Key.F3:
                if (shift)
                    CloudCmd.Markdown.show(path);
                else
                    CloudCmd.View.show();

                Events.preventDefault(event);
                break;

            case Key.F4:
                CloudCmd.Edit.show();
                Events.preventDefault(event);
                break;

            case Key.F5:
                DOM.copyFiles();
                Events.preventDefault(event);
                break;

            case Key.F6:
                DOM.moveFiles();
                Events.preventDefault(event);
                break;

            case Key.F7:
                if (shift)
                    DOM.promptNewFile();
                else
                    DOM.promptNewDir();

                Events.preventDefault(event);
                break;

            case Key.F8:
                DOM.promptDelete(current);
                break;

            case Key.F9:
                CloudCmd.Menu.show();
                Events.preventDefault(event);

                break;

            case Key.F10:
                CloudCmd.Config.show();
                Events.preventDefault(event);

                break;

            case Key.TRA:
                DOM.Images.showLoad({top: true});

                if (shift)
                    obj = CloudCmd.Terminal;
                else
                    obj = CloudCmd.Konsole;

                if (obj && obj.show)
                    obj.show();

                Events.preventDefault(event);

                break;

            case Key.SPACE:
                isDir   = Info.isDir,
                name    = Info.name;

                if (!isDir || name === '..')
                    isSelected    = true;
                else
                    isSelected    = DOM.isSelected(current);

                Util.exec.if(isSelected, function() {
                    DOM.toggleSelectedFile(current);
                }, function(callback) {
                    DOM.loadCurrentSize(callback, current);
                });

                Events.preventDefault(event);
                break;

            /* навигация по таблице файлов  *
             * если нажали клавишу вверх    *
             * выделяем предыдущую строку   */
            case Key.UP:
                if (shift)
                     DOM.toggleSelectedFile(current);

                DOM.setCurrentFile(prev);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу в низ - выделяем следующую строку    */
            case Key.DOWN:
                if (shift)
                     DOM.toggleSelectedFile(current);

                DOM.setCurrentFile(next);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу Home     *
             * переходим к самому верхнему  *
             * элементу                     */
            case Key.HOME:
                DOM.setCurrentFile(Info.first);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу End выделяем последний элемент   */
            case Key.END:
                DOM.setCurrentFile(Info.last);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу page down проматываем экран */
            case Key.PAGE_DOWN:
                DOM.scrollByPages(panel, 1);

                for (i = 0; i < 30; i++) {

                    if (!current.nextSibling)
                        break;

                    current = current.nextSibling;
                }
                DOM.setCurrentFile(current);
                Events.preventDefault(event);
                break;

            /* если нажали клавишу page up проматываем экран */
            case Key.PAGE_UP:
                DOM.scrollByPages(panel, -1);

                var tryCatch    = function(pCurrentFile) {
                        Util.exec.try(function() {
                            return pCurrentFile
                                    .previousSibling
                                        .previousSibling
                                            .previousSibling
                                                .previousSibling;
                        });
                    };

                for (i = 0; i < 30; i++) {
                    if (!current.previousSibling || tryCatch(current) )
                        break;

                    current = current.previousSibling;
                }

                DOM.setCurrentFile(current);
                Events.preventDefault(event);
                break;

            /* открываем папку*/
            case Key.ENTER:
                if (Info.isDir)
                    CloudCmd.loadDir({
                        path: DOM.getCurrentPath()
                    });
                break;

            case Key.BACKSPACE:
                CloudCmd.goToParentDir();
                Events.preventDefault(event);
                break;

            case Key.BACKSLASH:
                if (command)
                    CloudCmd.loadDir({
                        path: '/'
                    });
                break;

            case Key.A:
                if (ctrlMeta)
                    DOM.toggleAllSelectedFiles();
                    Events.preventDefault(event);

                break;

            /*
             * обновляем страницу,
             * загружаем содержимое каталога
             * при этом данные берём всегда с
             * сервера, а не из кэша
             * (обновляем кэш)
             */
            case Key.R:
                if (ctrlMeta) {
                    Util.log('reloading page...\n');

                    CloudCmd.refresh();
                    Events.preventDefault(event);
                }
                break;

            case Key.C:
                if (ctrlMeta)
                    Buffer.copy();
                break;

            case Key.X:
                if (ctrlMeta)
                    Buffer.cut();
                break;

            case Key.V:
                if (ctrlMeta)
                   Buffer.paste();
                break;

            case Key.Z:
                if (ctrlMeta)
                    Buffer.clear();
                break;

            /* чистим хранилище */
            case Key.D:
                if (ctrlMeta) {
                    Util.log('clearing storage...');

                    DOM.Storage.clear();
                    Events.preventDefault();
                }
                break;

            /* убираем все обработчики нажатий клавиш */
            case Key.Q:
                if (alt) {
                    Util.log('keybindings disabled');

                    Binded = false;
                    Events.preventDefault(event);
                }
                break;
            }
        }
    }

})(CloudCmd, Util, DOM);
<|endoftext|>


<commit_before>(function () {

  var socket;
  var closures = {};
  var nowReady = false;
  var readied = 0;
  var lastTimeout;
  var uri = '//**SERVER**:**PORT**';

  var fqnMap = {
    data: {},

    get: function (fqn) {
      return fqnMap.data[fqn];
    },

    set: function (fqn, val) {
      if (fqnMap.data[fqn] !== undefined) {
        fqnMap.deleteVar(fqn, val);
      }
      var lastIndex = fqn.lastIndexOf('.');
      var parent = fqn.substring(0, lastIndex);
      fqnMap.addParent(parent, fqn.substring(lastIndex + 1));
      return (fqnMap.data[fqn] = val);
    },

    addParent: function (parent, key) {
      if (parent) {
        if (!util.isArray(fqnMap.data[parent])) {
          fqnMap.set(parent, []); // Handle changing a non-object to an object.
        }
        fqnMap.data[parent].push(key);
      }
    },

    deleteVar: function (fqn) {
      var lastIndex = fqn.lastIndexOf('.');
      var parent = fqn.substring(0, lastIndex);

      if (util.hasProperty(this.data, parent)) {

        // Remove from its parent.
        var index = util.indexOf(this.data[parent], fqn.substring(lastIndex + 1));
        if (index > -1) {
          this.data[parent].splice(index, 1);
        }
      }
      if (util.isArray(this.data[fqn])) {
        // Deleting a child will remove it via splice.
        for (var i = 0; this.data[fqn].length;) {
          // Recursive delete all children.
          this.deleteVar(fqn + '.' + this.data[fqn][i]);
        }
      }
      delete this.data[fqn];
    }
  };
  window.fqnMap = fqnMap;
  var util = {
    _events: {},
    // Event code from socket.io
    on: function (name, fn) {
      if (!(util.hasProperty(util._events, name))) {
        util._events[name] = [];
      }
      util._events[name].push(fn);
      return util;
    },

    indexOf: function (arr, val) {
      for (var i = 0, ii = arr.length; i < ii; i++) {
        if ("" + arr[i] === val) {
          return i;
        }
      }
      return -1;
    },

    emit: function (name, args) {
      if (util.hasProperty(util._events, name)) {
        var events = util._events[name].slice(0);
        for (var i = 0, ii = events.length; i < ii; i++) {
          events[i].apply(util, args === undefined ? [] : args);
        }
      }
      return util;
    },
    removeEvent: function (name, fn) {
      if (util.hasProperty(util._events, name)) {
        for (var a = 0, l = util._events[name].length; a < l; a++) {
          if (util._events[name][a] == fn) {
            util._events[name].splice(a, 1);
          }
        }
      }
      return util;
    },

    hasProperty: function (obj, prop) {
      return Object.prototype.hasOwnProperty.call(Object(obj), prop);
    },
    isArray: Array.isArray || function (obj) {
      return Object.prototype.toString.call(obj) === '[object Array]';
    },

    createVarAtFqn: function (scope, fqn, value) {
      var path = fqn.split('.');
      var currVar = util.forceGetParentVarAtFqn(scope, fqn);
      var key = path.pop();
      fqnMap.set(fqn, value);
      currVar[key] = value;
      if (value && typeof value === 'object') {
        currVar[key] = util.isArray(value) ? [] : {};
      }
      if (!(isIE || util.isArray(currVar))) {
        util.watch(currVar, key, fqn);
      }
    },

    forceGetParentVarAtFqn: function (scope, fqn) {
      var path = fqn.split('.');
      path.shift();
      var currVar = scope;
      while (path.length > 1) {
        var prop = path.shift();
        if (!util.hasProperty(currVar, prop)) {
          if (!isNaN(path[0])) {
            currVar[prop] = [];
          } else {
            currVar[prop] = {};
          }
        }
        currVar = currVar[prop];
      }
      return currVar;
    },

    getVarFromFqn: function (scope, fqn) {
      var path = fqn.split('.');
      path.shift();
      var currVar = scope;
      while (path.length > 0) {
        var prop = path.shift();
        if (util.hasProperty(currVar, prop)) {
          currVar = currVar[prop];
        } else {
          return false;
        }
      }
      return currVar;
    },

    generateRandomString: function () {
      return Math.random().toString().substr(2);
    },

    getValOrFqn: function (val, fqn) {
      if (typeof val === 'function') {
        if (val.remote) {
          return undefined;
        }
        return {fqn: fqn};
      } else {
        return val;
      }
    },

    watch: function (obj, label, fqn) {
      var val = obj[label];
      function getter () {
        return val;
      };
      function setter (newVal) {
        if (val !== newVal && newVal !== fqnMap.get(fqn)) {
          // trigger some sort of change.
          if (val && typeof val === 'object') {
            fqnMap.deleteVar(fqn);
            lib.processScope(obj, fqn.substring(0, fqn.lastIndexOf('.')));
            return undefined;
          }
          val = newVal;
          if (newVal && typeof newVal === 'object') {
            fqnMap.deleteVar(fqn);
            lib.processScope(newVal, fqn);
            return undefined;
          }
          fqnMap.set(fqn, newVal);
          if (typeof newVal === 'function') {
            newVal = {fqn: fqn};
          }
          var obj = {};
          obj[fqn] = newVal;
          socket.emit('rv', obj);
        }
        return newVal;
      };
      if (Object.defineProperty) {
        Object.defineProperty(obj, label, {get: getter, set: setter});
      } else {
        if (obj.__defineGetter__) {
          obj.__defineGetter__(label, getter);
        }
        if (obj.__defineSetter__) {
          obj.__defineSetter__(label, setter);
        }
      }
    }
  };

  var now = {
    ready: function (func) {
      if (arguments.length === 0) {
        util.emit('ready');
      } else {
        if (nowReady) {
          func();
        }
        util.on('ready', func);
      }
    },
    core: {
      on: util.on,
      options: **OPTIONS**,
      removeEvent: util.removeEvent,
      clientId: undefined
    }
  };

  // Needs to be easily configurable.
  **SCOPE**.now = now;

  var isIE = (function () {
    try {
      Object.defineProperty({}, '', {});
      return false;
    } catch (err) {
      return true;
    }
    return true;
  })();

  var lib = {

    deleteVar: function (fqn) {
      var path, currVar, parent, key;
      path = fqn.split('.');
      currVar = now;
      for (var i = 1; i < path.length; i++) {
        key = path[i];
        if (currVar === undefined) {
          // delete from fqnMap, just to be safe.
          fqnMap.deleteVar(fqn);
          return;
        }
        if (i === path.length - 1) {
          delete currVar[path.pop()];
          fqnMap.deleteVar(fqn);
          return;
        }
        currVar = currVar[key];
      }
    },

    replaceVar: function (data) {
      for (var fqn in data) {
        if (util.hasProperty(data[fqn], 'fqn')) {
          data[fqn] = lib.constructRemoteFunction(fqn);
        }
        util.createVarAtFqn(now, fqn, data[fqn]);
      }
    },

    remoteCall: function (data) {
      var func;
      // Retrieve the function, either from closures hash or from the now scope
      if (data.fqn.split('_')[0] === 'closure') {
        func = closures[data.fqn];
      } else {
        func = util.getVarFromFqn(now, data.fqn);
      }
      var args = data.args;

      if (typeof args === 'object' && !util.isArray(args)) {
        var newargs = [];
        // Enumeration order is not defined so this might be useless,
        // but there will be cases when it works
        for (var i in args) {
          newargs.push(args[i]);
        }
        args = newargs;
      }

      // Search (only at top level) of args for functions parameters,
      // and replace with wrapper remote call function
      for (var i = 0, ii = args.length; i < ii; i++) {
        if (util.hasProperty(args[i], 'fqn')) {
          args[i] = lib.constructRemoteFunction(args[i].fqn);
        }
      }
      func.apply({now: now}, args);
    },

    // Handle the ready message from the server
    serverReady: function () {
      nowReady = true;
      lib.processNowScope();
      util.emit('ready');
    },

    constructRemoteFunction: function (fqn) {
      var remoteFn = function () {
        lib.processNowScope();
        var args = [];
        for (var i = 0, ii = arguments.length; i < ii; i++)
          args[i] = arguments[i];
        for (i = 0, ii = args.length; i < ii; i++) {
          if (typeof args[i] === 'function') {
            var closureId = 'closure_' + args[i].name + '_' + util.generateRandomString();
            closures[closureId] = args[i];
            args[i] = {fqn: closureId};
          }
        }
        socket.emit('rfc', {fqn: fqn, args: args});
      };
      remoteFn.remote = true;
      return remoteFn;
    },
    handleNewConnection: function (socket) {
      if (socket.handled) return;
      socket.handled = true;

      socket.on('rfc', function (data) {
        lib.remoteCall(data);
        util.emit('rfc', data);
      });
      socket.on('rv', function (data) {
        lib.replaceVar(data);
        util.emit('rv', data);
      });
      socket.on('del', function (data) {
        lib.deleteVar(data);
        util.emit('del', data);
      });

      // Handle the ready message from the server
      socket.on('rd', function (data) {
        if (++readied == 2)
          lib.serverReady();
      });

      socket.on('disconnect', function () {
        readied = 0;
        util.emit('disconnect');
      });
      // Forward planning for socket io 0.7
      socket.on('error', function () {
        util.emit('error');
      });
      socket.on('retry', function () {
        util.emit('retry');
      });
      socket.on('reconnect', function () {
        util.emit('reconnect');
      });
      socket.on('reconnect_failed', function () {
        util.emit('reconnect_failed');
      });
      socket.on('connect_failed', function () {
        util.emit('connect_failed');
      });
    },
    processNowScope: function () {
      lib.processScope(now, 'now');
      clearTimeout(lastTimeout);
      if (socket.socket.connected)
        lastTimeout = setTimeout(lib.processNowScope, 1000);
    },
    processScope: function (obj, path) {
      var data = {};
      lib.traverseScope(obj, path, data);
      // Send only for non-empty object
      for (var i in data) {
        if (util.hasProperty(data, i) && data[i] !== undefined) {
          socket.emit('rv', data);
          break;
        }
      }
    },
    traverseScope: function (obj, path, data) {
      if (obj && typeof obj === 'object') {
        var objIsArray = util.isArray(obj);
        var keys = fqnMap.get(path);
        var hasProperties = false;
        for (var key in obj) {
          hasProperties = true;
          var fqn = path + '.' + key;
          var val = obj[key];

          if (fqn === 'now.core' || fqn === 'now.ready') {
            continue;
          }
          var type = typeof val;
          if (util.hasProperty(obj, key)) {
            if (isIE || objIsArray) {
              if (!(val && type === 'object') && fqnMap.get(fqn) !== val) {
                fqnMap.set(fqn, val);
                data[fqn] = util.getValOrFqn(val, fqn);
              }
            } else {
              if (fqnMap.get(fqn) === undefined) {
                util.watch(obj, key, fqn);
                if (type !== 'object' || !val) {
                  fqnMap.set(fqn, val);
                  data[fqn] = util.getValOrFqn(val, fqn);
                }
              }
            }
          }
          lib.traverseScope(val, fqn, data);
        }
        if (!(hasProperties || fqnMap.get(path))) {
          fqnMap.set(path, []);
          data[path] = obj;
        }
        if (keys && typeof keys === 'object') {
          var toDelete = [];
          // Scan for deleted keys.
          for (var i = 0; i < keys.length; i++) {
            if (keys[i] !== undefined && obj[keys[i]] === undefined) {
              toDelete.push(path + '.' + keys[i]);
              fqnMap.deleteVar(path + '.' + keys[i]);
              --i;
            }
          }
          // Send message to server to delete from its database.
          if (toDelete.length > 0) {
            socket.emit('del', toDelete);
          }
        }
      }
    }
  };

  var dependencies = [
    { key: 'io', path: '/socket.io/socket.io.js'}
  ];
  var dependenciesLoaded = 0;

  var scriptLoaded = function () {
    dependenciesLoaded++;
    if (dependenciesLoaded !== dependencies.length) {
      return;
    }
    socket = io.connect(uri+'/', now.core.options.socketio || {});
    now.core.socketio = socket;
    socket.on('connect', function () {
      now.core.clientId = socket.socket.sessionid;
      lib.handleNewConnection(socket);
      // Begin intermittent scope traversal

      setTimeout(function () {
        lib.processNowScope();
        socket.emit('rd');
        if (++readied == 2) {
          nowReady = true;
          util.emit('ready');
        }
      }, 100);

      util.emit('connect');
    });
    socket.on('disconnect', function () {
      // y-combinator trick
      (function (y) {
        y(y, now);
      })(function (fn, obj) {
        for (var i in obj) {
          if (obj[i] && typeof obj[i] === 'object' &&
              obj[i] != document && obj[i] !== now.core) {
            fn(fn, obj[i]);
          }
          else if (typeof obj[i] === 'function' && obj[i].remote) {
            delete obj[i];
          }
        }
      });

      // Clear all sorts of stuff in preparation for reconnecting.
      fqnMap.data = {};
    });
  };

  for (var i=0, ii=dependencies.length; i < ii; i++) {
    if (window[dependencies[i]['key']]) {
      scriptLoaded();
      return;
    }
    var fileref=document.createElement('script');
    fileref.setAttribute('type','text/javascript');
    fileref.setAttribute('src', uri+dependencies[i]['path']);
    fileref.onload = scriptLoaded;
    if (isIE) {
      fileref.onreadystatechange = function () {
        if (fileref.readyState === 'loaded' || fileref.readyState === 'complete' ) {
          scriptLoaded();
        }
      };
    }
    document.getElementsByTagName('head')[0].appendChild(fileref);
  }
})();<commit_msg>Reduce visibility of fqnMap.<commit_after>(function () {

  var socket;
  var closures = {};
  var nowReady = false;
  var readied = 0;
  var lastTimeout;
  var uri = '//**SERVER**:**PORT**';

  var fqnMap = {
    data: {},

    get: function (fqn) {
      return fqnMap.data[fqn];
    },

    set: function (fqn, val) {
      if (fqnMap.data[fqn] !== undefined) {
        fqnMap.deleteVar(fqn, val);
      }
      var lastIndex = fqn.lastIndexOf('.');
      var parent = fqn.substring(0, lastIndex);
      fqnMap.addParent(parent, fqn.substring(lastIndex + 1));
      return (fqnMap.data[fqn] = val);
    },

    addParent: function (parent, key) {
      if (parent) {
        if (!util.isArray(fqnMap.data[parent])) {
          fqnMap.set(parent, []); // Handle changing a non-object to an object.
        }
        fqnMap.data[parent].push(key);
      }
    },

    deleteVar: function (fqn) {
      var lastIndex = fqn.lastIndexOf('.');
      var parent = fqn.substring(0, lastIndex);

      if (util.hasProperty(this.data, parent)) {

        // Remove from its parent.
        var index = util.indexOf(this.data[parent], fqn.substring(lastIndex + 1));
        if (index > -1) {
          this.data[parent].splice(index, 1);
        }
      }
      if (util.isArray(this.data[fqn])) {
        // Deleting a child will remove it via splice.
        for (var i = 0; this.data[fqn].length;) {
          // Recursive delete all children.
          this.deleteVar(fqn + '.' + this.data[fqn][i]);
        }
      }
      delete this.data[fqn];
    }
  };
  var util = {
    _events: {},
    // Event code from socket.io
    on: function (name, fn) {
      if (!(util.hasProperty(util._events, name))) {
        util._events[name] = [];
      }
      util._events[name].push(fn);
      return util;
    },

    indexOf: function (arr, val) {
      for (var i = 0, ii = arr.length; i < ii; i++) {
        if ("" + arr[i] === val) {
          return i;
        }
      }
      return -1;
    },

    emit: function (name, args) {
      if (util.hasProperty(util._events, name)) {
        var events = util._events[name].slice(0);
        for (var i = 0, ii = events.length; i < ii; i++) {
          events[i].apply(util, args === undefined ? [] : args);
        }
      }
      return util;
    },
    removeEvent: function (name, fn) {
      if (util.hasProperty(util._events, name)) {
        for (var a = 0, l = util._events[name].length; a < l; a++) {
          if (util._events[name][a] == fn) {
            util._events[name].splice(a, 1);
          }
        }
      }
      return util;
    },

    hasProperty: function (obj, prop) {
      return Object.prototype.hasOwnProperty.call(Object(obj), prop);
    },
    isArray: Array.isArray || function (obj) {
      return Object.prototype.toString.call(obj) === '[object Array]';
    },

    createVarAtFqn: function (scope, fqn, value) {
      var path = fqn.split('.');
      var currVar = util.forceGetParentVarAtFqn(scope, fqn);
      var key = path.pop();
      fqnMap.set(fqn, value);
      currVar[key] = value;
      if (value && typeof value === 'object') {
        currVar[key] = util.isArray(value) ? [] : {};
      }
      if (!(isIE || util.isArray(currVar))) {
        util.watch(currVar, key, fqn);
      }
    },

    forceGetParentVarAtFqn: function (scope, fqn) {
      var path = fqn.split('.');
      path.shift();
      var currVar = scope;
      while (path.length > 1) {
        var prop = path.shift();
        if (!util.hasProperty(currVar, prop)) {
          if (!isNaN(path[0])) {
            currVar[prop] = [];
          } else {
            currVar[prop] = {};
          }
        }
        currVar = currVar[prop];
      }
      return currVar;
    },

    getVarFromFqn: function (scope, fqn) {
      var path = fqn.split('.');
      path.shift();
      var currVar = scope;
      while (path.length > 0) {
        var prop = path.shift();
        if (util.hasProperty(currVar, prop)) {
          currVar = currVar[prop];
        } else {
          return false;
        }
      }
      return currVar;
    },

    generateRandomString: function () {
      return Math.random().toString().substr(2);
    },

    getValOrFqn: function (val, fqn) {
      if (typeof val === 'function') {
        if (val.remote) {
          return undefined;
        }
        return {fqn: fqn};
      } else {
        return val;
      }
    },

    watch: function (obj, label, fqn) {
      var val = obj[label];
      function getter () {
        return val;
      };
      function setter (newVal) {
        if (val !== newVal && newVal !== fqnMap.get(fqn)) {
          // trigger some sort of change.
          if (val && typeof val === 'object') {
            fqnMap.deleteVar(fqn);
            lib.processScope(obj, fqn.substring(0, fqn.lastIndexOf('.')));
            return undefined;
          }
          val = newVal;
          if (newVal && typeof newVal === 'object') {
            fqnMap.deleteVar(fqn);
            lib.processScope(newVal, fqn);
            return undefined;
          }
          fqnMap.set(fqn, newVal);
          if (typeof newVal === 'function') {
            newVal = {fqn: fqn};
          }
          var obj = {};
          obj[fqn] = newVal;
          socket.emit('rv', obj);
        }
        return newVal;
      };
      if (Object.defineProperty) {
        Object.defineProperty(obj, label, {get: getter, set: setter});
      } else {
        if (obj.__defineGetter__) {
          obj.__defineGetter__(label, getter);
        }
        if (obj.__defineSetter__) {
          obj.__defineSetter__(label, setter);
        }
      }
    }
  };

  var now = {
    ready: function (func) {
      if (arguments.length === 0) {
        util.emit('ready');
      } else {
        if (nowReady) {
          func();
        }
        util.on('ready', func);
      }
    },
    core: {
      on: util.on,
      options: **OPTIONS**,
      removeEvent: util.removeEvent,
      clientId: undefined
    }
  };

  // Needs to be easily configurable.
  **SCOPE**.now = now;

  var isIE = (function () {
    try {
      Object.defineProperty({}, '', {});
      return false;
    } catch (err) {
      return true;
    }
    return true;
  })();

  var lib = {

    deleteVar: function (fqn) {
      var path, currVar, parent, key;
      path = fqn.split('.');
      currVar = now;
      for (var i = 1; i < path.length; i++) {
        key = path[i];
        if (currVar === undefined) {
          // delete from fqnMap, just to be safe.
          fqnMap.deleteVar(fqn);
          return;
        }
        if (i === path.length - 1) {
          delete currVar[path.pop()];
          fqnMap.deleteVar(fqn);
          return;
        }
        currVar = currVar[key];
      }
    },

    replaceVar: function (data) {
      for (var fqn in data) {
        if (util.hasProperty(data[fqn], 'fqn')) {
          data[fqn] = lib.constructRemoteFunction(fqn);
        }
        util.createVarAtFqn(now, fqn, data[fqn]);
      }
    },

    remoteCall: function (data) {
      var func;
      // Retrieve the function, either from closures hash or from the now scope
      if (data.fqn.split('_')[0] === 'closure') {
        func = closures[data.fqn];
      } else {
        func = util.getVarFromFqn(now, data.fqn);
      }
      var args = data.args;

      if (typeof args === 'object' && !util.isArray(args)) {
        var newargs = [];
        // Enumeration order is not defined so this might be useless,
        // but there will be cases when it works
        for (var i in args) {
          newargs.push(args[i]);
        }
        args = newargs;
      }

      // Search (only at top level) of args for functions parameters,
      // and replace with wrapper remote call function
      for (var i = 0, ii = args.length; i < ii; i++) {
        if (util.hasProperty(args[i], 'fqn')) {
          args[i] = lib.constructRemoteFunction(args[i].fqn);
        }
      }
      func.apply({now: now}, args);
    },

    // Handle the ready message from the server
    serverReady: function () {
      nowReady = true;
      lib.processNowScope();
      util.emit('ready');
    },

    constructRemoteFunction: function (fqn) {
      var remoteFn = function () {
        lib.processNowScope();
        var args = [];
        for (var i = 0, ii = arguments.length; i < ii; i++)
          args[i] = arguments[i];
        for (i = 0, ii = args.length; i < ii; i++) {
          if (typeof args[i] === 'function') {
            var closureId = 'closure_' + args[i].name + '_' + util.generateRandomString();
            closures[closureId] = args[i];
            args[i] = {fqn: closureId};
          }
        }
        socket.emit('rfc', {fqn: fqn, args: args});
      };
      remoteFn.remote = true;
      return remoteFn;
    },
    handleNewConnection: function (socket) {
      if (socket.handled) return;
      socket.handled = true;

      socket.on('rfc', function (data) {
        lib.remoteCall(data);
        util.emit('rfc', data);
      });
      socket.on('rv', function (data) {
        lib.replaceVar(data);
        util.emit('rv', data);
      });
      socket.on('del', function (data) {
        lib.deleteVar(data);
        util.emit('del', data);
      });

      // Handle the ready message from the server
      socket.on('rd', function (data) {
        if (++readied == 2)
          lib.serverReady();
      });

      socket.on('disconnect', function () {
        readied = 0;
        util.emit('disconnect');
      });
      // Forward planning for socket io 0.7
      socket.on('error', function () {
        util.emit('error');
      });
      socket.on('retry', function () {
        util.emit('retry');
      });
      socket.on('reconnect', function () {
        util.emit('reconnect');
      });
      socket.on('reconnect_failed', function () {
        util.emit('reconnect_failed');
      });
      socket.on('connect_failed', function () {
        util.emit('connect_failed');
      });
    },
    processNowScope: function () {
      lib.processScope(now, 'now');
      clearTimeout(lastTimeout);
      if (socket.socket.connected)
        lastTimeout = setTimeout(lib.processNowScope, 1000);
    },
    processScope: function (obj, path) {
      var data = {};
      lib.traverseScope(obj, path, data);
      // Send only for non-empty object
      for (var i in data) {
        if (util.hasProperty(data, i) && data[i] !== undefined) {
          socket.emit('rv', data);
          break;
        }
      }
    },
    traverseScope: function (obj, path, data) {
      if (obj && typeof obj === 'object') {
        var objIsArray = util.isArray(obj);
        var keys = fqnMap.get(path);
        var hasProperties = false;
        for (var key in obj) {
          hasProperties = true;
          var fqn = path + '.' + key;
          var val = obj[key];

          if (fqn === 'now.core' || fqn === 'now.ready') {
            continue;
          }
          var type = typeof val;
          if (util.hasProperty(obj, key)) {
            if (isIE || objIsArray) {
              if (!(val && type === 'object') && fqnMap.get(fqn) !== val) {
                fqnMap.set(fqn, val);
                data[fqn] = util.getValOrFqn(val, fqn);
              }
            } else {
              if (fqnMap.get(fqn) === undefined) {
                util.watch(obj, key, fqn);
                if (type !== 'object' || !val) {
                  fqnMap.set(fqn, val);
                  data[fqn] = util.getValOrFqn(val, fqn);
                }
              }
            }
          }
          lib.traverseScope(val, fqn, data);
        }
        if (!(hasProperties || fqnMap.get(path))) {
          fqnMap.set(path, []);
          data[path] = obj;
        }
        if (keys && typeof keys === 'object') {
          var toDelete = [];
          // Scan for deleted keys.
          for (var i = 0; i < keys.length; i++) {
            if (keys[i] !== undefined && obj[keys[i]] === undefined) {
              toDelete.push(path + '.' + keys[i]);
              fqnMap.deleteVar(path + '.' + keys[i]);
              --i;
            }
          }
          // Send message to server to delete from its database.
          if (toDelete.length > 0) {
            socket.emit('del', toDelete);
          }
        }
      }
    }
  };

  var dependencies = [
    { key: 'io', path: '/socket.io/socket.io.js'}
  ];
  var dependenciesLoaded = 0;

  var scriptLoaded = function () {
    dependenciesLoaded++;
    if (dependenciesLoaded !== dependencies.length) {
      return;
    }
    socket = io.connect(uri+'/', now.core.options.socketio || {});
    now.core.socketio = socket;
    socket.on('connect', function () {
      now.core.clientId = socket.socket.sessionid;
      lib.handleNewConnection(socket);
      // Begin intermittent scope traversal

      setTimeout(function () {
        lib.processNowScope();
        socket.emit('rd');
        if (++readied == 2) {
          nowReady = true;
          util.emit('ready');
        }
      }, 100);

      util.emit('connect');
    });
    socket.on('disconnect', function () {
      // y-combinator trick
      (function (y) {
        y(y, now);
      })(function (fn, obj) {
        for (var i in obj) {
          if (obj[i] && typeof obj[i] === 'object' &&
              obj[i] != document && obj[i] !== now.core) {
            fn(fn, obj[i]);
          }
          else if (typeof obj[i] === 'function' && obj[i].remote) {
            delete obj[i];
          }
        }
      });

      // Clear all sorts of stuff in preparation for reconnecting.
      fqnMap.data = {};
    });
  };

  for (var i=0, ii=dependencies.length; i < ii; i++) {
    if (window[dependencies[i]['key']]) {
      scriptLoaded();
      return;
    }
    var fileref=document.createElement('script');
    fileref.setAttribute('type','text/javascript');
    fileref.setAttribute('src', uri+dependencies[i]['path']);
    fileref.onload = scriptLoaded;
    if (isIE) {
      fileref.onreadystatechange = function () {
        if (fileref.readyState === 'loaded' || fileref.readyState === 'complete' ) {
          scriptLoaded();
        }
      };
    }
    document.getElementsByTagName('head')[0].appendChild(fileref);
  }
})();<|endoftext|>


<commit_before>const eg = require('../../eg');
const SCHEMA = 'http://express-gateway.io/models/credentials.json';

module.exports = class extends eg.Generator {
  constructor (args, opts) {
    super(args, opts);

    this.stdin = process.stdin;

    this.configureCommand({
      command: 'create [options]',
      desc: 'Create credentials for user or app with specified type',
      builder: yargs =>
        yargs
          .usage(`Usage: $0 ${process.argv[2]} create [options]`)
          .example(`$0 ${process.argv[2]} create -c jdoe -t key-auth`)
          .example(`echo '{"consumer":"jdoe", "type": "key-auth"}'` +
          `| $0 ${process.argv[2]} create --stdin`)
          .example(`echo '{"consumer":"jdoe", "type": "key-auth", "scopes":["existingScope"]}'` +
          `| $0 ${process.argv[2]} create --stdin`)
          .example(`cat all_apps.json | $0 ${process.argv[2]} create --stdin`)
          .example(`$0 ${process.argv[2]} create -u jdoe -p 'scopes=existingScope'`)
          .string(['p', 'c', 't'])
          .boolean(['stdin'])
          .describe('c', 'Consumer ID: can be User ID or username or app ID')
          .describe('t', 'Type of credential: can be one of: oauth2, basic-auth, key-auth')
          .describe('p', 'App property in the form [-p \'foo=bar\']')
          .describe('stdin', 'Import newline-delimited JSON via standard input')
          .alias('c', 'consumer').nargs('c', 1)
          .alias('t', 'type').nargs('t', 1)
          .alias('p', 'property')
          .group(['c', 'p', 'stdin', 't'], 'Options:')
          .check((args, opts) => {
            if (args.stdin) return true; // direct input from stdin, no validation

            if (!(args.t && args.c)) {
              throw new Error('must include either --stdin or -c with -t (--consumer with --type)');
            }
            return true;
          })
    });
  }

  initializing () {
    if (this.argv.stdin) {
      return this._createFromStdin();
    }
  }

  prompting () {
    if (!this.argv.stdin) {
      return this._createFromCommandLine();
    }
  }

  _createFromCommandLine () {
    const argv = this.argv;
    let propertyValues = [];

    if (argv.p) {
      propertyValues = Array.isArray(argv.p) ? argv.p : [argv.p];
    }

    const credential = {};

    let hasInvalidProperty = false;

    propertyValues.forEach(p => {
      const equalIndex = p.indexOf('=');

      if (equalIndex === -1 || equalIndex === p.length - 1) {
        this.log.error('invalid property option:', p);
        hasInvalidProperty = true;
        return;
      }

      const key = p.substring(0, equalIndex);
      const value = p.substring(equalIndex + 1);

      // this is for values like [], {}
      try {
        credential[key] = JSON.parse(value);
      } catch (err) {
        credential[key] = value;
      }
    });

    if (hasInvalidProperty) {
      return;
    }

    return this._promptAndValidate(credential, SCHEMA)
      .then((credential) => this.admin.credentials.create(argv.consumer, argv.type, credential))
      .then(newCredential => {
        this._output(newCredential);
      })
      .catch(err => {
        this.log.error((err.response && err.response.error && err.response.error.text) || err.message);
      });
  };

  _createFromStdin () {
    const argv = this.argv;
    this.stdin.setEncoding('utf8');

    const bufs = [];

    this.stdin.on('readable', () => {
      const chunk = this.stdin.read();

      if (chunk) {
        bufs.push(chunk);
      }
    });
    return new Promise((resolve, reject) => {
      this.stdin.on('end', () => {
        const lines = bufs.join('').split('\n');
        const promises = lines
          .filter(line => line.length > 0)
          .map((line, index) => {
            const credential = JSON.parse(line);
            let consumer, type;

            if (credential.consumer) {
              consumer = credential.consumer;
              delete credential.consumer;
            } else {
              consumer = argv.consumer;
            }
            if (credential.type) {
              type = credential.type;
              delete credential.type;
            } else {
              type = argv.type;
            }

            const options = {
              skipPrompt: true,
              isLast: index === lines.length - 1,
              consumer,
              type
            };

            return this._promptAndValidate(credential, options)
              .then((credential) => this.admin.credentials.create(options.consumer, options.type, credential))
              .then(newCredential => {
                this._output(newCredential);
              })
              .catch(err => {
                this.log.error((err.response && err.response.error && err.response.error.text) || err.message);
              });
          });

        const p = Promise.all(promises);
        resolve(p);
      });
    });
  };

  _output (credential, options) {
    const argv = this.argv;
    if (!argv.q) {
      this.log.ok(`Created ${credential.id || credential.keyId}`);
      this.stdout(JSON.stringify(credential, null, 2));
    } else {
      if (argv.type === 'key-auth' || argv.type === 'jwt') {
        this.stdout(`${credential.keyId}:${credential.keySecret}`);
      } else if (argv.type === 'basic-auth') {
        this.stdout(`${credential.id}:${credential.password}`);
      }
    }
  }
};
<commit_msg>Pass Schema name<commit_after>const eg = require('../../eg');
const SCHEMA = 'http://express-gateway.io/models/credentials.json';

module.exports = class extends eg.Generator {
  constructor (args, opts) {
    super(args, opts);

    this.stdin = process.stdin;

    this.configureCommand({
      command: 'create [options]',
      desc: 'Create credentials for user or app with specified type',
      builder: yargs =>
        yargs
          .usage(`Usage: $0 ${process.argv[2]} create [options]`)
          .example(`$0 ${process.argv[2]} create -c jdoe -t key-auth`)
          .example(`echo '{"consumer":"jdoe", "type": "key-auth"}'` +
          `| $0 ${process.argv[2]} create --stdin`)
          .example(`echo '{"consumer":"jdoe", "type": "key-auth", "scopes":["existingScope"]}'` +
          `| $0 ${process.argv[2]} create --stdin`)
          .example(`cat all_apps.json | $0 ${process.argv[2]} create --stdin`)
          .example(`$0 ${process.argv[2]} create -u jdoe -p 'scopes=existingScope'`)
          .string(['p', 'c', 't'])
          .boolean(['stdin'])
          .describe('c', 'Consumer ID: can be User ID or username or app ID')
          .describe('t', 'Type of credential: can be one of: oauth2, basic-auth, key-auth')
          .describe('p', 'App property in the form [-p \'foo=bar\']')
          .describe('stdin', 'Import newline-delimited JSON via standard input')
          .alias('c', 'consumer').nargs('c', 1)
          .alias('t', 'type').nargs('t', 1)
          .alias('p', 'property')
          .group(['c', 'p', 'stdin', 't'], 'Options:')
          .check((args, opts) => {
            if (args.stdin) return true; // direct input from stdin, no validation

            if (!(args.t && args.c)) {
              throw new Error('must include either --stdin or -c with -t (--consumer with --type)');
            }
            return true;
          })
    });
  }

  initializing () {
    if (this.argv.stdin) {
      return this._createFromStdin();
    }
  }

  prompting () {
    if (!this.argv.stdin) {
      return this._createFromCommandLine();
    }
  }

  _createFromCommandLine () {
    const argv = this.argv;
    let propertyValues = [];

    if (argv.p) {
      propertyValues = Array.isArray(argv.p) ? argv.p : [argv.p];
    }

    const credential = {};

    let hasInvalidProperty = false;

    propertyValues.forEach(p => {
      const equalIndex = p.indexOf('=');

      if (equalIndex === -1 || equalIndex === p.length - 1) {
        this.log.error('invalid property option:', p);
        hasInvalidProperty = true;
        return;
      }

      const key = p.substring(0, equalIndex);
      const value = p.substring(equalIndex + 1);

      // this is for values like [], {}
      try {
        credential[key] = JSON.parse(value);
      } catch (err) {
        credential[key] = value;
      }
    });

    if (hasInvalidProperty) {
      return;
    }

    return this._promptAndValidate(credential, SCHEMA)
      .then((credential) => this.admin.credentials.create(argv.consumer, argv.type, credential))
      .then(newCredential => {
        this._output(newCredential);
      })
      .catch(err => {
        this.log.error((err.response && err.response.error && err.response.error.text) || err.message);
      });
  };

  _createFromStdin () {
    const argv = this.argv;
    this.stdin.setEncoding('utf8');

    const bufs = [];

    this.stdin.on('readable', () => {
      const chunk = this.stdin.read();

      if (chunk) {
        bufs.push(chunk);
      }
    });
    return new Promise((resolve, reject) => {
      this.stdin.on('end', () => {
        const lines = bufs.join('').split('\n');
        const promises = lines
          .filter(line => line.length > 0)
          .map((line, index) => {
            const credential = JSON.parse(line);
            let consumer, type;

            if (credential.consumer) {
              consumer = credential.consumer;
              delete credential.consumer;
            } else {
              consumer = argv.consumer;
            }
            if (credential.type) {
              type = credential.type;
              delete credential.type;
            } else {
              type = argv.type;
            }

            const options = {
              skipPrompt: true,
              isLast: index === lines.length - 1,
              consumer,
              type
            };

            return this._promptAndValidate(credential, SCHEMA, options)
              .then((credential) => this.admin.credentials.create(options.consumer, options.type, credential))
              .then(newCredential => {
                this._output(newCredential);
              })
              .catch(err => {
                this.log.error((err.response && err.response.error && err.response.error.text) || err.message);
              });
          });

        const p = Promise.all(promises);
        resolve(p);
      });
    });
  };

  _output (credential, options) {
    const argv = this.argv;
    if (!argv.q) {
      this.log.ok(`Created ${credential.id || credential.keyId}`);
      this.stdout(JSON.stringify(credential, null, 2));
    } else {
      if (argv.type === 'key-auth' || argv.type === 'jwt') {
        this.stdout(`${credential.keyId}:${credential.keySecret}`);
      } else if (argv.type === 'basic-auth') {
        this.stdout(`${credential.id}:${credential.password}`);
      }
    }
  }
};
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

var utils = require('./utils.js');
var udp = require('./udp.js');
var sources = require('./sources.js');
var jsonsource = require('./jsonsource.js');
var trackWriter = require('./tracks/trackWriter.js');
var fs = require('fs');
var winston = require('winston');

var express = require('express');
var app = express();

exports.startApp = function () {

  var optimist = sources.usages()
    .usage('$0: Http server and router for navigational data (NMEA 0183 & NMEA 2000)')
    .describe('u', 'Broadcast nmea 0183 via udp on port 7777')
    .describe('b', 'Broadcast address for udp broadcast')
    .describe('writejson', 'Write the internal json stream to [filename]')
    .describe('p', 'http port')
    .demand('boat')
    .describe('boat', 'boat configuration, loaded from lib/boats/ directory')
    .options('p', {default: 8080})
    .wrap(70);

  var argv = optimist.argv;

  if (argv.help) {
    optimist.showHelp();
    process.exit(0);
  }

  app.get('/track', function(req, res){
    res.contentType("text/javascript");
    res.write('{ "type": "Feature","geometry": {"type": "MultiPoint","coordinates": [');
    var coordinates = fs.readFileSync('track_coordinates.txt','utf8');
    res.write(coordinates);
    res.write(']},"properties": {"time": [');
    var timestamps = fs.readFileSync('track_timestamps.txt','utf8');
    res.write(timestamps);
    res.write(']}}');
    res.end();
  });
  var oneDay = 86400000;
  app.use(express.static(__dirname + '/../webapp/', { maxAge: oneDay }));
  var server = require('http').createServer(app);
  server.listen(argv.p);

  var primus = new require('primus')(server, {
    parser: 'JSON'
  });

  var streamSources = sources.configure(argv);

  require('./boats/' + argv.boat + '.js').boat.configureStreams(streamSources);

  if (argv.u) {
    udp.create(streamSources.nmea.raw, argv);
  }

  if (argv.writejson) {
    jsonsource.startWriting(streamSources.nmea)
  }

  if(argv.writetrack) {
    trackWriter.createTrackWriter(streamSources.gaugeData.all.filter(function(msg){return msg.type === 'position'}));
  }

  primus.on('connection', function (spark) {
      spark['unsubscribe'] = [];
      winston.info('Connect:' + JSON.stringify(spark.query));
      if (spark.query['pgn'] != undefined) {
        [].concat(spark.query['pgn']).map(function (pgn) {
          var stream = streamconfig.out.pgn.pgnStream(pgn);
          spark['unsubscribe'].push(stream.subscribe(function (event) {
            spark.write(event.value());
          }))
        });
      } else if (spark.query['gaugedata'] != undefined) {
        spark['unsubscribe'].push(streamSources.gaugeData.subscribe(function (event) {
          spark.write(event.value());
        }));
      } else {
        spark['unsubscribe'].push(streamSources.n2k.subscribe(function (event) {
          spark.write(event.value());
        }));
        spark['unsubscribe'].push(streamSources.nmea.json.subscribe(function (event) {
          spark.write(event.value());
        }));
      }

    }
  )
  ;

  primus.on('disconnection', function (spark) {
    spark['unsubscribe'].map(function (unsubscribeF) {
      unsubscribeF();
    });
  });
}

<commit_msg>Revert "Switch to Express, add first naive implementation of serving tracks"<commit_after>#!/usr/bin/env node
'use strict';

var utils = require('./utils.js');
var udp = require('./udp.js');
var sources = require('./sources.js');
var jsonsource = require('./jsonsource.js');
var winston = require('winston');

exports.startApp = function () {

  var optimist = sources.usages()
    .usage('$0: Http server and router for navigational data (NMEA 0183 & NMEA 2000)')
    .describe('u', 'Broadcast nmea 0183 via udp on port 7777')
    .describe('b', 'Broadcast address for udp broadcast')
    .describe('writejson', 'Write the internal json stream to [filename]')
    .describe('p', 'http port')
    .demand('boat')
    .describe('boat', 'boat configuration, loaded from lib/boats/ directory')
    .options('p', {default: 8080})
    .wrap(70);

  var argv = optimist.argv;

  if (argv.help) {
    optimist.showHelp();
    process.exit(0);
  }

  var server = require('http').createServer(function (request, response) {
    request.addListener('end',function () {
      new (require('node-static')).Server(__dirname + '/../webapp/').serve(request, response);
    }).resume();
  });
  server.listen(argv.p);

  var primus = new require('primus')(server, {
    parser: 'JSON'
  });

  var streamSources = sources.configure(argv);

  require('./boats/' + argv.boat + '.js').boat.configureStreams(streamSources);

  if (argv.u) {
    udp.create(streamSources.nmea.raw, argv);
  }

  if (argv.writejson) {
    jsonsource.startWriting(streamSources.nmea)
  }

  primus.on('connection', function (spark) {
      spark['unsubscribe'] = [];
      winston.info('Connect:' + JSON.stringify(spark.query));
      if (spark.query['pgn'] != undefined) {
        [].concat(spark.query['pgn']).map(function (pgn) {
          var stream = streamconfig.out.pgn.pgnStream(pgn);
          spark['unsubscribe'].push(stream.subscribe(function (event) {
            spark.write(event.value());
          }))
        });
      } else if (spark.query['gaugedata'] != undefined) {
        spark['unsubscribe'].push(streamSources.gaugeData.subscribe(function (event) {
          spark.write(event.value());
        }));
      } else {
        spark['unsubscribe'].push(streamSources.n2k.subscribe(function (event) {
          spark.write(event.value());
        }));
        spark['unsubscribe'].push(streamSources.nmea.json.subscribe(function (event) {
          spark.write(event.value());
        }));
      }

    }
  )
  ;

  primus.on('disconnection', function (spark) {
    spark['unsubscribe'].map(function (unsubscribeF) {
      unsubscribeF();
    });
  });
}

<|endoftext|>