<commit_before>'use strict';

var serverConfig   = require('../configs/server');
var facebookConfig = require('../configs/facebook');
var _              = require('lodash');

var urlGenerator = {
    main: function() {
        return serverConfig.URL + '/fr';
    },
    user: function(user) {
        return serverConfig.URL + '/fr' + '/users/' + user.id;
    },
    business: function(business) {
        if(business.slug) {
            return serverConfig.URL + '/fr' + '/businesses/' + business.id + '/' + business.slug;
        } else {
            return serverConfig.URL + '/fr' + '/businesses/' + business.id;
        }

    },
    hairfie: function(hairfie) {
        return serverConfig.URL + '/fr' + '/hairfies/' + hairfie.id;
    }
}

var globalMetas = [
    { property: "fb:app_id", content: facebookConfig.APP_ID },
    { property: "og:locale:alternate", content: "fr_FR" }
];

var daysOfWeek = {
    MON: 'monday',
    TUE: 'tuesday',
    WED: 'wednesday',
    THU: 'thursday',
    FRI: 'friday',
    SAT: 'saturday',
    SUN: 'sunday'
};

function fullDayOfWeek(abbr) {
    return daysOfWeek[abbr];
}

module.exports = {
    getBasicMetadata: function() {
        var metas = [];
        metas.push.apply(metas, globalMetas);
        metas.push({property: "og:image", content: serverConfig.URL + '/img/background-pro.png'});
        metas.push({property: "og:title", content: "Hairfie"});
        metas.push({property: "og:url", content: urlGenerator.main()});

        return metas;
    },

    getHairfieMetadata: function (hairfie) {
        var author         = hairfie.author,
            business       = hairfie.business,
            metas          = [],
            canonicalUrl   = urlGenerator.hairfie(hairfie),
            homeUrl        = serverConfig.URL,
            authorUrl      = author ? urlGenerator.user(author) : null,
            businessUrl    = business ? urlGenerator.business(business) : null,
            title          = null,
            hairdresserUrl = null,
            caption        = null,
            description    = null;

        if(hairfie.hairdresser) {
            title = 'Hairfie réalisé par ' + hairfie.hairdresser.firstName;
            description = 'Réservez gratuitement en ligne la même prestation réalisée par ' + hairfie.hairdresser.firstName + ' au salon ' + business.name + ' sur Hairfie';
        } else if(business) {
            title = 'Hairfie réalisé chez ' + business.name;
            description = 'Réservez gratuitement en ligne la même prestation réalisée au salon ' + business.name + ' sur Hairfie';
        } else {
            title = 'Hairfie posté par ' + author.firstName;
            description = 'Réservez gratuitement votre séance en ligne sur Hairfie'
        }

        title += ' | Hairfie'

        if(hairfie.tags) {
            caption += _.map(hairfie.tags, function(tag) { return '#'+tag.name.replace(/ /g,''); }).join(" ");
        }

        metas.push.apply(metas, globalMetas);
        metas.push({property: "og:type", content: facebookConfig.APP_NAMESPACE+':hairfie'});
        metas.push({property: "og:url", content: canonicalUrl});
        metas.push({property: "og:title", content: title});
        metas.push({property: "og:image", content: hairfie.picture.url});
        metas.push({property: "og:description", content: description})

        if (caption)        metas.push({property: 'og:caption', content: caption})
        if (authorUrl)      metas.push({property: "hairfie:author", content: authorUrl});
        if (businessUrl)    metas.push({property: "hairfie:business", content: businessUrl});
        if (hairdresserUrl) metas.push({property: "hairfie:hairdresser", content: hairdresserUrl});

        return metas;
    },

    getBusinessMetadata: function(business) {
        var title          = business.name + ' | Hairfie',
            description    = 'Prenez rendez-vous gratuitement en quelques clics sur Hairfie',
            metas          = [],
            canonicalUrl   = urlGenerator.business(business),
            homeUrl        = serverConfig.URL;

        metas.push.apply(metas, globalMetas);
        metas.push({property: "og:type", content: facebookConfig.APP_NAMESPACE+':business'});
        metas.push({property: "og:url", content: canonicalUrl});
        metas.push({property: "og:title", content: title});
        metas.push({property: "og:description", content: description});

        if (business.address) {
            metas.push({property: "business:contact_data:street_address", content: business.address.street});
            metas.push({property: "business:contact_data:locality", content: business.address.city});
            metas.push({property: "business:contact_data:postal_code", content: business.address.zipCode});
            metas.push({property: "business:contact_data:country_name", content: business.address.country});
        }

        if (business.timetable) {
            for (var day in business.timetable) {
                var timeWindows = business.timetable[day];

                if (0 == timeWindows.length) continue;

                metas.push({property: "business:hours:day", content: fullDayOfWeek(day)});
                for (var i = 0; i < Math.min(timeWindows.length, 2); i++) {
                    var timeWindow = timeWindows[i];
                    metas.push({property: "business:hours:start", content: timeWindow.startTime});
                    metas.push({property: "business:hours:end", content: timeWindow.endTime});
                }
            }
        }

        if (business.gps) {
            metas.push({property: "place:location:latitude", content: business.gps.lat});
            metas.push({property: "place:location:longitude", content: business.gps.lng});
        }

        if(business.pictures) {
            business.pictures.map(function (picture) {
                metas.push({property: "og:image", content: picture.url});
            });
        } else {
            metas.push({property: "og:image", content: serverConfig.URL + '/img/logo.png'});
        }

        return metas;
    }
};
<commit_msg>fix #55<commit_after>'use strict';

var serverConfig   = require('../configs/server');
var facebookConfig = require('../configs/facebook');
var _              = require('lodash');

var urlGenerator = {
    main: function() {
        return serverConfig.URL + '/fr';
    },
    user: function(user) {
        return serverConfig.URL + '/fr' + '/users/' + user.id;
    },
    business: function(business) {
        if(business.slug) {
            return serverConfig.URL + '/fr' + '/businesses/' + business.id + '/' + business.slug;
        } else {
            return serverConfig.URL + '/fr' + '/businesses/' + business.id;
        }

    },
    hairfie: function(hairfie) {
        return serverConfig.URL + '/fr' + '/hairfies/' + hairfie.id;
    }
}

var globalMetas = [
    { property: "fb:app_id", content: facebookConfig.APP_ID },
    { property: "og:locale:alternate", content: "fr_FR" }
];

var daysOfWeek = {
    MON: 'monday',
    TUE: 'tuesday',
    WED: 'wednesday',
    THU: 'thursday',
    FRI: 'friday',
    SAT: 'saturday',
    SUN: 'sunday'
};

function fullDayOfWeek(abbr) {
    return daysOfWeek[abbr];
}

module.exports = {
    getBasicMetadata: function() {
        var metas = [];
        metas.push.apply(metas, globalMetas);
        metas.push({property: "og:image", content: serverConfig.URL + '/img/background-pro.png'});
        metas.push({property: "og:title", content: "Hairfie"});
        metas.push({property: "og:url", content: urlGenerator.main()});
        metas.push({property: "og:description", content: "Trouvez rapidement le coiffeur qui vous correspond près de chez vous et prenez rendez-vous gratuitement en ligne en quelques clics."})

        return metas;
    },

    getHairfieMetadata: function (hairfie) {
        var author         = hairfie.author,
            business       = hairfie.business,
            metas          = [],
            canonicalUrl   = urlGenerator.hairfie(hairfie),
            homeUrl        = serverConfig.URL,
            authorUrl      = author ? urlGenerator.user(author) : null,
            businessUrl    = business ? urlGenerator.business(business) : null,
            title          = null,
            hairdresserUrl = null,
            caption        = null,
            description    = null;

        if(hairfie.hairdresser) {
            title = 'Hairfie réalisé par ' + hairfie.hairdresser.firstName;
            description = 'Réservez gratuitement en ligne la même prestation réalisée par ' + hairfie.hairdresser.firstName + ' au salon ' + business.name + ' sur Hairfie';
        } else if(business) {
            title = 'Hairfie réalisé chez ' + business.name;
            description = 'Réservez gratuitement en ligne la même prestation réalisée au salon ' + business.name + ' sur Hairfie';
        } else {
            title = 'Hairfie posté par ' + author.firstName;
            description = 'Réservez gratuitement votre séance en ligne sur Hairfie'
        }

        title += ' | Hairfie'

        if(hairfie.tags) {
            caption += _.map(hairfie.tags, function(tag) { return '#'+tag.name.replace(/ /g,''); }).join(" ");
        }

        metas.push.apply(metas, globalMetas);
        metas.push({property: "og:type", content: facebookConfig.APP_NAMESPACE+':hairfie'});
        metas.push({property: "og:url", content: canonicalUrl});
        metas.push({property: "og:title", content: title});
        metas.push({property: "og:image", content: hairfie.picture.url});
        metas.push({property: "og:description", content: description})

        if (caption)        metas.push({property: 'og:caption', content: caption})
        if (authorUrl)      metas.push({property: "hairfie:author", content: authorUrl});
        if (businessUrl)    metas.push({property: "hairfie:business", content: businessUrl});
        if (hairdresserUrl) metas.push({property: "hairfie:hairdresser", content: hairdresserUrl});

        return metas;
    },

    getBusinessMetadata: function(business) {
        var title          = business.name + ' | Hairfie',
            description    = 'Prenez rendez-vous gratuitement en quelques clics sur Hairfie',
            metas          = [],
            canonicalUrl   = urlGenerator.business(business),
            homeUrl        = serverConfig.URL;

        metas.push.apply(metas, globalMetas);
        metas.push({property: "og:type", content: facebookConfig.APP_NAMESPACE+':business'});
        metas.push({property: "og:url", content: canonicalUrl});
        metas.push({property: "og:title", content: title});
        metas.push({property: "og:description", content: description});

        if (business.address) {
            metas.push({property: "business:contact_data:street_address", content: business.address.street});
            metas.push({property: "business:contact_data:locality", content: business.address.city});
            metas.push({property: "business:contact_data:postal_code", content: business.address.zipCode});
            metas.push({property: "business:contact_data:country_name", content: business.address.country});
        }

        if (business.timetable) {
            for (var day in business.timetable) {
                var timeWindows = business.timetable[day];

                if (0 == timeWindows.length) continue;

                metas.push({property: "business:hours:day", content: fullDayOfWeek(day)});
                for (var i = 0; i < Math.min(timeWindows.length, 2); i++) {
                    var timeWindow = timeWindows[i];
                    metas.push({property: "business:hours:start", content: timeWindow.startTime});
                    metas.push({property: "business:hours:end", content: timeWindow.endTime});
                }
            }
        }

        if (business.gps) {
            metas.push({property: "place:location:latitude", content: business.gps.lat});
            metas.push({property: "place:location:longitude", content: business.gps.lng});
        }

        if(business.pictures) {
            business.pictures.map(function (picture) {
                metas.push({property: "og:image", content: picture.url});
            });
        } else {
            metas.push({property: "og:image", content: serverConfig.URL + '/img/logo.png'});
        }

        return metas;
    }
};
<|endoftext|>


<commit_before>var M = process.mono;
var EventEmitter = require('events').EventEmitter;

var broadcast = require(M.config.paths.SERVER_ROOT + 'send').broadcast;
var model = require(M.config.paths.MODELS + 'factory');
var view = require(M.config.paths.VIEWS + 'factory');

// TODO get this values from a config
var moduleModel = {
    name: 'modules'
};
var instanceModel = {
    name: 'instances'
};

module.exports = init;

function sendHandler (event) {
    return function (err, data) {
        var self = this;

        // websocket link
        if (self.link && self.link.ws) {
            self.link.send(event, err, data);
        }
    };
}

// create instance
function instanceFactory (name, module, dbInstance, callback) {

    // create new Mono observer instance
    var instance = new EventEmitter();
    instance.Z = {
        module: module.source + '/' + module.owner + '/' + module.name + '/' + module.version + '/',
        name: name,
        // allow only the clients events to be emitted form the server
        access: {},
        roles: {},
        client: {}
    };

    // save configs on instance
    if (dbInstance.config) {

        // save custom client config
        if (dbInstance.config.client) {
            instance.Z.client = {
                config: dbInstance.config.client
            };
        }

        // server config
        instance.Z.config = dbInstance.config.server || {};
    }

    // save load infos in client
    if (dbInstance.L) {
        instance.Z.client.L = dbInstance.L;
    }

    // save observe infos in client
    if (dbInstance.O) {
        instance.Z.client.O = dbInstance.O;
    }

    // save module name in client config
    instance.Z.client.module = instance.Z.module;

    // add roles to cache
    for (var i = 0, l = dbInstance.roles.length; i < l; ++i) {
        instance.Z.roles[dbInstance.roles[i]] = 1;
    }

    // merge scripts
    // all dependencies of the instance dependencies must be in this array!
    // while installing a module, save all dependencies in the module deps
    // dependencies: ['./file.js', 's/o/modA/v']
    // => ModA deps: ['./file.js', 's/o/modB/v'] => ModB deps: []
    // => to client: ['./file.js', 's/o/n/v/file.js']
    if (module.dependencies) {
        instance.Z.client.scripts = module.dependencies;
    }

    // append custom instance scripts
    if (dbInstance.scripts) {
        instance.Z.client.scripts = module.dependencies.concat(instance.Z.scripts || []);
    }

    if (dbInstance.send) {

        // exend send config with public instance load event
        dbInstance.send.up.push('inst>');
        dbInstance.send.down.push('<inst');

        // grant access for client emitted server events
        if (dbInstance.send.up) {
            for (i = 0, l = dbInstance.send.up.length; i < l; ++i) {
                instance.Z.access[dbInstance.send.up[i]] = true;
            }

            instance.Z.client.send = dbInstance.send.up;
        }

        // attach send handler for server emitted client events
        if (dbInstance.send.down) {
            for (i = 0, l = dbInstance.send.down.length; i < l; ++i) {
                instance.on(dbInstance.send.down[i], sendHandler(dbInstance.send.down[i]));
            }
        }
    }

    // load instance on "inst>" event
    instance.on('inst>', load);

    // setup model events and add model factory to instance
    model.setup(instance);
    instance.Z.model = model.factory;

    // setup view events and add model factory to instance
    instance.Z.view = view(instance);

    // attach the broadcast functionality
    instance.broadcast = broadcast;

    // handle ready
    instance.on('ready', function (err) {
        callback(err,  instance.Z.client);
    });

    // save instance in cache
    // TODO update this cache when a instance config changes
    M.cache.instances.save(name, instance);

    // require and init mono module
    if (module.main) {
        // TODO do not use try catch when in dev mode
        try {
            var monoModule = require(M.config.paths.MODULE_ROOT + instance.Z.module + module.main);

            if (typeof monoModule === 'function') {
                monoModule.call(instance, instance.Z.config || {});
            }
        } catch (err) {
            return callback('Module ' + dbInstance.name + ' init error: ' + err.toString());
        }
    } else {
        instance.emit('ready');
    }
}

// init module with newly created module instance as this
function loadinstance (name, roleId, callback) {
    var query = {
        roles: roleId,
        name: name
    };

    model.factory(instanceModel, function (err, instModel) {

        if (err) {
            return callback(err);
        }

        instModel.request({m: 'findOne', q: query, o: {fields: {_id: 0, name: 0}}}, function (err, dbInstance) {

            if (err || !dbInstance) {
                return callback(err || 'Instance "' + name + '" not found');
            }

            // get module from cache
            var module = M.cache.instances.get(dbInstance.module);
            if (module) {
                return instanceFactory(name, module, dbInstance, callback);
            }

            // get module version from db
            model.factory(moduleModel, function (err, modModel) {

                if (err) {
                    return callback(err);
                }

                modModel.request({m: 'findOne', q: {_id: dbInstance.module}}, function (err, module) {

                    if (err || !module) {
                        return callback(err || 'not found');
                    }

                    // save module in cache
                    M.cache.modules.save(dbInstance.module, module);

                    // create instance
                    instanceFactory(name, module, dbInstance, callback);
                });
            });
        });
    });
}

// get cached instance and check role access
function getCachedInstance (instance, roleId) {

    instance = M.cache.instances.get(instance);

    // send client config from cache
    if (
        instance &&
        (
            // TODO return no access response
            // check access
            instance.Z.roles['*'] ||
            instance.Z.roles[roleId]
        ) &&
        instance.Z.client
    ) {
        return instance;
    }

    return null;
}

// load instance configuration (ws)
function load (err, instance) {
    var self = this;
    var session = self.link.ws.session;

    // send client config from cache
    var cachedInstance = getCachedInstance(instance, session[M.config.session.role]);
    if (cachedInstance) {
        return self.emit('<inst', null, cachedInstance.Z.client);
    }

    // load and init module
    loadinstance(instance, session[M.config.session.role], function (err, client) {

        if (err) {
            var message = 'Error while loading module instance: ' + instance + '. Error: ' + (err || 'module not found');
            return self.emit('<inst', message);
        }

        // return client config
        self.emit('<inst', null, client);
    });
}

// load client module files (http)
function moduleFiles () {
    var self = this;

    var source = self.link.path[0];
    var owner = self.link.path[1];
    var name = self.link.path[2];
    var version = self.link.path[3];
    var headers = {
        'Cache-Control': 'public, max-age=31536000',
        'Vary': 'Accept-Encoding',
        'Content-Encoding': 'gzip'
    };

    // check if request format is correct
    if (!source || !owner || !name || !version) {
        return self.link.send(400, "Incorrect module request URL format");
    }

    // the module name must be almost alphanumeric
    if (self.link.pathname.replace(/[^a-z0-9\/\.\-_@]|\.\.\//gi, "") !== self.link.pathname) {
        return self.link.send(400, "Incorrect data in module request URL");
    }

    // create file path
    var path = M.config.paths.MODULE_ROOT + self.link.path.join('/');

    // check cache
    var script = M.cache.client.get(path);
    if (script) {

        headers['Content-Length'] = script.data.length;
        headers['Last-Modified'] = script.stats.mtime;
        headers['Content-Type']= script.mime;
        self.link.res.writeHead(200, headers);
        return self.link.res.end(script.data);
    }

    // save compressed/compiled script in cache and send it to the client
    M.cache.client.save(path, function (err, script) {

        if (err) {
            self.link.res.writeHead(500, {'content-type': 'text/plain'});
            return self.link.res.end(err.toString());
        }

        headers['Content-Length'] = script.data.length;
        headers['Last-Modified'] = script.stats.mtime;
        headers['Content-Type']= script.mime;
        self.link.res.writeHead(200, headers);

        return self.link.res.end(script.data);
    });
}

// get mono client (http)
function client (){
    var self = this;
    var path = M.config.paths.CLIENT_ROOT + self.link.path[0];
    var headers = {
        'Cache-Control': 'public, max-age=31536000',
        'Vary': 'Accept-Encoding',
        'Content-Encoding': 'gzip'
    };

    // check cache
    var script = M.cache.client.get(path);
    if (script) {

        headers['Content-Length'] = script.data.length;
        headers['Last-Modified'] = script.stats.mtime;
        headers['Content-Type']= script.mime;
        self.link.res.writeHead(200, headers);
        return self.link.res.end(script.data);
    }

    // save compressed/compiled script in cache and send it to the client
    M.cache.client.save(path, function (err, script) {

        if (err) {
            self.link.res.writeHead(500, {'content-type': 'text/plain'});
            return self.link.res.end(err.toString());
        }

        headers['Content-Length'] = script.data.length;
        headers['Last-Modified'] = script.stats.mtime;
        headers['Content-Type']= script.mime;
        self.link.res.writeHead(200, headers);

        return self.link.res.end(script.data);
    });
}

function init () {
    var instance = new EventEmitter();
    instance.Z = {
        module: 'core',
        name: M.config.coreInstance,

        // set core module access
        access: {
            'inst>': true,
            'view>': true,
            'model>': true,
            'mod': true,
            'client': true
        },
        // set core module public rights
        roles: {'*': 1}
    };

    // setup client event interface
    instance.on('<inst',  sendHandler('<inst'));
    instance.on('<view',  sendHandler('<view'));
    instance.on('<model',  sendHandler('<model'));
    instance.on('inst>', load);
    instance.on('mod', moduleFiles);
    instance.on('client', client);

    // setup model events and add model factory to instance
    model.setup(instance);
    instance.model = model.factory;

    // setup view events and add model factory to instance
    instance.view = view(instance);

    // attach the broadcast functionality
    instance.broadcast = broadcast;

    // init mono module and save in cache
    M.cache.instances.save(instance.Z.name, instance);
}
<commit_msg>get custom scripts from instance config<commit_after>var M = process.mono;
var EventEmitter = require('events').EventEmitter;

var broadcast = require(M.config.paths.SERVER_ROOT + 'send').broadcast;
var model = require(M.config.paths.MODELS + 'factory');
var view = require(M.config.paths.VIEWS + 'factory');

// TODO get this values from a config
var moduleModel = {
    name: 'modules'
};
var instanceModel = {
    name: 'instances'
};

module.exports = init;

function sendHandler (event) {
    return function (err, data) {
        var self = this;

        // websocket link
        if (self.link && self.link.ws) {
            self.link.send(event, err, data);
        }
    };
}

// create instance
function instanceFactory (name, module, dbInstance, callback) {

    // create new Mono observer instance
    var instance = new EventEmitter();
    instance.Z = {
        module: module.source + '/' + module.owner + '/' + module.name + '/' + module.version + '/',
        name: name,
        // allow only the clients events to be emitted form the server
        access: {},
        roles: {},
        client: {}
    };

    // save configs on instance
    if (dbInstance.config) {

        // save custom client config
        if (dbInstance.config.client) {
            instance.Z.client = {
                config: dbInstance.config.client
            };
        }

        // server config
        instance.Z.config = dbInstance.config.server || {};
    }

    // save load infos in client
    if (dbInstance.L) {
        instance.Z.client.L = dbInstance.L;
    }

    // save observe infos in client
    if (dbInstance.O) {
        instance.Z.client.O = dbInstance.O;
    }

    // save module name in client config
    instance.Z.client.module = instance.Z.module;

    // add roles to cache
    for (var i = 0, l = dbInstance.roles.length; i < l; ++i) {
        instance.Z.roles[dbInstance.roles[i]] = 1;
    }

    // merge scripts
    // all dependencies of the instance dependencies must be in this array!
    // while installing a module, save all dependencies in the module deps
    // dependencies: ['./file.js', 's/o/modA/v']
    // => ModA deps: ['./file.js', 's/o/modB/v'] => ModB deps: []
    // => to client: ['./file.js', 's/o/n/v/file.js']
    if (module.dependencies) {
        instance.Z.client.scripts = module.dependencies;
    }

    // append custom instance scripts
    if (dbInstance.scripts) {
        instance.Z.client.scripts = module.dependencies.concat(dbInstance.scripts || []);
    }

    if (dbInstance.send) {

        // exend send config with public instance load event
        dbInstance.send.up.push('inst>');
        dbInstance.send.down.push('<inst');

        // grant access for client emitted server events
        if (dbInstance.send.up) {
            for (i = 0, l = dbInstance.send.up.length; i < l; ++i) {
                instance.Z.access[dbInstance.send.up[i]] = true;
            }

            instance.Z.client.send = dbInstance.send.up;
        }

        // attach send handler for server emitted client events
        if (dbInstance.send.down) {
            for (i = 0, l = dbInstance.send.down.length; i < l; ++i) {
                instance.on(dbInstance.send.down[i], sendHandler(dbInstance.send.down[i]));
            }
        }
    }

    // load instance on "inst>" event
    instance.on('inst>', load);

    // setup model events and add model factory to instance
    model.setup(instance);
    instance.Z.model = model.factory;

    // setup view events and add model factory to instance
    instance.Z.view = view(instance);

    // attach the broadcast functionality
    instance.broadcast = broadcast;

    // handle ready
    instance.on('ready', function (err) {
        callback(err,  instance.Z.client);
    });

    // save instance in cache
    // TODO update this cache when a instance config changes
    M.cache.instances.save(name, instance);

    // require and init mono module
    if (module.main) {
        // TODO do not use try catch when in dev mode
        try {
            var monoModule = require(M.config.paths.MODULE_ROOT + instance.Z.module + module.main);

            if (typeof monoModule === 'function') {
                monoModule.call(instance, instance.Z.config || {});
            }
        } catch (err) {
            return callback('Module ' + dbInstance.name + ' init error: ' + err.toString());
        }
    } else {
        instance.emit('ready');
    }
}

// init module with newly created module instance as this
function loadinstance (name, roleId, callback) {
    var query = {
        roles: roleId,
        name: name
    };

    model.factory(instanceModel, function (err, instModel) {

        if (err) {
            return callback(err);
        }

        instModel.request({m: 'findOne', q: query, o: {fields: {_id: 0, name: 0}}}, function (err, dbInstance) {

            if (err || !dbInstance) {
                return callback(err || 'Instance "' + name + '" not found');
            }

            // get module from cache
            var module = M.cache.instances.get(dbInstance.module);
            if (module) {
                return instanceFactory(name, module, dbInstance, callback);
            }

            // get module version from db
            model.factory(moduleModel, function (err, modModel) {

                if (err) {
                    return callback(err);
                }

                modModel.request({m: 'findOne', q: {_id: dbInstance.module}}, function (err, module) {

                    if (err || !module) {
                        return callback(err || 'not found');
                    }

                    // save module in cache
                    M.cache.modules.save(dbInstance.module, module);

                    // create instance
                    instanceFactory(name, module, dbInstance, callback);
                });
            });
        });
    });
}

// get cached instance and check role access
function getCachedInstance (instance, roleId) {

    instance = M.cache.instances.get(instance);

    // send client config from cache
    if (
        instance &&
        (
            // TODO return no access response
            // check access
            instance.Z.roles['*'] ||
            instance.Z.roles[roleId]
        ) &&
        instance.Z.client
    ) {
        return instance;
    }

    return null;
}

// load instance configuration (ws)
function load (err, instance) {
    var self = this;
    var session = self.link.ws.session;

    // send client config from cache
    var cachedInstance = getCachedInstance(instance, session[M.config.session.role]);
    if (cachedInstance) {
        return self.emit('<inst', null, cachedInstance.Z.client);
    }

    // load and init module
    loadinstance(instance, session[M.config.session.role], function (err, client) {

        if (err) {
            var message = 'Error while loading module instance: ' + instance + '. Error: ' + (err || 'module not found');
            return self.emit('<inst', message);
        }

        // return client config
        self.emit('<inst', null, client);
    });
}

// load client module files (http)
function moduleFiles () {
    var self = this;

    var source = self.link.path[0];
    var owner = self.link.path[1];
    var name = self.link.path[2];
    var version = self.link.path[3];
    var headers = {
        'Cache-Control': 'public, max-age=31536000',
        'Vary': 'Accept-Encoding',
        'Content-Encoding': 'gzip'
    };

    // check if request format is correct
    if (!source || !owner || !name || !version) {
        return self.link.send(400, "Incorrect module request URL format");
    }

    // the module name must be almost alphanumeric
    if (self.link.pathname.replace(/[^a-z0-9\/\.\-_@]|\.\.\//gi, "") !== self.link.pathname) {
        return self.link.send(400, "Incorrect data in module request URL");
    }

    // create file path
    var path = M.config.paths.MODULE_ROOT + self.link.path.join('/');

    // check cache
    var script = M.cache.client.get(path);
    if (script) {

        headers['Content-Length'] = script.data.length;
        headers['Last-Modified'] = script.stats.mtime;
        headers['Content-Type']= script.mime;
        self.link.res.writeHead(200, headers);
        return self.link.res.end(script.data);
    }

    // save compressed/compiled script in cache and send it to the client
    M.cache.client.save(path, function (err, script) {

        if (err) {
            self.link.res.writeHead(500, {'content-type': 'text/plain'});
            return self.link.res.end(err.toString());
        }

        headers['Content-Length'] = script.data.length;
        headers['Last-Modified'] = script.stats.mtime;
        headers['Content-Type']= script.mime;
        self.link.res.writeHead(200, headers);

        return self.link.res.end(script.data);
    });
}

// get mono client (http)
function client (){
    var self = this;
    var path = M.config.paths.CLIENT_ROOT + self.link.path[0];
    var headers = {
        'Cache-Control': 'public, max-age=31536000',
        'Vary': 'Accept-Encoding',
        'Content-Encoding': 'gzip'
    };

    // check cache
    var script = M.cache.client.get(path);
    if (script) {

        headers['Content-Length'] = script.data.length;
        headers['Last-Modified'] = script.stats.mtime;
        headers['Content-Type']= script.mime;
        self.link.res.writeHead(200, headers);
        return self.link.res.end(script.data);
    }

    // save compressed/compiled script in cache and send it to the client
    M.cache.client.save(path, function (err, script) {

        if (err) {
            self.link.res.writeHead(500, {'content-type': 'text/plain'});
            return self.link.res.end(err.toString());
        }

        headers['Content-Length'] = script.data.length;
        headers['Last-Modified'] = script.stats.mtime;
        headers['Content-Type']= script.mime;
        self.link.res.writeHead(200, headers);

        return self.link.res.end(script.data);
    });
}

function init () {
    var instance = new EventEmitter();
    instance.Z = {
        module: 'core',
        name: M.config.coreInstance,

        // set core module access
        access: {
            'inst>': true,
            'view>': true,
            'model>': true,
            'mod': true,
            'client': true
        },
        // set core module public rights
        roles: {'*': 1}
    };

    // setup client event interface
    instance.on('<inst',  sendHandler('<inst'));
    instance.on('<view',  sendHandler('<view'));
    instance.on('<model',  sendHandler('<model'));
    instance.on('inst>', load);
    instance.on('mod', moduleFiles);
    instance.on('client', client);

    // setup model events and add model factory to instance
    model.setup(instance);
    instance.model = model.factory;

    // setup view events and add model factory to instance
    instance.view = view(instance);

    // attach the broadcast functionality
    instance.broadcast = broadcast;

    // init mono module and save in cache
    M.cache.instances.save(instance.Z.name, instance);
}
<|endoftext|>


<commit_before>var env = process.env;
var EventEmitter = require('events').EventEmitter;
var fingerprint = require(env.Z_PATH_UTILS + 'fingerprint');

var broadcast = require(env.Z_PATH_PROJECT + 'send').broadcast;
var model = require(env.Z_PATH_MODELS + 'factory');
var view = require(env.Z_PATH_VIEWS + 'factory');
var cache = require(env.Z_PATH_CACHE + 'cache');

// init caches
var pojoInstances = cache.pojo('instances');
var compInstances = cache.comp('instances');
var pojoModules = cache.pojo('modules');
var compModules = cache.comp('modules');
var fileClient = cache.file('client');

module.exports = init;

function pathValue (path, scope) {

    if (!path) {
        return;
    }

    var o = path;
    path = path.split('.');
    scope = scope || this;

    // find keys in paths or return
    for (var i = 0; i < path.length; ++i) {
        if (!(scope = scope[path[i]])) {
            return;
        }
    }

    return scope;
}

function sendHandler (instanceName, self) {
    return function (err, data) {
        // websocket link
        if (self.link && self.link.ws) {
            self.link.send(err, data, instanceName);
        }
    };
}

function linkHandler (link) {
    var self = this;

    // listen to event
    self[link['1'] ? 'once' : 'on'](link.event, function (err, data) {
        self = this;

        // emit or call on a different instance
        // TODO check role access!
        if (link.to) {
            self = pojoInstances.get(link.to, self.link.ws.session.role);
            if (!self) {
                return;
            }
        }

        // create an empty data object
        if (!data && (link.data || link.add)) {
            data = {};
        }

        // handle static data
        if (link.data) {

            // create copy
            try {
                var copy = JSON.parse(JSON.stringify(link.data));

                // merge static data in data
                for (var key in copy) {
                    data[key] = copy[key];
                }
            } catch (error) {
                err = error;
            }
        }

        // add dynamic data to the data object
        if (link.add) {
            for (var prop in link.add) {
                data[prop] = pathValue(link.add[prop], self);
            }
        }

        // handle method call
        if (link.call) {

            if (typeof link.call === 'string') {
                link.call = pathValue(link.call, self);
            }

            link.call.call(self, err, data, sendHandler(self._name, self));
        }

        // emit event
        if (link.emit) {
            self.emit(link.emit, err, data, sendHandler(self._name, self));
        }
    });

    // ensure clinet send array
    if (!self._client.send) {
        self._client.send = [];
    }

    // add send events to client
    self._client.send.push(link.event);
    self._access[link.event] = true;
}

// set up link configuration
function linkSetup (instance, links, callback) {

    // set up links
    for (var i = 0, link; i < links.length; ++i) {
        linkHandler.call(instance, links[i]);
    }

    callback(null, instance._client);
}

// create instance
function instanceFactory (name, module, compInst, callback) {

    // create new Mono observer instance
    var instance = new EventEmitter();
    instance._module = module.name.replace(/_/g, '/') + '/';
    instance._name = compInst.name;
    instance._access = {};
    instance._roles = compInst.roles || {};
    instance._client = {};

    // save configs on instance
    if (compInst.config) {

        // save custom client config
        if (compInst.config.client) {
            instance._client = {
                config: compInst.config.client
            };
        }

        // server config
        instance._config = compInst.config.server || {};
    }

    // save observe infos in client
    if (compInst.O) {
        instance._client.O = compInst.O;
    }

    // save module name in client config
    instance._client.module = instance._module;

    // save load infos in client
    if (compInst.L) {
        instance._client.L = {};

        if (compInst.L.elms) {
            instance._client.L.elms = compInst.L.elms;
        }
    }

    // merge scripts
    // all dependencies of the instance dependencies must be in this array!
    // while installing a module, save all dependencies in the module deps
    // dependencies: ['./file.js', 's/o/modA/v']
    // => ModA deps: ['./file.js', 's/o/modB/v'] => ModB deps: []
    // => to client: ['./file.js', 's/o/n/v/file.js']
    if (module.dependencies) {

        // append custom instance scripts
        if (compInst.L && compInst.L.scripts) {
            instance._client.L.scripts = module.dependencies.concat(compInst.L.scripts);

        } else {
            instance._client.L = instance._client.L || {};
            instance._client.L.scripts = module.dependencies;
        }
    } else if (compInst.L && compInst.L.scripts) {
        instance._client.L.scripts = compInst.L.scripts;
    }

    // TODO better do callback buffering on instances, then copy the scripts
    instance._scripts = instance._client.L && instance._client.L.scripts ? instance._client.L.scripts.slice() : [];

    // setup model events and add model factory to instance
    model.setup(instance);
    instance._model = model.factory;

    // setup view events and add model factory to instance
    instance._view = view(instance);

    // handle send configurations
    if (!compInst.links) {
        compInst.links = [];
    }

    // set up core send events
    compInst.links.push({event: env.Z_SEND_INST_REQ, call: load});
    compInst.links.push({event: env.Z_SEND_MODEL_REQ, call: instance._modelService});
    compInst.links.push({event: env.Z_SEND_VIEW_REQ, call: instance._viewService});

    // attach the broadcast functionality
    instance._broadcast = broadcast;

    // add fingerprints to scripts
    fingerprint.addToFiles(instance._module, instance._scripts, function (err, scripts) {

        if (err) {
            return callback(err);
        }

        // update scripts
        if (scripts) {
            instance._client.L.scripts = scripts;
        }

        // send original instance name to client, in case it's an alias
        if (compInst.name !== name) {
            instance._client.name = compInst.name;

            // save instance also under original name
            pojoInstances.set(compInst.name, instance);
        }

        // save instance in cache
        // TODO update this cache when a instance config changes
        pojoInstances.set(name, instance);

        // require and init mono module
        if (module.main) {

            try {
                var monoModule = require(env.Z_PATH_PROCESS_MODULES + instance._module + module.main);

                if (typeof monoModule === 'function') {
                    monoModule.call(instance, instance._config || {}, function (err) {

                        if (err) {
                            return callback(err);
                        }

                        // setup links
                        if (compInst.links) {
                            return linkSetup(instance, compInst.links, callback);
                        }

                        callback(null, instance._client);
                    });
                }
            } catch (err) {

                // remove instance from cache
                pojoInstances.rm(name);

                callback('Module ' + compInst.name + ' init error: ' + err.toString());
            }
        } else {

            // setup links
            if (compInst.links) {
                return linkSetup(instance, compInst.links, callback);
            }

            callback(null, instance._client);
        }
    }, true);
}

// init module with newly created module instance as this
function loadinstance (name, role, callback) {

    // get and set model config from composition store
    compInstances.set(name, role, function (err, instance) {

        if (err) {
            return callback(err);
        }
        // check access
        if (!instance) {
            return callback(new Error('Instance ' + name + ' not found.'));
        }

        compModules.set(instance.module, role, function (err, module) {

            if (err) {
                return callback(err);
            }

            // check access
            if (!module) {
                return callback(new Error('Module ' + instance.module + ' not found.'));
            }

            instanceFactory(name, module, instance, callback);
        });
    });
}

// load instance configuration (ws)
function load (err, instance, callback) {
    var self = this;

    // send client config from cache
    var cachedInstance = pojoInstances.get(instance, self.link.role);

    // handle no access case
    if (cachedInstance === 0) {
        return callback('Instance: ' + instance + '. Error: Instance not found.');
    }

    if (cachedInstance) {
        return callback(null, cachedInstance._client);
    }

    // load and init module
    loadinstance(instance, self.link.role, function (err, client) {

        if (err) {
            return callback('Instance: ' + instance + '. Error: ' + err);
        }

        // return client config
        callback(null, client);
    });
}

// init the core module
function init () {
    var instance = new EventEmitter();

    instance._module = 'core',
    instance._name = env.Z_CORE_INST,
    instance._access = {},

    // set public rights to core module
    instance._roles = {'*': true};

    // set core module access
    instance._access[env.Z_SEND_INST_REQ] = true;
    instance._access[env.Z_SEND_MODULE_REQ] = true;
    instance._access[env.Z_SEND_CLIENT_REQ] = true;

    // setup client event interface
    instance.on(env.Z_SEND_INST_REQ, function (err, data) {
        var self = this;
        load.call(self, err, data, sendHandler(instance._name, self));
    });
    instance.on(env.Z_SEND_MODULE_REQ, moduleFiles);
    instance.on(env.Z_SEND_CLIENT_REQ, client);

    // setup model events and add model factory to instance
    model.setup(instance);
    instance._model = model.factory;

    // attach the broadcast functionality
    instance._broadcast = broadcast;

    // init mono module and save in cache
    pojoInstances.set(instance._name, instance);
}

// load client module files (http)
function moduleFiles () {
    var self = this;

    var source = self.link.path[0];
    var owner = self.link.path[1];
    var name = self.link.path[2];
    var version = self.link.path[3];

    // check if request format is correct
    if (!source || !owner || !name || !version) {
        return self.link.send(400, "Incorrect module request URL format");
    }

    // the module name must be almost alphanumeric
    if (self.link.pathname.replace(/[^a-z0-9\/\.\-_@]|\.\.\//gi, "") !== self.link.pathname) {
        return self.link.send(400, "Incorrect data in module request URL");
    }

    // create file path
    var moduleFile = self.link.path.join('/');
    var path = env.Z_PATH_PROCESS_MODULES + moduleFile;

    // save compressed/compiled script in cache and send it to the client
    fileClient.set(path, function (err, script) {

        if (err) {
            self.link.res.writeHead(500, {'content-type': 'text/plain'});
            return self.link.res.end(err.toString());
        }

        self.link.res.writeHead(200, script.http);
        self.link.res.end(script.data);
        return;
    }, null, moduleFile);
}

// get mono client (http)
function client (){
    var self = this;
    var path = env.Z_PATH_CLIENT + self.link.path[0];

    // save compressed/compiled script in cache and send it to the client
    fileClient.set(path, function (err, script) {

        if (err) {
            self.link.res.writeHead(500, {'content-type': 'text/plain'});
            return self.link.res.end(err.toString());
        }

        self.link.res.writeHead(200, script.http);
        self.link.res.end(script.data);
        return;
    });
}
<commit_msg>use new object utility module<commit_after>var env = process.env;
var EventEmitter = require('events').EventEmitter;
var fingerprint = require(env.Z_PATH_UTILS + 'fingerprint');
var object = require(env.Z_PATH_UTILS + 'object');

var broadcast = require(env.Z_PATH_PROJECT + 'send').broadcast;
var model = require(env.Z_PATH_MODELS + 'factory');
var view = require(env.Z_PATH_VIEWS + 'factory');
var cache = require(env.Z_PATH_CACHE + 'cache');

// init caches
var pojoInstances = cache.pojo('instances');
var compInstances = cache.comp('instances');
var pojoModules = cache.pojo('modules');
var compModules = cache.comp('modules');
var fileClient = cache.file('client');

module.exports = init;

function sendHandler (instanceName, self) {
    return function (err, data) {
        // websocket link
        if (self.link && self.link.ws) {
            self.link.send(err, data, instanceName);
        }
    };
}

function linkHandler (link) {
    var self = this;

    // listen to event
    self[link['1'] ? 'once' : 'on'](link.event, function (err, data) {
        self = this;

        // emit or call on a different instance
        // TODO check role access!
        if (link.to) {
            self = pojoInstances.get(link.to, self.link.ws.session.role);
            if (!self) {
                return;
            }
        }

        // create an empty data object
        if (!data && (link.data || link.add)) {
            data = {};
        }

        // handle static data
        if (link.data) {

            // create copy
            try {
                var copy = JSON.parse(JSON.stringify(link.data));

                // merge static data in data
                for (var key in copy) {
                    data[key] = copy[key];
                }
            } catch (error) {
                err = error;
            }
        }

        // add dynamic data to the data object
        if (link.add) {
            for (var prop in link.add) {
                data[prop] = object.path(link.add[prop], self);
            }
        }

        // handle method call
        if (link.call) {

            if (typeof link.call === 'string') {
                link.call = object.path(link.call, self);
            }

            link.call.call(self, err, data, sendHandler(self._name, self));
        }

        // emit event
        if (link.emit) {
            self.emit(link.emit, err, data, sendHandler(self._name, self));
        }
    });

    // ensure clinet send array
    if (!self._client.send) {
        self._client.send = [];
    }

    // add send events to client
    self._client.send.push(link.event);
    self._access[link.event] = true;
}

// set up link configuration
function linkSetup (instance, links, callback) {

    // set up links
    for (var i = 0, link; i < links.length; ++i) {
        linkHandler.call(instance, links[i]);
    }

    callback(null, instance._client);
}

// create instance
function instanceFactory (name, module, compInst, callback) {

    // create new Mono observer instance
    var instance = new EventEmitter();
    instance._module = module.name.replace(/_/g, '/') + '/';
    instance._name = compInst.name;
    instance._access = {};
    instance._roles = compInst.roles || {};
    instance._client = {};

    // save configs on instance
    if (compInst.config) {

        // save custom client config
        if (compInst.config.client) {
            instance._client = {
                config: compInst.config.client
            };
        }

        // server config
        instance._config = compInst.config.server || {};
    }

    // save observe infos in client
    if (compInst.O) {
        instance._client.O = compInst.O;
    }

    // save module name in client config
    instance._client.module = instance._module;

    // save load infos in client
    if (compInst.L) {
        instance._client.L = {};

        if (compInst.L.elms) {
            instance._client.L.elms = compInst.L.elms;
        }
    }

    // merge scripts
    // all dependencies of the instance dependencies must be in this array!
    // while installing a module, save all dependencies in the module deps
    // dependencies: ['./file.js', 's/o/modA/v']
    // => ModA deps: ['./file.js', 's/o/modB/v'] => ModB deps: []
    // => to client: ['./file.js', 's/o/n/v/file.js']
    if (module.dependencies) {

        // append custom instance scripts
        if (compInst.L && compInst.L.scripts) {
            instance._client.L.scripts = module.dependencies.concat(compInst.L.scripts);

        } else {
            instance._client.L = instance._client.L || {};
            instance._client.L.scripts = module.dependencies;
        }
    } else if (compInst.L && compInst.L.scripts) {
        instance._client.L.scripts = compInst.L.scripts;
    }

    // TODO better do callback buffering on instances, then copy the scripts
    instance._scripts = instance._client.L && instance._client.L.scripts ? instance._client.L.scripts.slice() : [];

    // setup model events and add model factory to instance
    model.setup(instance);
    instance._model = model.factory;

    // setup view events and add model factory to instance
    instance._view = view(instance);

    // handle send configurations
    if (!compInst.links) {
        compInst.links = [];
    }

    // set up core send events
    compInst.links.push({event: env.Z_SEND_INST_REQ, call: load});
    compInst.links.push({event: env.Z_SEND_MODEL_REQ, call: instance._modelService});
    compInst.links.push({event: env.Z_SEND_VIEW_REQ, call: instance._viewService});

    // attach the broadcast functionality
    instance._broadcast = broadcast;

    // add fingerprints to scripts
    fingerprint.addToFiles(instance._module, instance._scripts, function (err, scripts) {

        if (err) {
            return callback(err);
        }

        // update scripts
        if (scripts) {
            instance._client.L.scripts = scripts;
        }

        // send original instance name to client, in case it's an alias
        if (compInst.name !== name) {
            instance._client.name = compInst.name;

            // save instance also under original name
            pojoInstances.set(compInst.name, instance);
        }

        // save instance in cache
        // TODO update this cache when a instance config changes
        pojoInstances.set(name, instance);

        // require and init mono module
        if (module.main) {

            try {
                var monoModule = require(env.Z_PATH_PROCESS_MODULES + instance._module + module.main);

                if (typeof monoModule === 'function') {
                    monoModule.call(instance, instance._config || {}, function (err) {

                        if (err) {
                            return callback(err);
                        }

                        // setup links
                        if (compInst.links) {
                            return linkSetup(instance, compInst.links, callback);
                        }

                        callback(null, instance._client);
                    });
                }
            } catch (err) {

                // remove instance from cache
                pojoInstances.rm(name);

                callback('Module ' + compInst.name + ' init error: ' + err.toString());
            }
        } else {

            // setup links
            if (compInst.links) {
                return linkSetup(instance, compInst.links, callback);
            }

            callback(null, instance._client);
        }
    }, true);
}

// init module with newly created module instance as this
function loadinstance (name, role, callback) {

    // get and set model config from composition store
    compInstances.set(name, role, function (err, instance) {

        if (err) {
            return callback(err);
        }
        // check access
        if (!instance) {
            return callback(new Error('Instance ' + name + ' not found.'));
        }

        compModules.set(instance.module, role, function (err, module) {

            if (err) {
                return callback(err);
            }

            // check access
            if (!module) {
                return callback(new Error('Module ' + instance.module + ' not found.'));
            }

            instanceFactory(name, module, instance, callback);
        });
    });
}

// load instance configuration (ws)
function load (err, instance, callback) {
    var self = this;

    // send client config from cache
    var cachedInstance = pojoInstances.get(instance, self.link.role);

    // handle no access case
    if (cachedInstance === 0) {
        return callback('Instance: ' + instance + '. Error: Instance not found.');
    }

    if (cachedInstance) {
        return callback(null, cachedInstance._client);
    }

    // load and init module
    loadinstance(instance, self.link.role, function (err, client) {

        if (err) {
            return callback('Instance: ' + instance + '. Error: ' + err);
        }

        // return client config
        callback(null, client);
    });
}

// init the core module
function init () {
    var instance = new EventEmitter();

    instance._module = 'core',
    instance._name = env.Z_CORE_INST,
    instance._access = {},

    // set public rights to core module
    instance._roles = {'*': true};

    // set core module access
    instance._access[env.Z_SEND_INST_REQ] = true;
    instance._access[env.Z_SEND_MODULE_REQ] = true;
    instance._access[env.Z_SEND_CLIENT_REQ] = true;

    // setup client event interface
    instance.on(env.Z_SEND_INST_REQ, function (err, data) {
        var self = this;
        load.call(self, err, data, sendHandler(instance._name, self));
    });
    instance.on(env.Z_SEND_MODULE_REQ, moduleFiles);
    instance.on(env.Z_SEND_CLIENT_REQ, client);

    // setup model events and add model factory to instance
    model.setup(instance);
    instance._model = model.factory;

    // attach the broadcast functionality
    instance._broadcast = broadcast;

    // init mono module and save in cache
    pojoInstances.set(instance._name, instance);
}

// load client module files (http)
function moduleFiles () {
    var self = this;

    var source = self.link.path[0];
    var owner = self.link.path[1];
    var name = self.link.path[2];
    var version = self.link.path[3];

    // check if request format is correct
    if (!source || !owner || !name || !version) {
        return self.link.send(400, "Incorrect module request URL format");
    }

    // the module name must be almost alphanumeric
    if (self.link.pathname.replace(/[^a-z0-9\/\.\-_@]|\.\.\//gi, "") !== self.link.pathname) {
        return self.link.send(400, "Incorrect data in module request URL");
    }

    // create file path
    var moduleFile = self.link.path.join('/');
    var path = env.Z_PATH_PROCESS_MODULES + moduleFile;

    // save compressed/compiled script in cache and send it to the client
    fileClient.set(path, function (err, script) {

        if (err) {
            self.link.res.writeHead(500, {'content-type': 'text/plain'});
            return self.link.res.end(err.toString());
        }

        self.link.res.writeHead(200, script.http);
        self.link.res.end(script.data);
        return;
    }, null, moduleFile);
}

// get mono client (http)
function client (){
    var self = this;
    var path = env.Z_PATH_CLIENT + self.link.path[0];

    // save compressed/compiled script in cache and send it to the client
    fileClient.set(path, function (err, script) {

        if (err) {
            self.link.res.writeHead(500, {'content-type': 'text/plain'});
            return self.link.res.end(err.toString());
        }

        self.link.res.writeHead(200, script.http);
        self.link.res.end(script.data);
        return;
    });
}
<|endoftext|>


<commit_before>"use babel"

const _ = require("underscore-plus")

const {saveEditorState, getNonWordCharactersForCursor, searchByProjectFind} = require("./utils")
const SearchModel = require("./search-model")
const Motion = require("./base").getClass("Motion")

class SearchBase extends Motion {
  jump = true
  backwards = false
  useRegexp = true
  caseSensitivityKind = null
  landingPoint = null // ['start' or 'end']
  defaultLandingPoint = "start" // ['start' or 'end']
  relativeIndex = null
  updatelastSearchPattern = true

  isBackwards() {
    return this.backwards
  }

  isIncrementalSearch() {
    return this.instanceof("Search") && !this.repeated && this.getConfig("incrementalSearch")
  }

  constructor(...args) {
    super(...args)
    this.onDidFinishOperation(() => this.finish())
  }

  getCount(...args) {
    return super.getCount(...args) * (this.isBackwards() ? -1 : 1)
  }

  finish() {
    if (this.isIncrementalSearch() && this.getConfig("showHoverSearchCounter")) {
      this.vimState.hoverSearchCounter.reset()
    }
    if (this.searchModel) this.searchModel.destroy()

    this.relativeIndex = null
    this.searchModel = null
  }

  getLandingPoint() {
    if (!this.landingPoint) this.landingPoint = this.defaultLandingPoint
    return this.landingPoint
  }

  getPoint(cursor) {
    if (this.searchModel) {
      this.relativeIndex = this.getCount() + this.searchModel.getRelativeIndex()
    } else if (this.relativeIndex == null) {
      this.relativeIndex = this.getCount()
    }

    const range = this.search(cursor, this.input, this.relativeIndex)

    this.searchModel.destroy()
    this.searchModel = null

    if (range) return range[this.getLandingPoint()]
  }

  moveCursor(cursor) {
    if (!this.input) return
    const point = this.getPoint(cursor)

    if (point) cursor.setBufferPosition(point, {autoscroll: false})

    if (!this.repeated) {
      this.globalState.set("currentSearch", this)
      this.vimState.searchHistory.save(this.input)
    }

    if (this.updatelastSearchPattern) {
      this.globalState.set("lastSearchPattern", this.getPattern(this.input))
    }
  }

  getSearchModel() {
    if (!this.searchModel) {
      this.searchModel = new SearchModel(this.vimState, {incrementalSearch: this.isIncrementalSearch()})
    }
    return this.searchModel
  }

  search(cursor, input, relativeIndex) {
    const searchModel = this.getSearchModel()
    if (input) {
      const fromPoint = this.getBufferPositionForCursor(cursor)
      return searchModel.search(fromPoint, this.getPattern(input), relativeIndex)
    }
    this.vimState.hoverSearchCounter.reset()
    searchModel.clearMarkers()
  }
}
SearchBase.initClass(false)

// /, ?
// -------------------------
class Search extends SearchBase {
  caseSensitivityKind = "Search"
  requireInput = true

  constructor(...args) {
    super(...args)

    if (!this.isComplete()) {
      if (this.isIncrementalSearch()) {
        this.restoreEditorState = saveEditorState(this.editor)
        this.onDidCommandSearch(this.handleCommandEvent.bind(this))
      }

      this.onDidConfirmSearch(this.handleConfirmSearch.bind(this))
      this.onDidCancelSearch(this.handleCancelSearch.bind(this))
      this.onDidChangeSearch(this.handleChangeSearch.bind(this))

      this.focusSearchInputEditor()
    }
  }

  focusSearchInputEditor() {
    const classList = this.backwards ? ["backwards"] : []
    this.vimState.searchInput.focus({classList})
  }

  handleCommandEvent(event) {
    if (!event.input) return

    if (event.name === "visit") {
      let {direction} = event
      if (this.isBackwards() && this.getConfig("incrementalSearchVisitDirection") === "relative") {
        direction = direction === "next" ? "prev" : "next"
      }
      this.getSearchModel().visit(direction === "next" ? +1 : -1)
    } else if (event.name === "occurrence") {
      const {operation, input} = event
      this.vimState.occurrenceManager.addPattern(this.getPattern(input), {reset: operation != null})
      this.vimState.occurrenceManager.saveLastPattern()

      this.vimState.searchHistory.save(input)
      this.vimState.searchInput.cancel()
      if (operation != null) this.vimState.operationStack.run(operation)
    } else if (event.name === "project-find") {
      this.vimState.searchHistory.save(event.input)
      this.vimState.searchInput.cancel()
      searchByProjectFind(this.editor, event.input)
    }
  }

  handleCancelSearch() {
    if (!["visual", "insert"].includes(this.mode)) this.vimState.resetNormalMode()

    if (this.restoreEditorState) this.restoreEditorState()
    this.vimState.reset()
    this.finish()
  }

  isSearchRepeatCharacter(char) {
    return this.isIncrementalSearch() ? char === "" : ["", this.isBackwards() ? "?" : "/"].includes(char) // empty confirm or invoking-char
  }

  handleConfirmSearch({input, landingPoint}) {
    this.input = input
    this.landingPoint = landingPoint
    if (this.isSearchRepeatCharacter(this.input)) {
      this.input = this.vimState.searchHistory.get("prev")
      if (!this.input) atom.beep()
    }
    this.processOperation()
  }

  handleChangeSearch(input) {
    // If input starts with space, remove first space and disable useRegexp.
    if (input.startsWith(" ")) {
      // FIXME: Sould I remove this unknown hack and implement visible button to togle regexp?
      input = input.replace(/^ /, "")
      this.useRegexp = false
    }
    this.vimState.searchInput.updateOptionSettings({useRegexp: this.useRegexp})

    if (this.isIncrementalSearch()) {
      this.search(this.editor.getLastCursor(), input, this.getCount())
    }
  }

  getPattern(term) {
    let modifiers = this.isCaseSensitive(term) ? "g" : "gi"
    // FIXME this prevent search \\c itself.
    // DONT thinklessly mimic pure Vim. Instead, provide ignorecase button and shortcut.
    if (term.indexOf("\\c") >= 0) {
      term = term.replace("\\c", "")
      if (!modifiers.includes("i")) modifiers += "i"
    }

    if (this.useRegexp) {
      try {
        return new RegExp(term, modifiers)
      } catch (error) {
        null
      }
    }

    return new RegExp(_.escapeRegExp(term), modifiers)
  }
}
Search.initClass()

class SearchBackwards extends Search {
  backwards = true
}
SearchBackwards.initClass()

// *, #
// -------------------------
class SearchCurrentWord extends SearchBase {
  caseSensitivityKind = "SearchCurrentWord"

  moveCursor(cursor) {
    if (this.input == null) {
      const wordRange = this.getCurrentWordBufferRange()
      if (wordRange) {
        this.editor.setCursorBufferPosition(wordRange.start)
        this.input = this.editor.getTextInBufferRange(wordRange)
      } else {
        this.input = ""
      }
    }

    super.moveCursor(cursor)
  }

  getPattern(term) {
    const escaped = _.escapeRegExp(term)
    const source = /\W/.test(term) ? `${escaped}\\b` : `\\b${escaped}\\b`
    return new RegExp(source, this.isCaseSensitive(term) ? "g" : "gi")
  }

  getCurrentWordBufferRange() {
    const cursor = this.editor.getLastCursor()
    const point = cursor.getBufferPosition()

    const nonWordCharacters = getNonWordCharactersForCursor(cursor)
    const wordRegex = new RegExp(`[^\\s${_.escapeRegExp(nonWordCharacters)}]+`, "g")

    let foundRange
    this.scanForward(wordRegex, {from: [point.row, 0], allowNextLine: false}, ({range, stop}) => {
      if (range.end.isGreaterThan(point)) {
        foundRange = range
        stop()
      }
    })
    return foundRange
  }
}
SearchCurrentWord.initClass()

class SearchCurrentWordBackwards extends SearchCurrentWord {
  backwards = true
}
SearchCurrentWordBackwards.initClass()
<commit_msg>cleanup<commit_after>"use babel"

const _ = require("underscore-plus")

const {saveEditorState, getNonWordCharactersForCursor, searchByProjectFind} = require("./utils")
const SearchModel = require("./search-model")
const Motion = require("./base").getClass("Motion")

class SearchBase extends Motion {
  jump = true
  backwards = false
  useRegexp = true
  caseSensitivityKind = null
  landingPoint = null // ['start' or 'end']
  defaultLandingPoint = "start" // ['start' or 'end']
  relativeIndex = null
  updatelastSearchPattern = true

  isBackwards() {
    return this.backwards
  }

  isIncrementalSearch() {
    return this.instanceof("Search") && !this.repeated && this.getConfig("incrementalSearch")
  }

  constructor(...args) {
    super(...args)
    this.onDidFinishOperation(() => this.finish())
  }

  getCount(...args) {
    return super.getCount(...args) * (this.isBackwards() ? -1 : 1)
  }

  finish() {
    if (this.isIncrementalSearch() && this.getConfig("showHoverSearchCounter")) {
      this.vimState.hoverSearchCounter.reset()
    }
    if (this.searchModel) this.searchModel.destroy()

    this.relativeIndex = null
    this.searchModel = null
  }

  getLandingPoint() {
    if (!this.landingPoint) this.landingPoint = this.defaultLandingPoint
    return this.landingPoint
  }

  getPoint(cursor) {
    if (this.searchModel) {
      this.relativeIndex = this.getCount() + this.searchModel.getRelativeIndex()
    } else if (this.relativeIndex == null) {
      this.relativeIndex = this.getCount()
    }

    const range = this.search(cursor, this.input, this.relativeIndex)

    this.searchModel.destroy()
    this.searchModel = null

    if (range) return range[this.getLandingPoint()]
  }

  moveCursor(cursor) {
    if (!this.input) return
    const point = this.getPoint(cursor)

    if (point) cursor.setBufferPosition(point, {autoscroll: false})

    if (!this.repeated) {
      this.globalState.set("currentSearch", this)
      this.vimState.searchHistory.save(this.input)
    }

    if (this.updatelastSearchPattern) {
      this.globalState.set("lastSearchPattern", this.getPattern(this.input))
    }
  }

  getSearchModel() {
    if (!this.searchModel) {
      this.searchModel = new SearchModel(this.vimState, {incrementalSearch: this.isIncrementalSearch()})
    }
    return this.searchModel
  }

  search(cursor, input, relativeIndex) {
    const searchModel = this.getSearchModel()
    if (input) {
      const fromPoint = this.getBufferPositionForCursor(cursor)
      return searchModel.search(fromPoint, this.getPattern(input), relativeIndex)
    }
    this.vimState.hoverSearchCounter.reset()
    searchModel.clearMarkers()
  }
}
SearchBase.initClass(false)

// /, ?
// -------------------------
class Search extends SearchBase {
  caseSensitivityKind = "Search"
  requireInput = true

  constructor(...args) {
    super(...args)

    if (!this.isComplete()) {
      if (this.isIncrementalSearch()) {
        this.restoreEditorState = saveEditorState(this.editor)
        this.onDidCommandSearch(this.handleCommandEvent.bind(this))
      }

      this.onDidConfirmSearch(this.handleConfirmSearch.bind(this))
      this.onDidCancelSearch(this.handleCancelSearch.bind(this))
      this.onDidChangeSearch(this.handleChangeSearch.bind(this))

      this.focusSearchInputEditor()
    }
  }

  focusSearchInputEditor() {
    const classList = this.backwards ? ["backwards"] : []
    this.vimState.searchInput.focus({classList})
  }

  handleCommandEvent(event) {
    if (!event.input) return

    if (event.name === "visit") {
      let {direction} = event
      if (this.isBackwards() && this.getConfig("incrementalSearchVisitDirection") === "relative") {
        direction = direction === "next" ? "prev" : "next"
      }
      this.getSearchModel().visit(direction === "next" ? +1 : -1)
    } else if (event.name === "occurrence") {
      const {operation, input} = event
      this.vimState.occurrenceManager.addPattern(this.getPattern(input), {reset: operation != null})
      this.vimState.occurrenceManager.saveLastPattern()

      this.vimState.searchHistory.save(input)
      this.vimState.searchInput.cancel()
      if (operation != null) this.vimState.operationStack.run(operation)
    } else if (event.name === "project-find") {
      this.vimState.searchHistory.save(event.input)
      this.vimState.searchInput.cancel()
      searchByProjectFind(this.editor, event.input)
    }
  }

  handleCancelSearch() {
    if (!["visual", "insert"].includes(this.mode)) this.vimState.resetNormalMode()

    if (this.restoreEditorState) this.restoreEditorState()
    this.vimState.reset()
    this.finish()
  }

  isSearchRepeatCharacter(char) {
    return this.isIncrementalSearch() ? char === "" : ["", this.isBackwards() ? "?" : "/"].includes(char) // empty confirm or invoking-char
  }

  handleConfirmSearch({input, landingPoint}) {
    this.input = input
    this.landingPoint = landingPoint
    if (this.isSearchRepeatCharacter(this.input)) {
      this.input = this.vimState.searchHistory.get("prev")
      if (!this.input) atom.beep()
    }
    this.processOperation()
  }

  handleChangeSearch(input) {
    // If input starts with space, remove first space and disable useRegexp.
    if (input.startsWith(" ")) {
      // FIXME: Sould I remove this unknown hack and implement visible button to togle regexp?
      input = input.replace(/^ /, "")
      this.useRegexp = false
    }
    this.vimState.searchInput.updateOptionSettings({useRegexp: this.useRegexp})

    if (this.isIncrementalSearch()) {
      this.search(this.editor.getLastCursor(), input, this.getCount())
    }
  }

  getPattern(term) {
    let modifiers = this.isCaseSensitive(term) ? "g" : "gi"
    // FIXME this prevent search \\c itself.
    // DONT thinklessly mimic pure Vim. Instead, provide ignorecase button and shortcut.
    if (term.indexOf("\\c") >= 0) {
      term = term.replace("\\c", "")
      if (!modifiers.includes("i")) modifiers += "i"
    }

    if (this.useRegexp) {
      try {
        return new RegExp(term, modifiers)
      } catch (error) {}
    }
    return new RegExp(_.escapeRegExp(term), modifiers)
  }
}
Search.initClass()

class SearchBackwards extends Search {
  backwards = true
}
SearchBackwards.initClass()

// *, #
// -------------------------
class SearchCurrentWord extends SearchBase {
  caseSensitivityKind = "SearchCurrentWord"

  moveCursor(cursor) {
    if (this.input == null) {
      const wordRange = this.getCurrentWordBufferRange()
      if (wordRange) {
        this.editor.setCursorBufferPosition(wordRange.start)
        this.input = this.editor.getTextInBufferRange(wordRange)
      } else {
        this.input = ""
      }
    }

    super.moveCursor(cursor)
  }

  getPattern(term) {
    const escaped = _.escapeRegExp(term)
    const source = /\W/.test(term) ? `${escaped}\\b` : `\\b${escaped}\\b`
    return new RegExp(source, this.isCaseSensitive(term) ? "g" : "gi")
  }

  getCurrentWordBufferRange() {
    const cursor = this.editor.getLastCursor()
    const point = cursor.getBufferPosition()

    const nonWordCharacters = getNonWordCharactersForCursor(cursor)
    const wordRegex = new RegExp(`[^\\s${_.escapeRegExp(nonWordCharacters)}]+`, "g")

    let foundRange
    this.scanForward(wordRegex, {from: [point.row, 0], allowNextLine: false}, ({range, stop}) => {
      if (range.end.isGreaterThan(point)) {
        foundRange = range
        stop()
      }
    })
    return foundRange
  }
}
SearchCurrentWord.initClass()

class SearchCurrentWordBackwards extends SearchCurrentWord {
  backwards = true
}
SearchCurrentWordBackwards.initClass()
<|endoftext|>


<commit_before>/**
 * Copyright reelyActive 2014-2021
 * We believe in an open Internet of Things
 */

const advlib = require('advlib');

const DEFAULT_PROCESSORS = {};
const DEFAULT_DYNAMB_PROPERTIES = [
    'acceleration',
    'batteryPercentage',
    'batteryVoltage',
    'nearest', // TODO: potentially move to a more suitable data structure
    'relativeHumidity',
    'temperature'
];
const DEFAULT_STATID_PROPERTIES = [
    'appearance',
    'deviceIds',
    'name',
    'uri',
    'uuids',
    'version'
];

/**
 * PacketManager Class
 * Handles the decoding of packets and classification of their data.
 */
class PacketManager {

  /**
   * PacketManager constructor
   * @param {Barnacles} barnacles The barnacles instance.
   * @param {StoreManager} store The data store interface.
   * @param {Object} options The options as a JSON object.
   * @constructor
   */
  constructor(barnacles, store, options) {
    options = options || {};

    this.processors = options.packetProcessors || DEFAULT_PROCESSORS;
    this.barnacles = barnacles;
    this.store = store;
    this.dynambProperties = options.dynambProperties ||
                            DEFAULT_DYNAMB_PROPERTIES;
    this.statidProperties = options.statidProperties ||
                            DEFAULT_STATID_PROPERTIES;
  }

  /**
   * Handle the packets in the given raddec.
   * @param {Raddec} raddec The raddec with packets to be handled.
   */
  handleRaddec(raddec) {
    let self = this;
    let isDynamic = false;
    let isStatid = false;
    let dynamb = { deviceId: raddec.transmitterId,
                   deviceIdType: raddec.transmitterIdType,
                   timestamp: raddec.initialTime };
    let statid = { deviceId: raddec.transmitterId,
                   deviceIdType: raddec.transmitterIdType };
    let data = {};

    try {
      data = advlib.process(raddec.packets, self.processors);
    }
    catch(error) {}

    for(const property in data) {
      if(self.dynambProperties.includes(property)) {
        dynamb[property] = data[property];
        isDynamic = true;
      }
      else if(self.statidProperties.includes(property)) {
        statid[property] = data[property];
        isStatid = true;
      }
    }

    if(isDynamic) {
      self.barnacles.handleEvent('dynamb', dynamb);
      self.store.insertDynamb(dynamb);
    }

    if(isStatid) {
      self.store.insertStatid(statid);
    }
  }
}

module.exports = PacketManager;
<commit_msg>Added default dynamb properties<commit_after>/**
 * Copyright reelyActive 2014-2021
 * We believe in an open Internet of Things
 */

const advlib = require('advlib');

const DEFAULT_PROCESSORS = {};
const DEFAULT_DYNAMB_PROPERTIES = [
    'acceleration',
    'batteryPercentage',
    'batteryVoltage',
    'interactionDigest',
    'nearest',
    'relativeHumidity',
    'temperature',
    'txCount',
    'uptime'
];
const DEFAULT_STATID_PROPERTIES = [
    'appearance',
    'deviceIds',
    'name',
    'uri',
    'uuids',
    'version'
];

/**
 * PacketManager Class
 * Handles the decoding of packets and classification of their data.
 */
class PacketManager {

  /**
   * PacketManager constructor
   * @param {Barnacles} barnacles The barnacles instance.
   * @param {StoreManager} store The data store interface.
   * @param {Object} options The options as a JSON object.
   * @constructor
   */
  constructor(barnacles, store, options) {
    options = options || {};

    this.processors = options.packetProcessors || DEFAULT_PROCESSORS;
    this.barnacles = barnacles;
    this.store = store;
    this.dynambProperties = options.dynambProperties ||
                            DEFAULT_DYNAMB_PROPERTIES;
    this.statidProperties = options.statidProperties ||
                            DEFAULT_STATID_PROPERTIES;
  }

  /**
   * Handle the packets in the given raddec.
   * @param {Raddec} raddec The raddec with packets to be handled.
   */
  handleRaddec(raddec) {
    let self = this;
    let isDynamic = false;
    let isStatid = false;
    let dynamb = { deviceId: raddec.transmitterId,
                   deviceIdType: raddec.transmitterIdType,
                   timestamp: raddec.initialTime };
    let statid = { deviceId: raddec.transmitterId,
                   deviceIdType: raddec.transmitterIdType };
    let data = {};

    try {
      data = advlib.process(raddec.packets, self.processors);
    }
    catch(error) {}

    for(const property in data) {
      if(self.dynambProperties.includes(property)) {
        dynamb[property] = data[property];
        isDynamic = true;
      }
      else if(self.statidProperties.includes(property)) {
        statid[property] = data[property];
        isStatid = true;
      }
    }

    if(isDynamic) {
      self.barnacles.handleEvent('dynamb', dynamb);
      self.store.insertDynamb(dynamb);
    }

    if(isStatid) {
      self.store.insertStatid(statid);
    }
  }
}

module.exports = PacketManager;
<|endoftext|>


<commit_before>"use strict";

var _ = require( "lodash" ),
    entities = require( "entities" );

function decodeText( text ){
    return entities.decodeHTML( text );
}

/**
 * 関連付けされたテンプレートのIDを返却する。
 * @return {String|null}
 */
function detectTemplateId( HTMLCode ){

    var commentTagPattern = /<!--\s*InstanceBegin\s+template="\/([^"]+)"\s*[^>]*-->/,
        matchingResult = HTMLCode.match( commentTagPattern );

    if( matchingResult ){
        return matchingResult[1];
    }
    else {
        return null;
    }
}

/**
 * ハッシュで与えられたパターンにマッチする文字列をすべて置換して返却する。
 * @param {String} src
 * @param {Object} patterns
 * @return {String}
 */
function replaceWithPatterns( src, patterns ){
    return _.reduce(
        patterns,
        function( replacedCode, replacement, pattern ){
            return replacedCode.replace( new RegExp( pattern, "gi" ), replacement, "gi" );
        },
        src
    );
}

/**
 * コメントタグで表現されたテンプレート処理用の記述を、DOMとしてパース可能なタグに置き換えて返却する。
 * @param {String} HTMLCode
 * @return {String} activated HTML code.
 */
function activateTemplateTags( HTMLCode ){
    return replaceWithPatterns( HTMLCode, {
        "<!--\\s+TemplateBeginEditable\\s+name=\"([^\"]+)\"\\s+-->": "<TemplateEditable name=\"$1\">",
        "<!--\\s+TemplateEndEditable\\s+-->": "</TemplateEditable>"
    } );
}

/**
 * コメントタグで表現されたテンプレート処理用の記述を、DOMとしてパース可能なタグに置き換えて返却する。
 * @param {String} HTMLCode
 * @return {String} activated HTML code.
 */
function activateInstanceTags( HTMLCode ){
    return replaceWithPatterns( HTMLCode, {
        "<!--\\s+InstanceBeginEditable\\s+name=\"([^\"]+)\"\\s+-->": "<InstanceEditable name=\"$1\">",
        "<!--\\s+InstanceEndEditable\\s+-->": "</InstanceEditable>"
    } );
}

/**
 * <!-- Instance〜 -->を除外したコードを返却する。
 * @param {String} HTMLCode
 * @return {String}
 *
 * @deprecated
 */
function excludeInstanceTags( HTMLCode ){
    return HTMLCode.replace( /<!-- Instance[^>]+ -->/ig, "", "gi" );
}

module.exports = {
    decodeText: decodeText,
    detectTemplateId: detectTemplateId,
    activateTemplateTags: activateTemplateTags,
    activateInstanceTags: activateInstanceTags,
    excludeInstanceTags: excludeInstanceTags
};
<commit_msg>ログ出力用のユーティリティ<commit_after>"use strict";

var _ = require( "lodash" ),
    entities = require( "entities" );

var DEBUG = process.env[ "HTMLCOMMENTTEMPLATE_DEBUG" ] && process.env[ "HTMLCOMMENTTEMPLATE_DEBUG" ] === "true";

function log(){
    if( !DEBUG ){ return; }
    console.log( [].slice.call( arguments ) );
}

function decodeText( text ){
    return entities.decodeHTML( text );
}

/**
 * 関連付けされたテンプレートのIDを返却する。
 * @return {String|null}
 */
function detectTemplateId( HTMLCode ){

    var commentTagPattern = /<!--\s*InstanceBegin\s+template="\/([^"]+)"\s*[^>]*-->/,
        matchingResult = HTMLCode.match( commentTagPattern );

    if( matchingResult ){
        return matchingResult[1];
    }
    else {
        return null;
    }
}

/**
 * ハッシュで与えられたパターンにマッチする文字列をすべて置換して返却する。
 * @param {String} src
 * @param {Object} patterns
 * @return {String}
 */
function replaceWithPatterns( src, patterns ){
    return _.reduce(
        patterns,
        function( replacedCode, replacement, pattern ){
            return replacedCode.replace( new RegExp( pattern, "gi" ), replacement, "gi" );
        },
        src
    );
}

/**
 * コメントタグで表現されたテンプレート処理用の記述を、DOMとしてパース可能なタグに置き換えて返却する。
 * @param {String} HTMLCode
 * @return {String} activated HTML code.
 */
function activateTemplateTags( HTMLCode ){
    return replaceWithPatterns( HTMLCode, {
        "<!--\\s+TemplateBeginEditable\\s+name=\"([^\"]+)\"\\s+-->": "<TemplateEditable name=\"$1\">",
        "<!--\\s+TemplateEndEditable\\s+-->": "</TemplateEditable>"
    } );
}

/**
 * コメントタグで表現されたテンプレート処理用の記述を、DOMとしてパース可能なタグに置き換えて返却する。
 * @param {String} HTMLCode
 * @return {String} activated HTML code.
 */
function activateInstanceTags( HTMLCode ){
    return replaceWithPatterns( HTMLCode, {
        "<!--\\s+InstanceBeginEditable\\s+name=\"([^\"]+)\"\\s+-->": "<InstanceEditable name=\"$1\">",
        "<!--\\s+InstanceEndEditable\\s+-->": "</InstanceEditable>"
    } );
}

/**
 * <!-- Instance〜 -->を除外したコードを返却する。
 * @param {String} HTMLCode
 * @return {String}
 *
 * @deprecated
 */
function excludeInstanceTags( HTMLCode ){
    return HTMLCode.replace( /<!-- Instance[^>]+ -->/ig, "", "gi" );
}

module.exports = {
    log: log,
    decodeText: decodeText,
    detectTemplateId: detectTemplateId,
    activateTemplateTags: activateTemplateTags,
    activateInstanceTags: activateInstanceTags,
    excludeInstanceTags: excludeInstanceTags
};
<|endoftext|>