<commit_before>// Copyright (c) 2012, Joyent, Inc. All rights reserved.

var fs = require('fs');
var os = require('os');

var assert = require('assert-plus');
var backoff = require('backoff');
var bunyan = require('bunyan');
var clone = require('clone');
var getopt = require('posix-getopt');
var vasync = require('vasync');
var zkplus = require('zkplus');

///--- Globals

var HOSTNAME = os.hostname();
var LOG = bunyan.createLogger({
        level: (process.env.LOG_LEVEL || 'info'),
        name: 'registrar',
        serializers: {
                err: bunyan.stdSerializers.err
        },
        stream: process.stdout
});

///--- CLI Helpers

function parseOptions() {
        var option;
        var opts = {};
        var parser = new getopt.BasicParser('vf:(file)', process.argv);

        while ((option = parser.getopt()) !== undefined) {
                switch (option.option) {
                case 'f':
                        opts.file = option.optarg;
                        break;

                case 'v':
                        // Allows us to set -vvv -> this little hackery
                        // just ensures that we're never < TRACE
                        LOG.level(Math.max(bunyan.TRACE, (LOG.level() - 10)));
                        if (LOG.level() <= bunyan.DEBUG)
                                LOG = LOG.child({src: true});
                        break;

                default:
                        console.error('invalid option: ' + option.option);
                        process.exit(1);
                        break;
                }
        }

        return (opts);
}

function readConfig(opts) {
        assert.object(opts, 'options');
        assert.string(opts.file, 'options.file');

        var cfg;
        var f = opts.file;
        var _file;
        try {
                _file = fs.readFileSync(f, 'utf8');
        } catch (e) {
                LOG.fatal(e, 'unable to read configuration %s', f);
                process.exit(1);
        }

        try {
                cfg = JSON.parse(_file);
        } catch (e) {
                LOG.fatal(e, 'invalid JSON in %s', f);
                process.exit(1);
        }

        LOG.info(cfg, 'configuration loaded from %s', f);

        return (cfg);
}

function usage(msg) {
        if (msg)
                console.error(msg);

        var str = 'usage: ' + require('path').basename(process.argv[1]);
        str += '[-v] [-f file]';
        console.error(str);
        process.exit(1);
}

///--- worker functions

function address() {
        var ifaces = os.networkInterfaces();
        var addrs = Object.keys(ifaces).filter(function (k) {
                return (!ifaces[k][0].internal);
        }).map(function (k) {
                return (ifaces[k][0]);
        });

        return (addrs[0].address);
}

function createZkClient(opts, cb) {
        assert.object(opts, 'options');
        assert.optionalNumber(opts.connectTimeout, 'options.connectTimeout');
        assert.arrayOfObject(opts.servers, 'options.servers');
        assert.number(opts.timeout, 'options.timeout');
        assert.func(cb, 'callback');

        assert.ok((opts.servers.length > 0), 'options.servers empty');
        for (var i = 0; i < opts.servers.length; i++) {
                assert.string(opts.servers[i].host, 'servers.host');
                assert.number(opts.servers[i].port, 'servers.port');
        }

        function _createClient(_, _cb) {
                var client = zkplus.createClient(opts);

                function onConnect() {
                        client.removeListener('error', onError);
                        LOG.info('zookeeper: connected');
                        _cb(null, client);
                }

                function onError(err) {
                        client.removeListener('connect', onConnect);
                        _cb(err);
                }

                client.once('connect', onConnect);
                client.once('error', onError);
        }

        var retry = backoff.call(_createClient, null, cb);
        retry.failAfter(Infinity);
        retry.setStrategy(new backoff.ExponentialStrategy({
                initialDelay: 1000,
                maxDelay: 30000
        }));

        retry.on('backoff', function (number, delay) {
                var level;
                if (number === 0) {
                        level = 'info';
                } else if (number < 5) {
                        level = 'warn';
                } else {
                        level = 'error';
                }
                LOG[level]({
                        attempt: number,
                        delay: delay
                }, 'zookeeper: connection attempted (failed)');
        });

        return (retry);
}

function domainToPath(domain) {
        assert.string(domain, 'domain');

        // 1.moray.sds.joyent.com) => /com/joyent/sds/moray/1
        return ('/' + domain.split('.').reverse().join('/'));
}

function heartbeat(zk, cb) {
        assert.object(zk, 'zkClient');
        assert.func(cb, 'callback');

        var path = domainToPath(CFG.registration.domain);

        LOG.debug({path: path}, 'heartbeat: entered');

        zk.stat(path, function (err, stat) {
                if (err) {
                        LOG.warn({
                                err: err,
                                path: path
                        }, 'heartbeat: failed');
                        cb(err);
                } else {
                        LOG.debug({path: path}, 'heartbeat: ok');
                        cb();
                }
        });
}

function registerSelf(opts, cb) {
        assert.object(opts, 'options');
        assert.object(opts.cfg, 'options.cfg');
        assert.string(opts.cfg.domain, 'options.cfg.domain');
        assert.string(opts.domain, 'options.domain');
        assert.object(opts.log, 'options.log');
        assert.string(opts.path, 'options.path');
        assert.object(opts.zk, 'options.zk');
        assert.func(cb, 'callback');

        var cfg = opts.cfg;
        var domain = opts.domain;
        var log = opts.log;
        var path = opts.path + '/' + HOSTNAME;
        var zk = opts.zk;

        log.debug({
                domain: domain,
                hostname: HOSTNAME,
                path: path
        }, 'registerSelf: entered');

        zk.mkdirp(opts.path, function (err) {
                if (err) {
                        log.error({
                                domain: domain,
                                hostname: HOSTNAME,
                                path: opts.path,
                                err: err
                        }, 'registerSelf: zk.mkdirp failed');
                        cb(err);
                        return;
                }

                log.debug({
                        domain: domain,
                        hostname: HOSTNAME,
                        path: opts.path
                }, 'registerSelf: zk.mkdirp done');

                var options = {
                        flags: ['ephemeral'],
                        object: {
                                type: cfg.type
                        }
                };
                options.object[cfg.type] = {
                        address: address()
                };
                if (typeof (cfg.ttl) === 'number')
                        options.object.ttl = cfg.ttl;

                zk.creat(path, options, function (err2) {
                        if (err2 && err2.code !== zkplus.ZNODEEXISTS) {
                                log.error({
                                        domain: domain,
                                        hostname: HOSTNAME,
                                        path: path,
                                        err: err
                                }, 'registerSelf: zk.creat failed');
                                cb(err2);
                                return;
                        }

                        log.info({
                                domain: domain,
                                hostname: HOSTNAME,
                                path: path,
                                data: options
                        }, 'registerSelf: done');
                        cb();
                });
        });
}

function registerService(opts, cb) {
        assert.object(opts, 'options');
        assert.object(opts.cfg, 'options.cfg');
        assert.string(opts.cfg.domain, 'options.cfg.domain');
        assert.string(opts.domain, 'options.domain');
        assert.object(opts.log, 'options.log');
        assert.string(opts.path, 'options.path');
        assert.object(opts.zk, 'options.zk');
        assert.func(cb, 'callback');

        if (!opts.cfg.service) {
                cb();
                return;
        }

        var cfg = opts.cfg;
        var domain = opts.cfg.domain;
        var log = opts.log;
        var path = opts.path;
        var zk = opts.zk;

        log.debug({
                domain: domain,
                path: path
        }, 'registerService: entered');

        var obj = {
                type: 'service',
                service: cfg.service
        };
        zk.update(path, obj, function (err) {
                if (err) {
                        log.error({
                                domain: domain,
                                path: path,
                                err: err
                        }, 'registerService: zk.update failed');
                        cb(err);
                } else {
                        log.debug({
                                domain: domain,
                                path: path
                        }, 'registerService: zk.update done');
                        cb();
                }
        });
}

function removeOldEntry(opts, cb) {
        assert.object(opts, 'options');
        assert.string(opts.domain, 'opts.domain');
        assert.object(opts.log, 'options.log');
        assert.string(opts.path, 'options.lopath');
        assert.object(opts.zk, 'options.zk');
        assert.func(cb, 'callback');

        var log = opts.log;
        var path = opts.path + '/' + HOSTNAME;
        var zk = opts.zk;

        log.debug({
                domain: opts.cfg.domain,
                path: path
        }, 'removeOldEntry: entered');

        zk.unlink(path, function (err) {
                if (err && err.code !== zkplus.ZNONODE) {
                        log.error({
                                domain: opts.domain,
                                err: err,
                                path: path
                        }, 'removeOldEntry: zk.unlink failed');
                        cb(err);
                } else {
                        log.debug({
                                domain: opts.domain,
                                path: path
                        }, 'removeOldEntry: done');
                        cb();
                }
        });
}

function register(opts) {
        assert.object(opts, 'options');
        assert.string(opts.domain, 'options.domain');
        assert.object(opts.registration, 'options.registration');
        assert.object(opts.zk, 'options.zk');

        var path = domainToPath(opts.domain);

        LOG.debug({
                domain: opts.domain,
                registration: opts.registration,
                path: path
        }, 'registering');

        // register $self in ZK depending on the type. We always
        // write a leadnode for ourselves, but we may need to additionally
        // set a service record.
        vasync.pipeline({
                arg: {
                        cfg: opts.registration,
                        domain: opts.domain,
                        log: LOG,
                        path: path,
                        zk: opts.zk
                },
                funcs: [
                        removeOldEntry,
                        function sleepForTickTime(_, cb) {
                                LOG.info('waiting for 1s');
                                setTimeout(cb.bind(null), 1000);
                        },
                        registerSelf,
                        registerService
                ]
        }, function (err) {
                if (err) {
                        LOG.error(err, 'unable to register in ZooKeeper');
                } else {
                        LOG.info('registered in ZooKeeper');
                }
        });
}

///--- Mainline

var ARGV = parseOptions();
var CFG = readConfig(ARGV);
CFG.zookeeper.log = LOG;

function onZooKeeperClient(zk_err, zk) {
        if (zk_err) {
                LOG.fatal(zk_err, 'unable to create ZooKeeper client');
                process.exit(1);
        }

        function cleanup(event, err) {
                LOG.error({
                        event: event,
                        err: err
                }, 'ZooKeeper session closure; restarting');
                clearInterval(t);
                zk.removeAllListeners('close');
                zk.removeAllListeners('error');
                zk.removeAllListeners('session_expired');
                zk.close();
                createZkClient(CFG.zookeeper, onZooKeeperClient);
        }

        zk.on('close', cleanup.bind(this, 'close'));
        zk.on('error', cleanup.bind(this, 'error'));
        zk.on('session_expired', cleanup.bind(this, 'session_expired'));

        var t = setInterval(function checkState() {
                heartbeat(zk, function (err) {
                        if (err) {
                                clearInterval(t);
                                zk.close();
                        }
                });
        }, ((CFG.zookeeper.timeout || 6000) / 2));

        register({
                domain: CFG.registration.domain,
                log: LOG,
                registration: CFG.registration,
                zk: zk
        });
}

createZkClient(CFG.zookeeper, onZooKeeperClient);
<commit_msg>MANTA-403: support explicit configuration of IP address<commit_after>// Copyright (c) 2012, Joyent, Inc. All rights reserved.

var fs = require('fs');
var os = require('os');

var assert = require('assert-plus');
var backoff = require('backoff');
var bunyan = require('bunyan');
var clone = require('clone');
var getopt = require('posix-getopt');
var vasync = require('vasync');
var zkplus = require('zkplus');

///--- Globals

var HOSTNAME = os.hostname();
var LOG = bunyan.createLogger({
        level: (process.env.LOG_LEVEL || 'info'),
        name: 'registrar',
        serializers: {
                err: bunyan.stdSerializers.err
        },
        stream: process.stdout
});

///--- CLI Helpers

function parseOptions() {
        var option;
        var opts = {};
        var parser = new getopt.BasicParser('vf:(file)', process.argv);

        while ((option = parser.getopt()) !== undefined) {
                switch (option.option) {
                case 'f':
                        opts.file = option.optarg;
                        break;

                case 'v':
                        // Allows us to set -vvv -> this little hackery
                        // just ensures that we're never < TRACE
                        LOG.level(Math.max(bunyan.TRACE, (LOG.level() - 10)));
                        if (LOG.level() <= bunyan.DEBUG)
                                LOG = LOG.child({src: true});
                        break;

                default:
                        console.error('invalid option: ' + option.option);
                        process.exit(1);
                        break;
                }
        }

        return (opts);
}

function readConfig(opts) {
        assert.object(opts, 'options');
        assert.string(opts.file, 'options.file');

        var cfg;
        var f = opts.file;
        var _file;
        try {
                _file = fs.readFileSync(f, 'utf8');
        } catch (e) {
                LOG.fatal(e, 'unable to read configuration %s', f);
                process.exit(1);
        }

        try {
                cfg = JSON.parse(_file);
        } catch (e) {
                LOG.fatal(e, 'invalid JSON in %s', f);
                process.exit(1);
        }

        LOG.info(cfg, 'configuration loaded from %s', f);

        return (cfg);
}

function usage(msg) {
        if (msg)
                console.error(msg);

        var str = 'usage: ' + require('path').basename(process.argv[1]);
        str += '[-v] [-f file]';
        console.error(str);
        process.exit(1);
}

///--- worker functions

function address() {
        if (CFG.adminIp)
                return (CFG.adminIp);

        var ifaces = os.networkInterfaces();
        var addrs = Object.keys(ifaces).filter(function (k) {
                return (!ifaces[k][0].internal);
        }).map(function (k) {
                return (ifaces[k][0]);
        });

        return (addrs[0].address);
}

function createZkClient(opts, cb) {
        assert.object(opts, 'options');
        assert.optionalNumber(opts.connectTimeout, 'options.connectTimeout');
        assert.arrayOfObject(opts.servers, 'options.servers');
        assert.number(opts.timeout, 'options.timeout');
        assert.func(cb, 'callback');

        assert.ok((opts.servers.length > 0), 'options.servers empty');
        for (var i = 0; i < opts.servers.length; i++) {
                assert.string(opts.servers[i].host, 'servers.host');
                assert.number(opts.servers[i].port, 'servers.port');
        }

        function _createClient(_, _cb) {
                var client = zkplus.createClient(opts);

                function onConnect() {
                        client.removeListener('error', onError);
                        LOG.info('zookeeper: connected');
                        _cb(null, client);
                }

                function onError(err) {
                        client.removeListener('connect', onConnect);
                        _cb(err);
                }

                client.once('connect', onConnect);
                client.once('error', onError);
        }

        var retry = backoff.call(_createClient, null, cb);
        retry.failAfter(Infinity);
        retry.setStrategy(new backoff.ExponentialStrategy({
                initialDelay: 1000,
                maxDelay: 30000
        }));

        retry.on('backoff', function (number, delay) {
                var level;
                if (number === 0) {
                        level = 'info';
                } else if (number < 5) {
                        level = 'warn';
                } else {
                        level = 'error';
                }
                LOG[level]({
                        attempt: number,
                        delay: delay
                }, 'zookeeper: connection attempted (failed)');
        });

        return (retry);
}

function domainToPath(domain) {
        assert.string(domain, 'domain');

        // 1.moray.sds.joyent.com) => /com/joyent/sds/moray/1
        return ('/' + domain.split('.').reverse().join('/'));
}

function heartbeat(zk, cb) {
        assert.object(zk, 'zkClient');
        assert.func(cb, 'callback');

        var path = domainToPath(CFG.registration.domain);

        LOG.debug({path: path}, 'heartbeat: entered');

        zk.stat(path, function (err, stat) {
                if (err) {
                        LOG.warn({
                                err: err,
                                path: path
                        }, 'heartbeat: failed');
                        cb(err);
                } else {
                        LOG.debug({path: path}, 'heartbeat: ok');
                        cb();
                }
        });
}

function registerSelf(opts, cb) {
        assert.object(opts, 'options');
        assert.object(opts.cfg, 'options.cfg');
        assert.string(opts.cfg.domain, 'options.cfg.domain');
        assert.string(opts.domain, 'options.domain');
        assert.object(opts.log, 'options.log');
        assert.string(opts.path, 'options.path');
        assert.object(opts.zk, 'options.zk');
        assert.func(cb, 'callback');

        var cfg = opts.cfg;
        var domain = opts.domain;
        var log = opts.log;
        var path = opts.path + '/' + HOSTNAME;
        var zk = opts.zk;

        log.debug({
                domain: domain,
                hostname: HOSTNAME,
                path: path
        }, 'registerSelf: entered');

        zk.mkdirp(opts.path, function (err) {
                if (err) {
                        log.error({
                                domain: domain,
                                hostname: HOSTNAME,
                                path: opts.path,
                                err: err
                        }, 'registerSelf: zk.mkdirp failed');
                        cb(err);
                        return;
                }

                log.debug({
                        domain: domain,
                        hostname: HOSTNAME,
                        path: opts.path
                }, 'registerSelf: zk.mkdirp done');

                var options = {
                        flags: ['ephemeral'],
                        object: {
                                type: cfg.type
                        }
                };
                options.object[cfg.type] = {
                        address: address()
                };
                if (typeof (cfg.ttl) === 'number')
                        options.object.ttl = cfg.ttl;

                zk.creat(path, options, function (err2) {
                        if (err2 && err2.code !== zkplus.ZNODEEXISTS) {
                                log.error({
                                        domain: domain,
                                        hostname: HOSTNAME,
                                        path: path,
                                        err: err
                                }, 'registerSelf: zk.creat failed');
                                cb(err2);
                                return;
                        }

                        log.info({
                                domain: domain,
                                hostname: HOSTNAME,
                                path: path,
                                data: options
                        }, 'registerSelf: done');
                        cb();
                });
        });
}

function registerService(opts, cb) {
        assert.object(opts, 'options');
        assert.object(opts.cfg, 'options.cfg');
        assert.string(opts.cfg.domain, 'options.cfg.domain');
        assert.string(opts.domain, 'options.domain');
        assert.object(opts.log, 'options.log');
        assert.string(opts.path, 'options.path');
        assert.object(opts.zk, 'options.zk');
        assert.func(cb, 'callback');

        if (!opts.cfg.service) {
                cb();
                return;
        }

        var cfg = opts.cfg;
        var domain = opts.cfg.domain;
        var log = opts.log;
        var path = opts.path;
        var zk = opts.zk;

        log.debug({
                domain: domain,
                path: path
        }, 'registerService: entered');

        var obj = {
                type: 'service',
                service: cfg.service
        };
        zk.update(path, obj, function (err) {
                if (err) {
                        log.error({
                                domain: domain,
                                path: path,
                                err: err
                        }, 'registerService: zk.update failed');
                        cb(err);
                } else {
                        log.debug({
                                domain: domain,
                                path: path
                        }, 'registerService: zk.update done');
                        cb();
                }
        });
}

function removeOldEntry(opts, cb) {
        assert.object(opts, 'options');
        assert.string(opts.domain, 'opts.domain');
        assert.object(opts.log, 'options.log');
        assert.string(opts.path, 'options.lopath');
        assert.object(opts.zk, 'options.zk');
        assert.func(cb, 'callback');

        var log = opts.log;
        var path = opts.path + '/' + HOSTNAME;
        var zk = opts.zk;

        log.debug({
                domain: opts.cfg.domain,
                path: path
        }, 'removeOldEntry: entered');

        zk.unlink(path, function (err) {
                if (err && err.code !== zkplus.ZNONODE) {
                        log.error({
                                domain: opts.domain,
                                err: err,
                                path: path
                        }, 'removeOldEntry: zk.unlink failed');
                        cb(err);
                } else {
                        log.debug({
                                domain: opts.domain,
                                path: path
                        }, 'removeOldEntry: done');
                        cb();
                }
        });
}

function register(opts) {
        assert.object(opts, 'options');
        assert.string(opts.domain, 'options.domain');
        assert.object(opts.registration, 'options.registration');
        assert.object(opts.zk, 'options.zk');

        var path = domainToPath(opts.domain);

        LOG.debug({
                domain: opts.domain,
                registration: opts.registration,
                path: path
        }, 'registering');

        // register $self in ZK depending on the type. We always
        // write a leadnode for ourselves, but we may need to additionally
        // set a service record.
        vasync.pipeline({
                arg: {
                        cfg: opts.registration,
                        domain: opts.domain,
                        log: LOG,
                        path: path,
                        zk: opts.zk
                },
                funcs: [
                        removeOldEntry,
                        function sleepForTickTime(_, cb) {
                                LOG.info('waiting for 1s');
                                setTimeout(cb.bind(null), 1000);
                        },
                        registerSelf,
                        registerService
                ]
        }, function (err) {
                if (err) {
                        LOG.error(err, 'unable to register in ZooKeeper');
                } else {
                        LOG.info('registered in ZooKeeper');
                }
        });
}

///--- Mainline

var ARGV = parseOptions();
var CFG = readConfig(ARGV);
CFG.zookeeper.log = LOG;

function onZooKeeperClient(zk_err, zk) {
        if (zk_err) {
                LOG.fatal(zk_err, 'unable to create ZooKeeper client');
                process.exit(1);
        }

        function cleanup(event, err) {
                LOG.error({
                        event: event,
                        err: err
                }, 'ZooKeeper session closure; restarting');
                clearInterval(t);
                zk.removeAllListeners('close');
                zk.removeAllListeners('error');
                zk.removeAllListeners('session_expired');
                zk.close();
                createZkClient(CFG.zookeeper, onZooKeeperClient);
        }

        zk.on('close', cleanup.bind(this, 'close'));
        zk.on('error', cleanup.bind(this, 'error'));
        zk.on('session_expired', cleanup.bind(this, 'session_expired'));

        var t = setInterval(function checkState() {
                heartbeat(zk, function (err) {
                        if (err) {
                                clearInterval(t);
                                zk.close();
                        }
                });
        }, ((CFG.zookeeper.timeout || 6000) / 2));

        register({
                domain: CFG.registration.domain,
                log: LOG,
                registration: CFG.registration,
                zk: zk
        });
}

createZkClient(CFG.zookeeper, onZooKeeperClient);
<|endoftext|>


<commit_before>const messages = {
    pt_BR: {
        mozilla_api_locale: "pt-BR",
        description: "pt_BR - Português do Brasil",
        message: {
            locale_picker: {
                txt_title: "Locale",
                txt_description: "Locale usado na interface e nas consultas"
            },
            search_panel: {
                txt_title:                  "Consulta",
                txt_keyword:                "Palavra chave",
                btn_search:                 "Pesquisar",
                txt_searching:              "Pesquisando...",
                error_missing_keyword:      "Digite uma palavra chave",
                error_connection_kitsune:   "Houve uma falha ao consultar a API do Kitsune, tente novamente."
            },
            result_panel: {
                // Pluralization format: String for 0 results | String for one result | String for 2 or more results
                txt_title:  "Nenhum resultado para '{keyword}' | Um resultado para '{keyword}' | {count} resultados para '{keyword}'"
            },
            result_table_header: {
                txt_title:      "Título",
                txt_summary:    "Resumo",
                txt_options:    "Opções"
            },
            result_table_row: {
                txt_action_view:        "Visualizar documento no Kitsune",
                txt_action_edit:        "Editar documento no Kitsune",
                txt_action_download:    "Download do documento como HTML"
            }
        }
    },
    en_US: {
        mozilla_api_locale: "en-US",
        description: "en_US - North American English",
        message: {
            locale_picker: {
                txt_title: "Locale",
                txt_description: "Locale used in interface and search"
            },
            search_panel: {
                txt_title:                  "Search",
                txt_keyword:                "Keyword",
                btn_search:                 "Search",
                txt_searching:              "Searching...",
                error_missing_keyword:      "Please enter a keyword",
                error_connection_kitsune:   "There was an error conecting to Kitsune, please try again."
            },
            result_panel: {
                // Pluralization format: String for 0 results | String for one result | String for 2 or more results
                txt_title:  "No results for '{keyword}' | Single result for '{keyword}' | {count} results for '{keyword}'"
            },
            result_table_header: {
                txt_title:      "Title",
                txt_summary:    "Summary",
                txt_options:    "Options"
            },
            result_table_row: {
                txt_action_view:        "View document on Kitsune",
                txt_action_edit:        "Edit document on Kitsune",
                txt_action_download:    "Download document as HTML"
            }
        }
    }
};<commit_msg>Conserta typo<commit_after>const messages = {
    pt_BR: {
        mozilla_api_locale: "pt-BR",
        description: "pt_BR - Português do Brasil",
        message: {
            locale_picker: {
                txt_title: "Locale",
                txt_description: "Locale usado na interface e nas consultas"
            },
            search_panel: {
                txt_title:                  "Consulta",
                txt_keyword:                "Palavra chave",
                btn_search:                 "Pesquisar",
                txt_searching:              "Pesquisando...",
                error_missing_keyword:      "Digite uma palavra chave",
                error_connection_kitsune:   "Houve uma falha ao consultar a API do Kitsune, tente novamente."
            },
            result_panel: {
                // Pluralization format: String for 0 results | String for one result | String for 2 or more results
                txt_title:  "Nenhum resultado para '{keyword}' | Um resultado para '{keyword}' | {count} resultados para '{keyword}'"
            },
            result_table_header: {
                txt_title:      "Título",
                txt_summary:    "Resumo",
                txt_options:    "Opções"
            },
            result_table_row: {
                txt_action_view:        "Visualizar documento no Kitsune",
                txt_action_edit:        "Editar documento no Kitsune",
                txt_action_download:    "Download do documento como HTML"
            }
        }
    },
    en_US: {
        mozilla_api_locale: "en-US",
        description: "en_US - North American English",
        message: {
            locale_picker: {
                txt_title: "Locale",
                txt_description: "Locale used in interface and search"
            },
            search_panel: {
                txt_title:                  "Search",
                txt_keyword:                "Keyword",
                btn_search:                 "Search",
                txt_searching:              "Searching...",
                error_missing_keyword:      "Please enter a keyword",
                error_connection_kitsune:   "There was an error connecting to Kitsune, please try again."
            },
            result_panel: {
                // Pluralization format: String for 0 results | String for one result | String for 2 or more results
                txt_title:  "No results for '{keyword}' | Single result for '{keyword}' | {count} results for '{keyword}'"
            },
            result_table_header: {
                txt_title:      "Title",
                txt_summary:    "Summary",
                txt_options:    "Options"
            },
            result_table_row: {
                txt_action_view:        "View document on Kitsune",
                txt_action_edit:        "Edit document on Kitsune",
                txt_action_download:    "Download document as HTML"
            }
        }
    }
};
<|endoftext|>


<commit_before>import isArray from '../../util/isArray'
import isString from '../../util/isString'
import EventEmitter from '../../util/EventEmitter'
import forEach from '../../util/forEach'
import NodeFactory from './NodeFactory'

/*
  A data storage implemention that supports data defined via a {@link Schema},
  and incremental updates which are backed by a OT library.

  It forms the underlying implementation for {@link Document}.
 */
class Data extends EventEmitter {

  /**
    @param {Schema} schema
    @param {Object} [options]
  */
  constructor(schema, options) {
    super()

    options = options || {}
    this.schema = schema
    this.nodes = {}
    this.indexes = {}
    this.options = options || {}

    this.nodeFactory = options.nodeFactory || new NodeFactory(schema.nodeRegistry)

    // Sometimes necessary to resolve issues with updating indexes in presence
    // of cyclic dependencies
    this.__QUEUE_INDEXING__ = false
    this.queue = []
  }

  /**
    Check if this storage contains a node with given id.

    @returns {bool} `true` if a node with id exists, `false` otherwise.
   */
  contains(id) {
    return Boolean(this.nodes[id])
  }

  /**
    Get a node or value via path.

    @param {String|String[]} path node id or path to property.
    @returns {Node|Object|Primitive|undefined} a Node instance, a value or undefined if not found.
   */
  get(path, strict) {
    let result = this._get(path)
    if (strict && result === undefined) {
      if (isString(path)) {
        throw new Error("Could not find node with id '"+path+"'.")
      } else if (!this.contains(path[0])) {
        throw new Error("Could not find node with id '"+path[0]+"'.")
      } else {
        throw new Error("Property for path '"+path+"' us undefined.")
      }
    }
    return result
  }

  _get(path) {
    if (!path) return undefined
    let result
    if (isString(path)) {
      result = this.nodes[path]
    } else if (path.length === 1) {
      result = this.nodes[path[0]]
    } else if (path.length > 1) {
      let context = this.nodes[path[0]]
      for (let i = 1; i < path.length-1; i++) {
        if (!context) return undefined
        context = context[path[i]]
      }
      if (!context) return undefined
      result = context[path[path.length-1]]
    }
    return result
  }

  /**
    Get the internal storage for nodes.

    @return The internal node storage.
   */
  getNodes() {
    return this.nodes
  }

  /**
    Create a node from the given data.

    @return {Node} The created node.
   */
  create(nodeData) {
    var node = this.nodeFactory.create(nodeData.type, nodeData)
    if (!node) {
      throw new Error('Illegal argument: could not create node for data:', nodeData)
    }
    if (this.contains(node.id)) {
      throw new Error("Node already exists: " + node.id)
    }
    if (!node.id || !node.type) {
      throw new Error("Node id and type are mandatory.")
    }
    this.nodes[node.id] = node

    var change = {
      type: 'create',
      node: node
    }

    if (this.__QUEUE_INDEXING__) {
      this.queue.push(change)
    } else {
      this._updateIndexes(change)
    }

    return node
  }

  /**
    Delete the node with given id.

    @param {String} nodeId
    @returns {Node} The deleted node.
   */
  delete(nodeId) {
    var node = this.nodes[nodeId]
    if (!node) return
    node.dispose()
    delete this.nodes[nodeId]

    var change = {
      type: 'delete',
      node: node,
    }

    if (this.__QUEUE_INDEXING__) {
      this.queue.push(change)
    } else {
      this._updateIndexes(change)
    }

    return node
  }

  /**
    Set a property to a new value.

    @param {Array} property path
    @param {Object} newValue
    @returns {Node} The deleted node.
   */
  set(path, newValue) {
    let node = this.get(path[0])
    let oldValue = this._set(path, newValue)
    var change = {
      type: 'set',
      node: node,
      path: path,
      newValue: newValue,
      oldValue: oldValue
    }
    if (this.__QUEUE_INDEXING__) {
      this.queue.push(change)
    } else {
      this._updateIndexes(change)
    }
    return oldValue
  }

  _set(path, newValue) {
    let oldValue
    if (path.length === 2) {
      oldValue = this.nodes[path[0]][path[1]]
      this.nodes[path[0]][path[1]] = newValue
    } else if (path.length === 3) {
      oldValue = this.nodes[path[0]][path[1]][path[2]]
      this.nodes[path[0]][path[1]][path[2]] = newValue
    } else {
      throw new Error('Path of length '+path.length+' not supported.')
    }
    return oldValue
  }

  /**
    Update a property incrementally.

    @param {Array} property path
    @param {Object} diff
    @returns {any} The value before applying the update.
  */
  update(path, diff) {
    var realPath = this.getRealPath(path)
    if (!realPath) {
      console.error('Could not resolve path', path)
      return
    }
    let node = this.get(realPath[0])
    let oldValue = this._get(realPath)
    let newValue
    if (diff.isOperation) {
      newValue = diff.apply(oldValue)
    } else {
      diff = this._normalizeDiff(oldValue, diff)
      if (isString(oldValue)) {
        switch (diff.type) {
          case 'delete': {
            newValue = oldValue.split('').splice(diff.start, diff.end-diff.start).join('')
            break
          }
          case 'insert': {
            newValue = [oldValue.substring(0, diff.start), diff.text, oldValue.substring(diff.start)].join('')
            break
          }
          default:
            throw new Error('Unknown diff type')
        }
      } else if (isArray(oldValue)) {
        newValue = oldValue.slice(0)
        switch (diff.type) {
          case 'delete': {
            newValue.splice(diff.pos, 1)
            break
          }
          case 'insert': {
            newValue.splice(diff.pos, 0, diff.value)
            break
          }
          default:
            throw new Error('Unknown diff type')
        }
      } else if (oldValue._isCoordinate) {
        switch (diff.type) {
          case 'shift': {
            // ATTENTION: in this case we do not want to create a new value
            oldValue = { path: oldValue.path, offset: oldValue.offset }
            newValue = oldValue
            newValue.offset += diff.value
            break
          }
          default:
            throw new Error('Unknown diff type')
        }
      } else {
        throw new Error('Diff is not supported:', JSON.stringify(diff))
      }
    }
    this._set(realPath, newValue)

    var change = {
      type: 'update',
      node: node,
      path: realPath,
      newValue: newValue,
      oldValue: oldValue
    }

    if (this.__QUEUE_INDEXING__) {
      this.queue.push(change)
    } else {
      this._updateIndexes(change)
    }

    return oldValue
  }

  // normalize to support legacy formats
  _normalizeDiff(value, diff) {
    if (isString(value)) {
      // legacy
      if (diff['delete']) {
        console.warn('DEPRECATED: use doc.update(path, {type:"delete", start:s, end: e}) instead')
        diff = {
          type: 'delete',
          start: diff['delete'].start,
          end: diff['delete'].end
        }
      } else if (diff['insert']) {
        console.warn('DEPRECATED: use doc.update(path, {type:"insert", start:s, text: t}) instead')
        diff = {
          type: 'insert',
          start: diff['insert'].offset,
          text: diff['insert'].value
        }
      }
    } else if (isArray(value)) {
      // legacy
      if (diff['delete']) {
        console.warn('DEPRECATED: use doc.update(path, {type:"delete", pos:1}) instead')
        diff = {
          type: 'delete',
          pos: diff['delete'].offset
        }
      } else if (diff['insert']) {
        console.warn('DEPRECATED: use doc.update(path, {type:"insert", pos:1, value: "foo"}) instead')
        diff = {
          type: 'insert',
          pos: diff['insert'].offset,
          value: diff['insert'].value
        }
      }
    } else if (value._isCoordinate) {
      if (diff.hasOwnProperty('shift')) {
        console.warn('DEPRECATED: use doc.update(path, {type:"shift", value:2}) instead')
        diff = {
          type: 'shift',
          value: diff['shift']
        }
      }
    }
    return diff
  }

  /*
    DEPRECATED: We moved away from having JSON as first-class exchange format.
    We will remove this soon.

    @internal
    @deprecated
   */
  toJSON() {
    let nodes = {}
    forEach(this.nodes, (node)=>{
      nodes[node.id] = node.toJSON()
    })
    return {
      schema: [this.schema.id, this.schema.version],
      nodes: nodes
    }
  }

  /**
    Clear nodes.

    @internal
   */
  reset() {
    this.nodes.clear()
  }

  /**
    Add a node index.

    @param {String} name
    @param {NodeIndex} index
   */
  addIndex(name, index) {
    if (this.indexes[name]) {
      console.error('Index with name %s already exists.', name)
    }
    index.reset(this)
    this.indexes[name] = index
    return index
  }

  /**
    Get the node index with given name.

    @param {String} name
    @returns {NodeIndex} The node index.
   */
  getIndex(name) {
    return this.indexes[name]
  }

  /**
    Update a node index by providing of change object.

    @param {Object} change
   */
  _updateIndexes(change) {
    if (!change || this.__QUEUE_INDEXING__) return
    forEach(this.indexes, function(index) {
      if (index.select(change.node)) {
        if (!index[change.type]) {
          console.error('Contract: every NodeIndex must implement ' + change.type)
        }
        index[change.type](change.node, change.path, change.newValue, change.oldValue)
      }
    })
  }

  /**
    Stops indexing process, all changes will be collected in indexing queue.

    @private
  */
  _stopIndexing() {
    this.__QUEUE_INDEXING__ = true
  }

  /**
    Update all index changes from indexing queue.

    @private
  */
  _startIndexing() {
    this.__QUEUE_INDEXING__ = false
    while(this.queue.length >0) {
      var change = this.queue.shift()
      this._updateIndexes(change)
    }
  }

}

export default Data
<commit_msg>Fixed Data.set()<commit_after>import isArray from '../../util/isArray'
import isString from '../../util/isString'
import EventEmitter from '../../util/EventEmitter'
import forEach from '../../util/forEach'
import NodeFactory from './NodeFactory'

/*
  A data storage implemention that supports data defined via a {@link Schema},
  and incremental updates which are backed by a OT library.

  It forms the underlying implementation for {@link Document}.
 */
class Data extends EventEmitter {

  /**
    @param {Schema} schema
    @param {Object} [options]
  */
  constructor(schema, options) {
    super()

    options = options || {}
    this.schema = schema
    this.nodes = {}
    this.indexes = {}
    this.options = options || {}

    this.nodeFactory = options.nodeFactory || new NodeFactory(schema.nodeRegistry)

    // Sometimes necessary to resolve issues with updating indexes in presence
    // of cyclic dependencies
    this.__QUEUE_INDEXING__ = false
    this.queue = []
  }

  /**
    Check if this storage contains a node with given id.

    @returns {bool} `true` if a node with id exists, `false` otherwise.
   */
  contains(id) {
    return Boolean(this.nodes[id])
  }

  /**
    Get a node or value via path.

    @param {String|String[]} path node id or path to property.
    @returns {Node|Object|Primitive|undefined} a Node instance, a value or undefined if not found.
   */
  get(path, strict) {
    let result = this._get(path)
    if (strict && result === undefined) {
      if (isString(path)) {
        throw new Error("Could not find node with id '"+path+"'.")
      } else if (!this.contains(path[0])) {
        throw new Error("Could not find node with id '"+path[0]+"'.")
      } else {
        throw new Error("Property for path '"+path+"' us undefined.")
      }
    }
    return result
  }

  _get(path) {
    if (!path) return undefined
    let result
    if (isString(path)) {
      result = this.nodes[path]
    } else if (path.length === 1) {
      result = this.nodes[path[0]]
    } else if (path.length > 1) {
      let context = this.nodes[path[0]]
      for (let i = 1; i < path.length-1; i++) {
        if (!context) return undefined
        context = context[path[i]]
      }
      if (!context) return undefined
      result = context[path[path.length-1]]
    }
    return result
  }

  /**
    Get the internal storage for nodes.

    @return The internal node storage.
   */
  getNodes() {
    return this.nodes
  }

  /**
    Create a node from the given data.

    @return {Node} The created node.
   */
  create(nodeData) {
    var node = this.nodeFactory.create(nodeData.type, nodeData)
    if (!node) {
      throw new Error('Illegal argument: could not create node for data:', nodeData)
    }
    if (this.contains(node.id)) {
      throw new Error("Node already exists: " + node.id)
    }
    if (!node.id || !node.type) {
      throw new Error("Node id and type are mandatory.")
    }
    this.nodes[node.id] = node

    var change = {
      type: 'create',
      node: node
    }

    if (this.__QUEUE_INDEXING__) {
      this.queue.push(change)
    } else {
      this._updateIndexes(change)
    }

    return node
  }

  /**
    Delete the node with given id.

    @param {String} nodeId
    @returns {Node} The deleted node.
   */
  delete(nodeId) {
    var node = this.nodes[nodeId]
    if (!node) return
    node.dispose()
    delete this.nodes[nodeId]

    var change = {
      type: 'delete',
      node: node,
    }

    if (this.__QUEUE_INDEXING__) {
      this.queue.push(change)
    } else {
      this._updateIndexes(change)
    }

    return node
  }

  /**
    Set a property to a new value.

    @param {Array} property path
    @param {Object} newValue
    @returns {Node} The deleted node.
   */
  set(path, newValue) {
    let node = this.get(path[0])
    let oldValue = this._set(path, newValue)
    var change = {
      type: 'set',
      node: node,
      path: path,
      newValue: newValue,
      oldValue: oldValue
    }
    if (this.__QUEUE_INDEXING__) {
      this.queue.push(change)
    } else {
      this._updateIndexes(change)
    }
    return oldValue
  }

  _set(path, newValue) {
    let oldValue = _setValue(this.nodes, path, newValue)
    return oldValue
  }

  /**
    Update a property incrementally.

    @param {Array} property path
    @param {Object} diff
    @returns {any} The value before applying the update.
  */
  update(path, diff) {
    var realPath = this.getRealPath(path)
    if (!realPath) {
      console.error('Could not resolve path', path)
      return
    }
    let node = this.get(realPath[0])
    let oldValue = this._get(realPath)
    let newValue
    if (diff.isOperation) {
      newValue = diff.apply(oldValue)
    } else {
      diff = this._normalizeDiff(oldValue, diff)
      if (isString(oldValue)) {
        switch (diff.type) {
          case 'delete': {
            newValue = oldValue.split('').splice(diff.start, diff.end-diff.start).join('')
            break
          }
          case 'insert': {
            newValue = [oldValue.substring(0, diff.start), diff.text, oldValue.substring(diff.start)].join('')
            break
          }
          default:
            throw new Error('Unknown diff type')
        }
      } else if (isArray(oldValue)) {
        newValue = oldValue.slice(0)
        switch (diff.type) {
          case 'delete': {
            newValue.splice(diff.pos, 1)
            break
          }
          case 'insert': {
            newValue.splice(diff.pos, 0, diff.value)
            break
          }
          default:
            throw new Error('Unknown diff type')
        }
      } else if (oldValue._isCoordinate) {
        switch (diff.type) {
          case 'shift': {
            // ATTENTION: in this case we do not want to create a new value
            oldValue = { path: oldValue.path, offset: oldValue.offset }
            newValue = oldValue
            newValue.offset += diff.value
            break
          }
          default:
            throw new Error('Unknown diff type')
        }
      } else {
        throw new Error('Diff is not supported:', JSON.stringify(diff))
      }
    }
    this._set(realPath, newValue)

    var change = {
      type: 'update',
      node: node,
      path: realPath,
      newValue: newValue,
      oldValue: oldValue
    }

    if (this.__QUEUE_INDEXING__) {
      this.queue.push(change)
    } else {
      this._updateIndexes(change)
    }

    return oldValue
  }

  // normalize to support legacy formats
  _normalizeDiff(value, diff) {
    if (isString(value)) {
      // legacy
      if (diff['delete']) {
        console.warn('DEPRECATED: use doc.update(path, {type:"delete", start:s, end: e}) instead')
        diff = {
          type: 'delete',
          start: diff['delete'].start,
          end: diff['delete'].end
        }
      } else if (diff['insert']) {
        console.warn('DEPRECATED: use doc.update(path, {type:"insert", start:s, text: t}) instead')
        diff = {
          type: 'insert',
          start: diff['insert'].offset,
          text: diff['insert'].value
        }
      }
    } else if (isArray(value)) {
      // legacy
      if (diff['delete']) {
        console.warn('DEPRECATED: use doc.update(path, {type:"delete", pos:1}) instead')
        diff = {
          type: 'delete',
          pos: diff['delete'].offset
        }
      } else if (diff['insert']) {
        console.warn('DEPRECATED: use doc.update(path, {type:"insert", pos:1, value: "foo"}) instead')
        diff = {
          type: 'insert',
          pos: diff['insert'].offset,
          value: diff['insert'].value
        }
      }
    } else if (value._isCoordinate) {
      if (diff.hasOwnProperty('shift')) {
        console.warn('DEPRECATED: use doc.update(path, {type:"shift", value:2}) instead')
        diff = {
          type: 'shift',
          value: diff['shift']
        }
      }
    }
    return diff
  }

  /*
    DEPRECATED: We moved away from having JSON as first-class exchange format.
    We will remove this soon.

    @internal
    @deprecated
   */
  toJSON() {
    let nodes = {}
    forEach(this.nodes, (node)=>{
      nodes[node.id] = node.toJSON()
    })
    return {
      schema: [this.schema.id, this.schema.version],
      nodes: nodes
    }
  }

  /**
    Clear nodes.

    @internal
   */
  reset() {
    this.nodes.clear()
  }

  /**
    Add a node index.

    @param {String} name
    @param {NodeIndex} index
   */
  addIndex(name, index) {
    if (this.indexes[name]) {
      console.error('Index with name %s already exists.', name)
    }
    index.reset(this)
    this.indexes[name] = index
    return index
  }

  /**
    Get the node index with given name.

    @param {String} name
    @returns {NodeIndex} The node index.
   */
  getIndex(name) {
    return this.indexes[name]
  }

  /**
    Update a node index by providing of change object.

    @param {Object} change
   */
  _updateIndexes(change) {
    if (!change || this.__QUEUE_INDEXING__) return
    forEach(this.indexes, function(index) {
      if (index.select(change.node)) {
        if (!index[change.type]) {
          console.error('Contract: every NodeIndex must implement ' + change.type)
        }
        index[change.type](change.node, change.path, change.newValue, change.oldValue)
      }
    })
  }

  /**
    Stops indexing process, all changes will be collected in indexing queue.

    @private
  */
  _stopIndexing() {
    this.__QUEUE_INDEXING__ = true
  }

  /**
    Update all index changes from indexing queue.

    @private
  */
  _startIndexing() {
    this.__QUEUE_INDEXING__ = false
    while(this.queue.length >0) {
      var change = this.queue.shift()
      this._updateIndexes(change)
    }
  }

}

function _setValue(root, path, newValue) {
  let ctx = root
  let L = path.length
  for (let i = 0; i < L-1; i++) {
    ctx = ctx[path[i]]
    if (!ctx) throw new Error('Can not set value.')
  }
  let oldValue = ctx[path[L-1]]
  ctx[path[L-1]] = newValue
  return oldValue
}

export default Data
<|endoftext|>


<commit_before>/**
 * @author  John Resig <jeresig@gmail.com>
 * @author  Originally by Marcus Spiegel <marcus.spiegel@gmail.com>
 * @link    https://github.com/jeresig/i18n-node
 * @license http://opensource.org/licenses/MIT
 *
 * @version 0.4.4
 */

// dependencies
var vsprintf = require("sprintf").vsprintf,
	fs = require("fs"),
	path = require("path");

var i18n = module.exports = function(opt) {
	var self = this;

	// Put into dev or production mode
	this.devMode = process.env.NODE_ENV !== "production";

	// Copy over options
	for (var prop in opt) {
		this[prop] = opt[prop];
	}

	// you may register helpers in global scope, up to you
	if (typeof this.register === "object") {
		i18n.registerMethods.forEach(function(method) {
			self.register[method] = self[method].bind(self);
		});
	}

	// implicitly read all locales
	// if it's an array of locale names, read in the data
	if (opt.locales && opt.locales.forEach) {
		this.locales = {};

		opt.locales.forEach(function(locale) {
			self.readFile(locale);
		});

		this.defaultLocale = opt.locales[0];
	}

	// Set the locale to the default locale
	this.setLocale(this.defaultLocale);

	// Check the defaultLocale
	if (!this.locales[this.defaultLocale]) {
		console.error("Not a valid default locale.");
	}

	if (this.request) {
		if (this.subdomain) {
			this.setLocaleFromSubdomain(this.request);
		}

		if (this.query !== false) {
			this.setLocaleFromQuery(this.request);
		}

		this.prefLocale = this.preferredLocale();
	}
};

i18n.version = "0.4.4";

i18n.localeCache = {};
i18n.resMethods = ["__", "__n", "getLocale", "isPreferredLocale"];

i18n.expressBind = function(app, opt) {
	if (!app) {
		return;
	}

	app.use(function(req, res, next) {
		opt.request = req;
		req.i18n = new i18n(opt);

		// Express 3
		if (res.locals) {
			i18n.registerMethods(res.locals, req)
		}

		next();
	});

	// Express 2
	if (app.dynamicHelpers) {
		app.dynamicHelpers(i18n.registerMethods({}));
	}
};

i18n.registerMethods = function(helpers, req) {
	i18n.resMethods.forEach(function(method) {
		if (req) {
			helpers[method]	= req.i18n[method].bind(req.i18n);
		} else {
			helpers[method] = function(req) {
				return req.i18n[method].bind(req.i18n);
			};
		}

	});

	return helpers;
};

i18n.prototype = {
	defaultLocale: "en",
	extension: ".js",
	directory: "./locales",
	cookiename: "lang",

	__: function() {
		var msg = this.translate(this.locale, arguments[0]);

		if (arguments.length > 1) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 1));
		}

		return msg;
	},

	__n: function(singular, plural, count) {
		var msg = this.translate(this.locale, singular, plural);

		msg = vsprintf(parseInt(count, 10) > 1 ? msg.other : msg.one, [count]);

		if (arguments.length > 3) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 3));
		}

		return msg;
	},

	setLocale: function(locale) {

		if (!locale) return;

		if (!this.locales[locale]) {
			if (this.devMode) {
				console.warn("Locale (" + locale + ") not found.");
			}

			locale = this.defaultLocale;
		}

		return (this.locale = locale);
	},

	getLocale: function() {
		return this.locale;
	},

	isPreferredLocale: function() {
		return !this.prefLocale ||
			this.prefLocale === this.getLocale();
	},

	setLocaleFromQuery: function(req) {
		req = req || this.request;

		if (!req || !req.query || !req.query.lang) {
			return;
		}

		var locale = req.query.lang.toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from query: " + locale);
			}

			this.setLocale(locale);
		}
	},

	setLocaleFromSubdomain: function(req) {
		req = req || this.request;

		if (!req || !req.headers || !req.headers.host) {
			return;
		}

		if (/^([^.]+)/.test(req.headers.host) && this.locales[RegExp.$1]) {
			if (this.devMode) {
				console.log("Overriding locale from host: " + RegExp.$1);
			}

			this.setLocale(RegExp.$1);
		}
	},

	setLocaleFromCookie: function(req) {
		req = req || this.request;

		if (!req || !req.cookies || !this.cookiename || !req.cookies[this.cookiename]) {
			return;
		}

		var locale = req.cookies[this.cookiename].toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from cookie: " + locale);
			}

			this.setLocale(locale);
		}
	},

	preferredLocale: function(req) {
		req = req || this.request;

		if (!req || !req.headers) {
			return;
		}

		var accept = req.headers["accept-language"] || "",
			self = this,
			prefLocale = this.defaultLocale;

		(accept.match(/(^|,\s*)([a-z]+)/g) || []).forEach(function(locale) {
			if (!prefLocale && self.locales[locale]) {
				prefLocale = locale;
			}
		});

		return prefLocale;
	},

	// read locale file, translate a msg and write to fs if new
	translate: function(locale, singular, plural) {
		if (!locale || !this.locales[locale]) {
			if (this.devMode) {
				console.warn("WARN: No locale found. Using the default (" +
					this.defaultLocale + ") as current locale");
			}

			locale = this.defaultLocale;

			this.initLocale(locale, {});
		}

		if (!this.locales[locale][singular]) {
			this.locales[locale][singular] = plural ?
				{ one: singular, other: plural } :
				singular;

			if (this.devMode) {
				this.writeFile(locale);
			}
		}

		return this.locales[locale][singular];
	},

	// try reading a file
	readFile: function(locale) {
		var file = this.locateFile(locale);

		if (!this.devMode && i18n.localeCache[file]) {
			this.initLocale(locale, i18n.localeCache[file]);
			return;
		}

		try {
			var localeFile = fs.readFileSync(file);

			try {
				// parsing filecontents to locales[locale]
				this.initLocale(locale, JSON.parse(localeFile));

			} catch (e) {
				console.error('unable to parse locales from file (maybe ' + file +
					' is empty or invalid json?): ', e);
			}

		} catch (e) {
			// unable to read, so intialize that file
			// locales[locale] are already set in memory, so no extra read required
			// or locales[locale] are empty, which initializes an empty locale.json file
			this.writeFile(locale);
		}
	},

	// try writing a file in a created directory
	writeFile: function(locale) {
		// don't write new locale information to disk if we're not in dev mode
		if (!this.devMode) {
			// Initialize the locale if didn't exist already
			this.initLocale(locale, {});
		}

		// creating directory if necessary
		try {
			fs.lstatSync(this.directory);

		} catch (e) {
			if (this.devMode) {
				console.log('creating locales dir in: ' + this.directory);
			}

			fs.mkdirSync(this.directory, 0755);
		}

		// Initialize the locale if didn't exist already
		this.initLocale(locale, {});

		// writing to tmp and rename on success
		try {
			var target = this.locateFile(locale),
				tmp = target + ".tmp";

			fs.writeFileSync(tmp, JSON.stringify(
				this.locales[locale], null, "\t"), "utf8");

			if (fs.statSync(tmp).isFile()) {
				fs.renameSync(tmp, target);

			} else {
				console.error('unable to write locales to file (either ' + tmp +
					' or ' + target + ' are not writeable?): ');
			}

		} catch (e) {
			console.error('unexpected error writing files (either ' + tmp +
				' or ' + target + ' are not writeable?): ', e);
		}
	},

	// basic normalization of filepath
	locateFile: function(locale) {
		return path.normalize(this.directory + '/' + locale + this.extension);
	},

	initLocale: function(locale, data) {
		if (!this.locales[locale]) {
			this.locales[locale] = data;

			// Only cache the files when we're not in dev mode
			if (!this.devMode) {
			    var file = this.locateFile(locale);
				if ( !i18n.localeCache[file] ) {
			    	i18n.localeCache[file] = data;
				}
			}
		}
	}
};
<commit_msg>Fix bug with defaultLocale for preferredLocale.<commit_after>/**
 * @author  John Resig <jeresig@gmail.com>
 * @author  Originally by Marcus Spiegel <marcus.spiegel@gmail.com>
 * @link    https://github.com/jeresig/i18n-node
 * @license http://opensource.org/licenses/MIT
 *
 * @version 0.4.4
 */

// dependencies
var vsprintf = require("sprintf").vsprintf,
	fs = require("fs"),
	path = require("path");

var i18n = module.exports = function(opt) {
	var self = this;

	// Put into dev or production mode
	this.devMode = process.env.NODE_ENV !== "production";

	// Copy over options
	for (var prop in opt) {
		this[prop] = opt[prop];
	}

	// you may register helpers in global scope, up to you
	if (typeof this.register === "object") {
		i18n.registerMethods.forEach(function(method) {
			self.register[method] = self[method].bind(self);
		});
	}

	// implicitly read all locales
	// if it's an array of locale names, read in the data
	if (opt.locales && opt.locales.forEach) {
		this.locales = {};

		opt.locales.forEach(function(locale) {
			self.readFile(locale);
		});

		this.defaultLocale = opt.locales[0];
	}

	// Set the locale to the default locale
	this.setLocale(this.defaultLocale);

	// Check the defaultLocale
	if (!this.locales[this.defaultLocale]) {
		console.error("Not a valid default locale.");
	}

	if (this.request) {
		if (this.subdomain) {
			this.setLocaleFromSubdomain(this.request);
		}

		if (this.query !== false) {
			this.setLocaleFromQuery(this.request);
		}

		this.prefLocale = this.preferredLocale();
	}
};

i18n.version = "0.4.4";

i18n.localeCache = {};
i18n.resMethods = ["__", "__n", "getLocale", "isPreferredLocale"];

i18n.expressBind = function(app, opt) {
	if (!app) {
		return;
	}

	app.use(function(req, res, next) {
		opt.request = req;
		req.i18n = new i18n(opt);

		// Express 3
		if (res.locals) {
			i18n.registerMethods(res.locals, req)
		}

		next();
	});

	// Express 2
	if (app.dynamicHelpers) {
		app.dynamicHelpers(i18n.registerMethods({}));
	}
};

i18n.registerMethods = function(helpers, req) {
	i18n.resMethods.forEach(function(method) {
		if (req) {
			helpers[method]	= req.i18n[method].bind(req.i18n);
		} else {
			helpers[method] = function(req) {
				return req.i18n[method].bind(req.i18n);
			};
		}

	});

	return helpers;
};

i18n.prototype = {
	defaultLocale: "en",
	extension: ".js",
	directory: "./locales",
	cookiename: "lang",

	__: function() {
		var msg = this.translate(this.locale, arguments[0]);

		if (arguments.length > 1) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 1));
		}

		return msg;
	},

	__n: function(singular, plural, count) {
		var msg = this.translate(this.locale, singular, plural);

		msg = vsprintf(parseInt(count, 10) > 1 ? msg.other : msg.one, [count]);

		if (arguments.length > 3) {
			msg = vsprintf(msg, Array.prototype.slice.call(arguments, 3));
		}

		return msg;
	},

	setLocale: function(locale) {

		if (!locale) return;

		if (!this.locales[locale]) {
			if (this.devMode) {
				console.warn("Locale (" + locale + ") not found.");
			}

			locale = this.defaultLocale;
		}

		return (this.locale = locale);
	},

	getLocale: function() {
		return this.locale;
	},

	isPreferredLocale: function() {
		return !this.prefLocale ||
			this.prefLocale === this.getLocale();
	},

	setLocaleFromQuery: function(req) {
		req = req || this.request;

		if (!req || !req.query || !req.query.lang) {
			return;
		}

		var locale = req.query.lang.toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from query: " + locale);
			}

			this.setLocale(locale);
		}
	},

	setLocaleFromSubdomain: function(req) {
		req = req || this.request;

		if (!req || !req.headers || !req.headers.host) {
			return;
		}

		if (/^([^.]+)/.test(req.headers.host) && this.locales[RegExp.$1]) {
			if (this.devMode) {
				console.log("Overriding locale from host: " + RegExp.$1);
			}

			this.setLocale(RegExp.$1);
		}
	},

	setLocaleFromCookie: function(req) {
		req = req || this.request;

		if (!req || !req.cookies || !this.cookiename || !req.cookies[this.cookiename]) {
			return;
		}

		var locale = req.cookies[this.cookiename].toLowerCase();

		if (this.locales[locale]) {
			if (this.devMode) {
				console.log("Overriding locale from cookie: " + locale);
			}

			this.setLocale(locale);
		}
	},

	preferredLocale: function(req) {
		req = req || this.request;

		if (!req || !req.headers) {
			return;
		}

		var accept = req.headers["accept-language"] || "",
			self = this,
			prefLocale;

		(accept.match(/(^|,\s*)([a-z]+)/g) || []).forEach(function(locale) {
			if (!prefLocale && self.locales[locale]) {
				prefLocale = locale;
			}
		});

		return prefLocale || this.defaultLocale;
	},

	// read locale file, translate a msg and write to fs if new
	translate: function(locale, singular, plural) {
		if (!locale || !this.locales[locale]) {
			if (this.devMode) {
				console.warn("WARN: No locale found. Using the default (" +
					this.defaultLocale + ") as current locale");
			}

			locale = this.defaultLocale;

			this.initLocale(locale, {});
		}

		if (!this.locales[locale][singular]) {
			this.locales[locale][singular] = plural ?
				{ one: singular, other: plural } :
				singular;

			if (this.devMode) {
				this.writeFile(locale);
			}
		}

		return this.locales[locale][singular];
	},

	// try reading a file
	readFile: function(locale) {
		var file = this.locateFile(locale);

		if (!this.devMode && i18n.localeCache[file]) {
			this.initLocale(locale, i18n.localeCache[file]);
			return;
		}

		try {
			var localeFile = fs.readFileSync(file);

			try {
				// parsing filecontents to locales[locale]
				this.initLocale(locale, JSON.parse(localeFile));

			} catch (e) {
				console.error('unable to parse locales from file (maybe ' + file +
					' is empty or invalid json?): ', e);
			}

		} catch (e) {
			// unable to read, so intialize that file
			// locales[locale] are already set in memory, so no extra read required
			// or locales[locale] are empty, which initializes an empty locale.json file
			this.writeFile(locale);
		}
	},

	// try writing a file in a created directory
	writeFile: function(locale) {
		// don't write new locale information to disk if we're not in dev mode
		if (!this.devMode) {
			// Initialize the locale if didn't exist already
			this.initLocale(locale, {});
		}

		// creating directory if necessary
		try {
			fs.lstatSync(this.directory);

		} catch (e) {
			if (this.devMode) {
				console.log('creating locales dir in: ' + this.directory);
			}

			fs.mkdirSync(this.directory, 0755);
		}

		// Initialize the locale if didn't exist already
		this.initLocale(locale, {});

		// writing to tmp and rename on success
		try {
			var target = this.locateFile(locale),
				tmp = target + ".tmp";

			fs.writeFileSync(tmp, JSON.stringify(
				this.locales[locale], null, "\t"), "utf8");

			if (fs.statSync(tmp).isFile()) {
				fs.renameSync(tmp, target);

			} else {
				console.error('unable to write locales to file (either ' + tmp +
					' or ' + target + ' are not writeable?): ');
			}

		} catch (e) {
			console.error('unexpected error writing files (either ' + tmp +
				' or ' + target + ' are not writeable?): ', e);
		}
	},

	// basic normalization of filepath
	locateFile: function(locale) {
		return path.normalize(this.directory + '/' + locale + this.extension);
	},

	initLocale: function(locale, data) {
		if (!this.locales[locale]) {
			this.locales[locale] = data;

			// Only cache the files when we're not in dev mode
			if (!this.devMode) {
			    var file = this.locateFile(locale);
				if ( !i18n.localeCache[file] ) {
			    	i18n.localeCache[file] = data;
				}
			}
		}
	}
};
<|endoftext|>


<commit_before>'use strict';

let five = require("johnny-five");

let board = new five.Board();

board.on("ready", function() {

  let led = new five.Led(13);

  led.strobe(1000);

  // Make led available in repl
  this.repl.inject({
    led: led
  });

  // try "on", "off", "toggle", "strobe", "stop" (stops strobing)
});
<commit_msg>red n green<commit_after>'use strict';

let five = require("johnny-five");

let board = new five.Board();

board.on("ready", function() {

  let green = new five.Led(13);
  let red = new five.Led(10);

  console.log('strobing');
  green.strobe(1000);
  red.strobe(500);

  // Make leds available in repl
  this.repl.inject({
    green: green,
    red: red,
  });

  // try "on", "off", "toggle", "strobe", "stop" (stops strobing)
});
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Jonathan Rowny. All rights reserved.
 * http://www.jonathanrowny.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, brackets, $, window */

define(function (require, exports, module) {
    'use strict';
    var Commands                = brackets.getModule("command/Commands"),
        CommandManager          = brackets.getModule("command/CommandManager"),
        EditorManager           = brackets.getModule("editor/EditorManager"),
        DocumentManager         = brackets.getModule("document/DocumentManager"),
        NativeFileSystem        = brackets.getModule("file/NativeFileSystem").NativeFileSystem,
        KeyBindingManager       = brackets.getModule("command/KeyBindingManager"),
        FileUtils               = brackets.getModule("file/FileUtils"),
        Menus                   = brackets.getModule("command/Menus");

    // Local modules
    var InlineSnippetForm       = require("InlineSnippetForm"),
        SnippetPresets          = require("SnippetPresets");

        //Snippets array
    var snippets = [],
        //directory where snippets are
        directory = "";

    //commands
    var SNIPPET_EXECUTE = "snippets.execute",
        VIEW_HIDE_SNIPPETS = "snippets.hideSnippets";

    function _handleHideSnippets() {
        var $snippets = $("#snippets");

        if ($snippets.css("display") === "none") {
            $snippets.show();
            CommandManager.get(VIEW_HIDE_SNIPPETS).setName("Hide Snippets");
        } else {
            $snippets.hide();
            CommandManager.get(VIEW_HIDE_SNIPPETS).setName("Show Snippets");
        }
        EditorManager.resizeEditor();
    }

    function inlineSnippetFormProvider(hostEditor, props) {
        var result = new $.Deferred();

        var snippetForm = new InlineSnippetForm(props);
        snippetForm.load(hostEditor);
        result.resolve(snippetForm);

        return result.promise();
    }

    function _handleSnippet(props) {
        var editor = EditorManager.getCurrentFullEditor();
        var document = DocumentManager.getCurrentDocument();
        var pos = editor.getCursorPos();
        var line = document.getLine(pos.line);
        if (!props) {
            props = $.trim(line).split(" ");
        }

        function completeInsert(editor, pos, output) {
            var s,
                cursorPos,
                lines = output.split("\n");

            for (s = 0; s < lines.length; s++) {
                if (lines[s].indexOf('!!{cursor}') >= 0) {
                    cursorPos = s;
                    lines[s] = lines[s].replace('!!{cursor}', '');
                }
                if (s !== lines.length - 1) {
                    lines[s] = lines[s] + "\n";
                }
                editor._codeMirror.setLine(pos.line, lines[s]);
                editor._codeMirror.indentLine(pos.line);
                pos.line++;
            }
            if (cursorPos) {
                editor._codeMirror.setCursor(pos.line - (lines.length - cursorPos), pos.ch);
            }
            EditorManager.focusEditor();
        }
        function startInsert(output) {
            //find variables
            var tmp = output.match(/\$\$\{[0-9A-Z_a-z]{1,32}\}/g);
             //remove duplicate variables
            var snippetVariables = [],
                j;

            if (tmp && tmp.length > 0) {
                for (j = 0; j < tmp.length; j++) {
                    if ($.inArray(tmp[j], snippetVariables) === -1) {
                        snippetVariables.push(tmp[j]);
                    }
                }
            }

            //if the same number of variables
            if (props.length - 1 >= snippetVariables.length) {
                var x;
                for (x = 0; x < snippetVariables.length; x++) {
                    //even my escapes have escapes
                    var re = new RegExp(snippetVariables[x].replace('$${', '\\$\\$\\{').replace('}', '\\}'), 'g');
                    output = output.replace(re, props[x + 1]);
                }
                completeInsert(editor, pos, output);
            } else {
                var snippetPromise,
                    result = new $.Deferred();
                snippetPromise = inlineSnippetFormProvider(editor, snippetVariables);

                snippetPromise.done(function (inlineWidget) {
                    editor.addInlineWidget(pos, inlineWidget);
                    var inlineComplete = function () {
                        var z;
                        for (z = 0; z < snippetVariables.length; z++) {
                            //even my escapes have escapes
                            var re = new RegExp(snippetVariables[z].replace('$${', '\\$\\$\\{').replace('}', '\\}'), 'g');
                            output = output.replace(re, inlineWidget.$form.find('.snipvar-' + snippetVariables[z].replace('$${', '').replace('}', '')).val());
                        }

                        completeInsert(editor, pos, output);
                    };
                    inlineWidget.$insert.click(inlineComplete);
                    inlineWidget.$form.keypress(function (e) {
                        if (e.which === 13) {
                            e.preventDefault();
                            inlineComplete();
                            inlineWidget.close();
                        }
                    });
                }).fail(function () {
                    result.reject();
                    console.log("Can't create inline snippet form");
                });
            }
        }

        function readSnippetFromFile(fieName) {
            var snippetFile = new NativeFileSystem.FileEntry(directory + '/' + fieName);
            FileUtils.readAsText(snippetFile)
                .done(function (text, readTimestamp) {
                    startInsert(SnippetPresets.execute(text));
                }).fail(function (error) {
                    FileUtils.showFileOpenError(error.code, snippetFile);
                });
        }

        if (props.length) {
            //try to find the snippet, given the trigger text
            var i;
            for (i = 0; i < snippets.length; i++) {
                if (snippets[i].trigger === props[0]) {
                    var output = snippets[i].template;
                    if (output.indexOf('.snippet') === output.length - 8) {
                        readSnippetFromFile(output);
                    } else {
                        startInsert(SnippetPresets.execute(output));
                    }
                    break;
                }
            }
        }
    }

    function makeCell(content) {
        return $("").html(content);
    }

    //shows the snippets table
    function showSnippets() {
        $('.content').append('
'
                             + '
'
                             + '
Snippets
×'
                             + '
'
                             + '
'
                             + '
');
        $('#snippets').hide();

        var $snippetsTable = $("
").append("
");
        $("
Name	Description	Trigger	Usage Example	Source
").appendTo($snippetsTable);

        $("#snippets .table-container")
            .empty()
            .append($snippetsTable);

        $('#snippets-table').on('click', '.insert-snippet', function () {
            CommandManager.execute(SNIPPET_EXECUTE, [$(this).attr('trigger')]);
        });
    }

    //parse a JSON file with a snippet in it
    function loadSnippet(fileEntry) {
        FileUtils.readAsText(fileEntry)
            .done(function (text, readTimestamp) {
                try {
                    //TODO: a better check for valid snippets
                    var newSnippets = JSON.parse(text);
                    newSnippets.forEach(function (item) {
                        $("
")
                            .append(makeCell('' + item.name + ''))
                            .append(makeCell(item.description))
                            .append(makeCell(item.trigger))
                            .append(makeCell(item.usage))
                            .appendTo($('#snippets-table'))
                            .append(makeCell(fileEntry.name)); //TODO: make that clickable to open file;
                    });
                    snippets = snippets.concat(newSnippets);
                } catch (e) {
                    console.log("Can't parse snippets from " + fileEntry.fullPath);
                }
            })
            .fail(function (error) {
                FileUtils.showFileOpenError(error.name, fileEntry.fullPath);
            });
    }

    CommandManager.register("Run Snippet", SNIPPET_EXECUTE, _handleSnippet);
    CommandManager.register("Show Snippets", VIEW_HIDE_SNIPPETS, _handleHideSnippets);

    function init() {
        //add the HTML UI
        showSnippets();

        //add the menu and keybinding for view/hide
        var menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU);
        menu.addMenuItem(VIEW_HIDE_SNIPPETS, "Ctrl-Shift-S", Menus.AFTER, Commands.VIEW_HIDE_SIDEBAR);

        //add the keybinding
        KeyBindingManager.addBinding(SNIPPET_EXECUTE, "Ctrl-Alt-V");

        $('#snippets .close').click(function () {
            CommandManager.execute(VIEW_HIDE_SNIPPETS);
        });

        //snippet module's directory
        var moduleDir = FileUtils.getNativeModuleDirectoryPath(module);
        var configFile = new NativeFileSystem.FileEntry(moduleDir + '/config.js');

        FileUtils.readAsText(configFile)
            .done(function (text, readTimestamp) {
                var config = {};

                //try to parse the config file
                try {
                    config = JSON.parse(text);
                } catch (e) {
                    console.log("Can't parse config.js - " + e);
                    config.dataDirectory = "data";
                }
                directory = moduleDir + "/" + config.dataDirectory;

                //Look for any marker of a non relative path
                if (config.dataDirectory.indexOf("/") !== -1 || config.dataDirectory.indexOf("\\") !== -1) {
                    directory = config.dataDirectory;
                }
                //loop through the directory to load snippets
                NativeFileSystem.requestNativeFileSystem(directory,
                    function (rootEntry) {
                        rootEntry.root.createReader().readEntries(
                            function (entries) {
                                var i;
                                for (i = 0; i < entries.length; i++) {
                                    loadSnippet(entries[i]);
                                }
                            },
                            function (error) {
                                console.log("[Snippets] Error -- could not read snippets directory: " + directory);
                            }
                        );
                    },
                    function (error) {
                        console.log("[Snippets] Error -- could not open snippets directory: " + directory);
                    });

            })
            .fail(function (error) {
                FileUtils.showFileOpenError(error.code, configFile);
            });

    }

    init();

});<commit_msg>Fix error if a directory exists in the data directory<commit_after>/*
 * Copyright (c) 2012 Jonathan Rowny. All rights reserved.
 * http://www.jonathanrowny.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, brackets, $, window */

define(function (require, exports, module) {
    'use strict';
    var Commands                = brackets.getModule("command/Commands"),
        CommandManager          = brackets.getModule("command/CommandManager"),
        EditorManager           = brackets.getModule("editor/EditorManager"),
        DocumentManager         = brackets.getModule("document/DocumentManager"),
        NativeFileSystem        = brackets.getModule("file/NativeFileSystem").NativeFileSystem,
        KeyBindingManager       = brackets.getModule("command/KeyBindingManager"),
        FileUtils               = brackets.getModule("file/FileUtils"),
        Menus                   = brackets.getModule("command/Menus");

    // Local modules
    var InlineSnippetForm       = require("InlineSnippetForm"),
        SnippetPresets          = require("SnippetPresets");

        //Snippets array
    var snippets = [],
        //directory where snippets are
        directory = "";

    //commands
    var SNIPPET_EXECUTE = "snippets.execute",
        VIEW_HIDE_SNIPPETS = "snippets.hideSnippets";

    function _handleHideSnippets() {
        var $snippets = $("#snippets");

        if ($snippets.css("display") === "none") {
            $snippets.show();
            CommandManager.get(VIEW_HIDE_SNIPPETS).setName("Hide Snippets");
        } else {
            $snippets.hide();
            CommandManager.get(VIEW_HIDE_SNIPPETS).setName("Show Snippets");
        }
        EditorManager.resizeEditor();
    }

    function inlineSnippetFormProvider(hostEditor, props) {
        var result = new $.Deferred();

        var snippetForm = new InlineSnippetForm(props);
        snippetForm.load(hostEditor);
        result.resolve(snippetForm);

        return result.promise();
    }

    function _handleSnippet(props) {
        var editor = EditorManager.getCurrentFullEditor();
        var document = DocumentManager.getCurrentDocument();
        var pos = editor.getCursorPos();
        var line = document.getLine(pos.line);
        if (!props) {
            props = $.trim(line).split(" ");
        }

        function completeInsert(editor, pos, output) {
            var s,
                cursorPos,
                lines = output.split("\n");

            for (s = 0; s < lines.length; s++) {
                if (lines[s].indexOf('!!{cursor}') >= 0) {
                    cursorPos = s;
                    lines[s] = lines[s].replace('!!{cursor}', '');
                }
                if (s !== lines.length - 1) {
                    lines[s] = lines[s] + "\n";
                }
                editor._codeMirror.setLine(pos.line, lines[s]);
                editor._codeMirror.indentLine(pos.line);
                pos.line++;
            }
            if (cursorPos) {
                editor._codeMirror.setCursor(pos.line - (lines.length - cursorPos), pos.ch);
            }
            EditorManager.focusEditor();
        }
        function startInsert(output) {
            //find variables
            var tmp = output.match(/\$\$\{[0-9A-Z_a-z]{1,32}\}/g);
             //remove duplicate variables
            var snippetVariables = [],
                j;

            if (tmp && tmp.length > 0) {
                for (j = 0; j < tmp.length; j++) {
                    if ($.inArray(tmp[j], snippetVariables) === -1) {
                        snippetVariables.push(tmp[j]);
                    }
                }
            }

            //if the same number of variables
            if (props.length - 1 >= snippetVariables.length) {
                var x;
                for (x = 0; x < snippetVariables.length; x++) {
                    //even my escapes have escapes
                    var re = new RegExp(snippetVariables[x].replace('$${', '\\$\\$\\{').replace('}', '\\}'), 'g');
                    output = output.replace(re, props[x + 1]);
                }
                completeInsert(editor, pos, output);
            } else {
                var snippetPromise,
                    result = new $.Deferred();
                snippetPromise = inlineSnippetFormProvider(editor, snippetVariables);

                snippetPromise.done(function (inlineWidget) {
                    editor.addInlineWidget(pos, inlineWidget);
                    var inlineComplete = function () {
                        var z;
                        for (z = 0; z < snippetVariables.length; z++) {
                            //even my escapes have escapes
                            var re = new RegExp(snippetVariables[z].replace('$${', '\\$\\$\\{').replace('}', '\\}'), 'g');
                            output = output.replace(re, inlineWidget.$form.find('.snipvar-' + snippetVariables[z].replace('$${', '').replace('}', '')).val());
                        }

                        completeInsert(editor, pos, output);
                    };
                    inlineWidget.$insert.click(inlineComplete);
                    inlineWidget.$form.keypress(function (e) {
                        if (e.which === 13) {
                            e.preventDefault();
                            inlineComplete();
                            inlineWidget.close();
                        }
                    });
                }).fail(function () {
                    result.reject();
                    console.log("Can't create inline snippet form");
                });
            }
        }

        function readSnippetFromFile(fieName) {
            var snippetFile = new NativeFileSystem.FileEntry(directory + '/' + fieName);
            FileUtils.readAsText(snippetFile)
                .done(function (text, readTimestamp) {
                    startInsert(SnippetPresets.execute(text));
                }).fail(function (error) {
                    FileUtils.showFileOpenError(error.code, snippetFile);
                });
        }

        if (props.length) {
            //try to find the snippet, given the trigger text
            var i;
            for (i = 0; i < snippets.length; i++) {
                if (snippets[i].trigger === props[0]) {
                    var output = snippets[i].template;
                    if (output.indexOf('.snippet') === output.length - 8) {
                        readSnippetFromFile(output);
                    } else {
                        startInsert(SnippetPresets.execute(output));
                    }
                    break;
                }
            }
        }
    }

    function makeCell(content) {
        return $("").html(content);
    }

    //shows the snippets table
    function showSnippets() {
        $('.content').append('
'
                             + '
'
                             + '
Snippets
×'
                             + '
'
                             + '
'
                             + '
');
        $('#snippets').hide();

        var $snippetsTable = $("
").append("
");
        $("
Name	Description	Trigger	Usage Example	Source
").appendTo($snippetsTable);

        $("#snippets .table-container")
            .empty()
            .append($snippetsTable);

        $('#snippets-table').on('click', '.insert-snippet', function () {
            CommandManager.execute(SNIPPET_EXECUTE, [$(this).attr('trigger')]);
        });
    }

    //parse a JSON file with a snippet in it
    function loadSnippet(fileEntry) {
        if(fileEntry.isDirectory) return;
        FileUtils.readAsText(fileEntry)
            .done(function (text, readTimestamp) {
                try {
                    //TODO: a better check for valid snippets
                    var newSnippets = JSON.parse(text);
                    newSnippets.forEach(function (item) {
                        $("
")
                            .append(makeCell('' + item.name + ''))
                            .append(makeCell(item.description))
                            .append(makeCell(item.trigger))
                            .append(makeCell(item.usage))
                            .appendTo($('#snippets-table'))
                            .append(makeCell(fileEntry.name)); //TODO: make that clickable to open file;
                    });
                    snippets = snippets.concat(newSnippets);
                } catch (e) {
                    console.log("Can't parse snippets from " + fileEntry.fullPath);
                }
            })
            .fail(function (error) {
                FileUtils.showFileOpenError(error.name, fileEntry.fullPath);
            });
    }

    CommandManager.register("Run Snippet", SNIPPET_EXECUTE, _handleSnippet);
    CommandManager.register("Show Snippets", VIEW_HIDE_SNIPPETS, _handleHideSnippets);

    function init() {
        //add the HTML UI
        showSnippets();

        //add the menu and keybinding for view/hide
        var menu = Menus.getMenu(Menus.AppMenuBar.VIEW_MENU);
        menu.addMenuItem(VIEW_HIDE_SNIPPETS, "Ctrl-Shift-S", Menus.AFTER, Commands.VIEW_HIDE_SIDEBAR);

        //add the keybinding
        KeyBindingManager.addBinding(SNIPPET_EXECUTE, "Ctrl-Alt-V");

        $('#snippets .close').click(function () {
            CommandManager.execute(VIEW_HIDE_SNIPPETS);
        });

        //snippet module's directory
        var moduleDir = FileUtils.getNativeModuleDirectoryPath(module);
        var configFile = new NativeFileSystem.FileEntry(moduleDir + '/config.js');

        FileUtils.readAsText(configFile)
            .done(function (text, readTimestamp) {
                var config = {};

                //try to parse the config file
                try {
                    config = JSON.parse(text);
                } catch (e) {
                    console.log("Can't parse config.js - " + e);
                    config.dataDirectory = "data";
                }
                directory = moduleDir + "/" + config.dataDirectory;

                //Look for any marker of a non relative path
                if (config.dataDirectory.indexOf("/") !== -1 || config.dataDirectory.indexOf("\\") !== -1) {
                    directory = config.dataDirectory;
                }
                //loop through the directory to load snippets
                NativeFileSystem.requestNativeFileSystem(directory,
                    function (rootEntry) {
                        rootEntry.root.createReader().readEntries(
                            function (entries) {
                                var i;
                                for (i = 0; i < entries.length; i++) {
                                    loadSnippet(entries[i]);
                                }
                            },
                            function (error) {
                                console.log("[Snippets] Error -- could not read snippets directory: " + directory);
                            }
                        );
                    },
                    function (error) {
                        console.log("[Snippets] Error -- could not open snippets directory: " + directory);
                    });

            })
            .fail(function (error) {
                FileUtils.showFileOpenError(error.code, configFile);
            });

    }

    init();

});<|endoftext|>


<commit_before>'use strict';
(function(app) {
	document.addEventListener('DOMContentLoaded', function() {
		ng.core.enableProdMode();
		ng.platformBrowserDynamic
			.platformBrowserDynamic()
			.bootstrapModule(app.AppModule);
	});
})(window.app || (window.app = {}));
<commit_msg>AngularJS 2.0.0-rc5 - restructured code to conform with Modules,Components,Services<commit_after>'use strict';
(function(app) {
	document.addEventListener('DOMContentLoaded', function() {
		//ng.core.enableProdMode();
		ng.platformBrowserDynamic
			.platformBrowserDynamic()
			.bootstrapModule(app.AppModule);
	});
})(window.app || (window.app = {}));
<|endoftext|>


<commit_before>window.onload = function(){
//cc是一个全局变量
cc.game.onStart = function(){
  //load resources
  //加载游戏资源（全局资源），回调
  //加载资源时会显示cocos的加载画面
  cc.LoaderScene.preload(g_resources, function () {
      //运行开始场景
      cc.director.runScene(new StartScene());
      console.log("资源加载完毕");
  }, this);
};
//指定运行的canvas
cc.game.run("canvas");
};<commit_msg>添加画面自动缩放<commit_after>window.onload = function(){
//cc是一个全局变量
cc.game.onStart = function(){
    cc.view.adjustViewPort(true);
    cc.view.enableRetina(true);
    cc.view.setDesignResolutionSize(568, 320, cc.ResolutionPolicy.SHOW_ALL);
    cc.view.resizeWithBrowserSize(true);
  //load resources
  //加载游戏资源（全局资源），回调
  //加载资源时会显示cocos的加载画面
  cc.LoaderScene.preload(g_resources, function () {
      //运行开始场景
      cc.director.runScene(new StartScene());
      console.log("资源加载完毕");
  }, this);
};
//指定运行的canvas
cc.game.run("canvas");
};<|endoftext|>