<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2019  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('15.14.0');
		this.setClientTag('node:19-12-29');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2019  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('15.14.0');
		this.setClientTag('node:19-12-30');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2019  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.12.0');
		this.setClientTag('node:19-01-22');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platfroms allow them to do with
// text.
//
// Copyright (C) 2006-2019  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('14.12.0');
		this.setClientTag('node:19-01-23');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platforms allow them to do with
// text.
//
// Copyright (C) 2006-2022  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('18.9.0');
		this.setClientTag('node:22-07-22');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<commit_msg>New clientlib ver<commit_after>// ===================================================================================================
//                           _  __     _ _
//                          | |/ /__ _| | |_ _  _ _ _ __ _
//                          | ' </ _` | |  _| || | '_/ _` |
//                          |_|\_\__,_|_|\__|\_,_|_| \__,_|
//
// This file is part of the Kaltura Collaborative Media Suite which allows users
// to do with audio, video, and animation what Wiki platforms allow them to do with
// text.
//
// Copyright (C) 2006-2022  Kaltura Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// @ignore
// ===================================================================================================
/**
 * The Kaltura Client - this is the facade through which all service actions should be called.
 * @param config the Kaltura configuration object holding partner credentials (type: KalturaConfiguration).
 */
var util = require('util');
var kaltura = require('./KalturaClientBase');
kaltura.services = require('./KalturaServices');
kaltura.objects = require('./KalturaModel');
kaltura.enums = require('./KalturaTypes');

class Client extends kaltura.ClientBase {

	/**
	 * @param Configuration config
	 */
	constructor(config) {
		super(config);
		this.setApiVersion('18.9.0');
		this.setClientTag('node:22-07-23');
	}
}

module.exports = kaltura;
module.exports.Client = Client;

<|endoftext|>


<commit_before>define(['../node_modules/pown/pown', '../shim'], function(pown, shim) {
  var Context = function(mediaElement) {
    // Set up audio context
    var context     = new shim.AudioContext();
    var source      = this.set('source',
                               context.createMediaElementSource(mediaElement));
    var analyser    = this.set('analyser', context.createAnalyser());
    var loFilter    = this.set('loFilter', context.createBiquadFilter());
    var hiFilter    = this.set('hiFilter', context.createBiquadFilter());
    var destination = this.set('destination', context.destination);

    // Set filter types
    loFilter.type = 'lowshelf';
    hiFilter.type = 'highshelf';
    // Cache filter ranges
    var freqBase = loFilter.frequency.minValue;
    var gainBase = loFilter.gain.minValue;
    var freqRange = loFilter.frequency.maxValue - freqBase;
    var gainRange = loFilter.gain.maxValue - gainBase;

    // Register analyser/filter listeners
    this.on('change', function(ctx, opt) {
      var filter;

      switch (opt.p) {
        case 'smooth':
          analyser.smoothingTimeConstant = opt.n;
          break;
        case 'fft':
          analyser.fftSize = opt.n;
          break;
        case 'loFreq':
          filter = loFilter;
        case 'hiFreq':
          filter = hiFilter;
          filter.frequency.value = freqBase + freqRange * opt.n;
          break;
        case 'loGain':
          filter = loFilter;
        case 'hiGain':
          filter = hiFilter;
          filter.gain.value = gainBase + gainRange * opt.n;
      }
    });

    // Initialize filter values
    this.set('loFreq', 0.5);
    this.set('hiFreq', 0.5);
    this.set('loGain', 0.5);
    this.set('hiGain', 0.5);

    // Connect audio context
    source.connect(analyser);
    analyser.connect(loFilter);
    loFilter.connect(hiFilter);
    hiFilter.connect(destination);

    // Bind listener callbacks
    var loadstart = this.trigger.bind(this, 'loadstart');
    var play = this.trigger.bind(this, 'play');
    var pause = this.trigger.bind(this, 'pause');

    // Register media listeners
    mediaElement.addEventListener('loadstart', loadstart);
    mediaElement.addEventListener('play', play);
    mediaElement.addEventListener('pause', pause);
  };

  Context.prototype = Object.create(pown);

  return Context;
});<commit_msg>Exposed play method in Context module.<commit_after>define(['../node_modules/pown/pown', '../shim'], function(pown, shim) {
  var Context = function(mediaElement) {
    this.mediaElement = mediaElement;
    // Set up audio context
    var context     = new shim.AudioContext();
    var source      = this.set('source',
                               context.createMediaElementSource(mediaElement));
    var analyser    = this.set('analyser', context.createAnalyser());
    var loFilter    = this.set('loFilter', context.createBiquadFilter());
    var hiFilter    = this.set('hiFilter', context.createBiquadFilter());
    var destination = this.set('destination', context.destination);

    // Set filter types
    loFilter.type = 'lowshelf';
    hiFilter.type = 'highshelf';
    // Cache filter ranges
    var freqBase = loFilter.frequency.minValue;
    var gainBase = loFilter.gain.minValue;
    var freqRange = loFilter.frequency.maxValue - freqBase;
    var gainRange = loFilter.gain.maxValue - gainBase;

    // Register analyser/filter listeners
    this.on('change', function(ctx, opt) {
      var filter;

      switch (opt.p) {
        case 'smooth':
          analyser.smoothingTimeConstant = opt.n;
          break;
        case 'fft':
          analyser.fftSize = opt.n;
          break;
        case 'loFreq':
          filter = loFilter;
        case 'hiFreq':
          filter = hiFilter;
          filter.frequency.value = freqBase + freqRange * opt.n;
          break;
        case 'loGain':
          filter = loFilter;
        case 'hiGain':
          filter = hiFilter;
          filter.gain.value = gainBase + gainRange * opt.n;
      }
    });

    // Initialize filter values
    this.set('loFreq', 0.5);
    this.set('hiFreq', 0.5);
    this.set('loGain', 0.5);
    this.set('hiGain', 0.5);

    // Connect audio context
    source.connect(analyser);
    analyser.connect(loFilter);
    loFilter.connect(hiFilter);
    hiFilter.connect(destination);

    // Bind listener callbacks
    var loadstart = this.trigger.bind(this, 'loadstart');
    var play = this.trigger.bind(this, 'play');
    var pause = this.trigger.bind(this, 'pause');

    // Register media listeners
    mediaElement.addEventListener('loadstart', loadstart);
    mediaElement.addEventListener('play', play);
    mediaElement.addEventListener('pause', pause);
  };

  Context.prototype = Object.create(pown);

  // Expose forced play
  Context.prototype.play = function() {
    this.mediaElement.play();
  };

  return Context;
});<|endoftext|>


<commit_before>'use strict';
var MongooseAdminUser = require('./models/mongoose_admin_user.js').MongooseAdminUser,
    _ = require('underscore'),
    async = require('async'),
    permissions = require('./models/permissions'),
    mongoose = require.main.require('mongoose'),
    AdminForm = require('./AdminForm').AdminForm,
    forms = require('./forms').forms;

/**
 * MongooseAdmin Constructor
 *
 * @api private
 */
var MongooseAdmin = module.exports = function (app, root) {
    this.app = app;
    this.root = root;
    this.models = {};
    this.title = "Backoffice";
};

/**
 * Build a full path that can be used in a URL
 *
 * @param {String} path
 */
MongooseAdmin.prototype.buildPath = function(path) {
    return this.root + path;
};

MongooseAdmin.prototype.getAdminTitle = function() {
    return this.title;
};

MongooseAdmin.prototype.setAdminTitle = function(title) {
    this.title = title;
};

/**
 * Stop listening and end the admin process
 *
 * @api public
 */
MongooseAdmin.prototype.close = function() {
    this.app.close();
};

function buildModelFilters (model, filters, dict) {
    if (!filters)
        return;

    setTimeout(function () {
        async.forEach(
            filters,
            function (filter, cbk) {
                model.collection.distinct(filter, function (err, results) {
                    if (results) {
                        if (results[0] && Array.isArray(results[0])) {
                            results = _.flatten(results);
                        }
                        if (results.length > 30)
                            results.splice(5);
                        if (model.schema.paths[filter] && model.schema.paths[filter].options.ref) {
                            mongoose.model(model.schema.paths[filter].options.ref).find()
                                .where('_id').in(results)
                                .exec(function (err, refs) {
                                    if (refs)
                                        dict.push({ key: filter, isString: false, values: _.map(refs, function (ref) {
                                            return { value: ref.id, text: ref.toString()};
                                        }) });
                                    cbk(err);
                                });
                        }
                        else {
                            dict.push({key: filter, values: _.map(results, function (result) {
                                return { value: result, text: result, isString: model.schema.paths[filter] && model.schema.paths[filter].options && model.schema.paths[filter].options.type == String };
                            })});
                            cbk();
                        }
                    }
                    else
                        cbk(err);
                });

            }, function () {

            })
    }, 1000);
}

MongooseAdmin.prototype.registerMongooseModel = function (name, model, fields, options) {
    var models = this.models;

    model.label = model.label || name[0].toUpperCase() + name.slice(1).replace(/_/g,' ');

    options = options || {};
    options.actions = options.actions || [];
    options.actions.push({
        value: 'delete',
        label: 'Delete',
        func: function (user, ids, callback) {
            async.map(
                ids,
                function (id, cb) {
                    require('./dependencies').check(models, name, id, cb);
                },
                function (err, results) {
                    if (err) return callback(err);

                    var no_dependencies = ids.filter(function (result, index) {
                        return !results[index] || !results[index].length;
                    });
                    model.remove({_id: {$in: no_dependencies}}, callback);
                }
            );
        }
    });

    var filters = [];
    buildModelFilters(model, options.filters, filters);

    this.models[name] = {
        model: model,
        filters: filters,
        modelName: name,
        options: options,
        fields: fields
    };

    console.log('\x1b[36mformage-admin:\x1b[0m %s', name);

    permissions.registerModel(name);
};

MongooseAdmin.prototype.registerSingleRowModel = function(model, name, options) {
    model.label = model.label || name[0].toUpperCase() + name.slice(1).replace(/_/g,' ');

    model.is_single = true;
    this.models[name] = {
        model: model,
        options: options || {},
        fields: {},
        is_single: true,
        modelName: name
    };
    permissions.registerModel(name);
};

/**
* Register a new mongoose model/schema with admin
*
* @param {Object} model
* @param {String} name
* @param {Object} options
*
* @api public
*/
MongooseAdmin.prototype.registerModel = function(model, name, options) {
    this.models[name] = {
        model: model,
        modelName: name,
        options: options
    };
    console.log('\x1b[36mformage-admin:\x1b[0m %s', name);
};

/**
 * Retrieve a list of all registered models
 *
 * @param {Function} callback
 *
 * @api public
 */
MongooseAdmin.prototype.getRegisteredModels = function (user, callback) {
    var raw_models = this.models;
    var out_models = Object.keys(raw_models).map(function (collectionName) {
        var out_model = raw_models[collectionName];
        out_model.model.is_single = out_model.is_single;
        return out_model;
    }).filter(function (model) {
        return permissions.hasPermissions(user, model.modelName, 'view');
    });
    callback(null, out_models);
};

/**
 * Get a single model from the registered list with admin
 *
 * @param {String} collectionName
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.getModel = function(collectionName, onReady) {
    var model = this.models[collectionName];
    onReady(null, model.model, model.fields, model.options);
};

/**
 * Get the counts of a model
 *
 * @param {String} collectionName
 *
 * @api public
 */
MongooseAdmin.prototype.modelCounts = function(collectionName,filters, onReady) {
    if(this.models[collectionName].is_single) {
        onReady(null,1);
        return;
    }
    var model = this.models[collectionName].model;
    _.each(filters,function(value,key) {
        if(model.schema && typeof(value) == 'string') {
            var type = model.schema.paths[key].options.type;
            if(type == String)
                filters[key] = new RegExp(value,'i');
            else if(type == Number)
                filters[key] = Number(value) || undefined;
            else if(type == Boolean)
                filters[key] = Boolean(value === 'true');
        }
    });
    this.models[collectionName].model.count(filters, function(err, count) {
        if (err) {
            console.error('Unable to get counts for model because: ' + err);
            onReady(null,0);
        } else {
            onReady(null, count);
        }
    });
};

var IS_OLD_MONGOOSE = Number(mongoose.version.split('.')[0]) < 3;

function mongooseSort(query,sort) {
    if(IS_OLD_MONGOOSE) {
        if(sort[0] === '-')
            query.sort(sort.slice(1),'descending');
        else
            query.sort(sort,'ascending');
    }
    else
        query.sort(sort);
}

/**
 * List a page of documents from a model
 *
 * @param {String} collectionName
 * @param {Number} start
 * @param {Number} count
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.listModelDocuments = function(collectionName, start, count,filters,sort, onReady) {
    var listFields = this.models[collectionName].options.list;
    if(listFields)
    {
	    var model = this.models[collectionName].model;
        _.each(filters, function(value,key) {
            if(model.schema && typeof(value) == 'string') {
                var type = model.schema.paths[key].options.type;
                if(type == String)
                    filters[key] = new RegExp(value,'i');
                else if(type == Number)
                    filters[key] = Number(value) || undefined;
                else if(type == Boolean)
                    filters[key] = Boolean(value === 'true');
            }
        });
        var query = this.models[collectionName].model.find(filters);
        var sorts = this.models[collectionName].options.order_by || [];
        var populates = this.models[collectionName].options.list_populate;
        if(sort)
            sorts.unshift(sort);
        if(sorts) {
                for(var i=0; i<sorts.length; i++)
                    mongooseSort(query,sorts[i]);
        }
        if(populates)
        {
            _.each(populates,function(populate)
            {
                query.populate(populate);
            });
        }
        query.skip(start).limit(count).execFind(function(err, documents) {
            if (err) {
                console.error('Unable to get documents for model because: ' + err);
                onReady(null,[]);
            } else {
                var filteredDocuments = [];
                documents.forEach(function(document) {
                    var d = {};
                    d['_id'] = document['_id'];
                    listFields.forEach(function(listField) {
                      d[listField] = typeof(document[listField])=='function'? document[listField]() : document.get(listField);
                    });
                    filteredDocuments.push(d);
                });

                onReady(null, filteredDocuments);
            }
        });
    }
    else
    {
        onReady(null,[]);
    }
};

/**
 * Retrieve a single document
 *
 * @param {String} collectionName
 * @param {String} documentId
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.getDocument = function(collectionName, documentId, onReady) {
    this.models[collectionName].model.findById(documentId, function(err, document) {
        if (err) {
            console.log('Unable to get document because: ' + err);
            onReady('Unable to get document', null);
        } else {
            onReady(null, document);
        }
    });
};

/**
 * Create a new document
 *
 * @param {String} collectionName
 * @param {Object} params
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.createDocument = function(req,user, collectionName, params, onReady) {
    var self = this;
    var model = this.models[collectionName].model;
    //noinspection LocalVariableNamingConventionJS
    var FormType = this.models[collectionName].options.form || AdminForm;
    if(permissions.hasPermissions(user,collectionName,'create'))
    {

        var form = new FormType(req,{data:params},model);
        form.is_valid(function(err,valid)
        {
            if(err)
            {
                onReady(err);
                return;
            }
            if(valid)
            {
                form.save(function(err,document)
                {
                    if (err) {
                        //console.log('Error saving document: ' + err);
                        onReady(form);
                    } else {

                        if (self.models[collectionName].options && self.models[collectionName].options.post) {
                            document = self.models[collectionName].options.post(document);
                        }
//                        MongooseAdminAudit.logActivity(user, self.models[collectionName].modelName, collectionName, document._id, 'add', null, function(err, auditLog) {
                            onReady(null, document);
//                        });
                    }
                });
            }
            else
            {
                onReady(form,null);
            }
        });
    }
    else
    {
        onReady('unauthorizaed');
    }
};

/**
 * Update a document
 *
 * @api public
 */
MongooseAdmin.prototype.updateDocument = function(req, user, collectionName, documentId, params, onReady) {
    var self = this,
        model = this.models[collectionName].model;

    if (!permissions.hasPermissions(user,collectionName,'update')) {
        return onReady('unauthorized');
    }

    var FormType2 = this.models[collectionName].options.form || AdminForm;
    return model.findById(documentId, function (err, document) {
        if (err) {
            console.log('Error retrieving document to update: ' + err);
            return onReady('Unable to update', null);
        }

        var form = new FormType2(req, { instance: document, data: params }, model);
        form.is_valid(function (err, valid) {
            if (err || !valid)
                return onReady(err || form, null);

            return form.save(function (err, document) {
                if (err)
                    return onReady(form, null);

                if (self.models[collectionName].options && self.models[collectionName].options.post) {
                    document = self.models[collectionName].options.post(document);
                }
                // MongooseAdminAudit.logActivity(user, self.models[collectionName].modelName, collectionName, document._id, 'edit', null, function(err, auditLog) {
                return onReady(null, document);
                // });
            });
        });
    });
};

/**
 * Delete, remove a document
 *
 * @param {String} collectionName
 * @param {String} documentId
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.deleteDocument = function(user, collectionName, documentId, onReady) {
    var self = this;
    var model = this.models[collectionName].model;
    if(permissions.hasPermissions(user,collectionName,'delete'))
    {
        model.findById(documentId, function(err, document) {
        if (err) {
            console.log('Error retrieving document to delete: ' + err);
            onReady('Unable to delete');
        } else {
            if (!document) {
                onReady('Document not found');
            } else {
                require('./dependencies').unlink(self.models, collectionName, documentId, function(err) {
                    if(err)
                        onReady('unlink dependencies failed');
                    else {
                        document.remove();
//                        MongooseAdminAudit.logActivity(user, self.models[collectionName].modelName, collectionName, documentId, 'del', null, function(err, auditLog) {
                            onReady(null);
//                        });
                    }
                });
            }
        }
    });
    }
    else
    {
        onReady('unauthorized')
    }
};

MongooseAdmin.prototype.orderDocuments = function (user, collectionName, data, callback) {
    if (!permissions.hasPermissions(user, collectionName, 'order')) return callback('unauthorized');
    var model = this.models[collectionName];
    var sorting_attr = model.options.sortable;
    if (!sorting_attr) return callback();
    Object.keys(data).forEach(function (id) {
        var set_dict = {};
        set_dict[sorting_attr] = data[id];
        model.model.update({_id: id}, {$set: set_dict}, function (err, r) {});
    });
    return callback();
};

MongooseAdmin.prototype.actionDocuments =function(user,collectionName,actionId,data,onReady)
{
    //console.log(data);
    if(permissions.hasPermissions(user,collectionName,'action'))
    {
            var action = _.find(this.models[collectionName].options.actions, function(action){ return action.value == actionId; });
        if(action)
        {
            action.func(user,data.ids,onReady);
        }
        else
            onReady('no action');
    }
    else
        onReady('unauthorized');
};

/**
 * Deserialize a user from a session store object
 *
 * @param {Object} sessionStore
 *
 * @api private
 */
MongooseAdmin.userFromSessionStore = function(sessionStore) {
    return !sessionStore ? false : MongooseAdminUser.fromSessionStore(sessionStore);
};

/**
 * Create an admin user account
 *
 * @param {String} username
 * @param {String} password
 *
 * @api public
 */
MongooseAdmin.prototype.ensureUserExists = function(username, password) {
    MongooseAdminUser.ensureExists(username, password, function(err, adminUser) {
        if (!err)
            console.log('\x1b[36mformage-admin\x1b[0m user: %s', adminUser.fields.username);
    });
};

/**
 * Log in as a user
 *
 * @param {String} username
 * @param {String} password
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.login = function(username, password, onReady) {
    MongooseAdminUser.getByUsernamePassword(username, password, function(err, adminUser) {
        onReady(err, adminUser);
    });
};

exports.loadApi = require('./AdminForm').loadApi;

exports.AdminForm = AdminForm;
<commit_msg>Just some explicicity<commit_after>'use strict';
var MongooseAdminUser = require('./models/mongoose_admin_user.js').MongooseAdminUser,
    _ = require('underscore'),
    async = require('async'),
    permissions = require('./models/permissions'),
    mongoose = require.main.require('mongoose'),
    AdminForm = require('./AdminForm').AdminForm,
    forms = require('./forms').forms;

/**
 * MongooseAdmin Constructor
 *
 * @api private
 */
var MongooseAdmin = module.exports = function (app, root) {
    this.app = app;
    this.root = root;
    this.models = {};
    this.title = "Backoffice";
};

/**
 * Build a full path that can be used in a URL
 *
 * @param {String} path
 */
MongooseAdmin.prototype.buildPath = function(path) {
    return this.root + path;
};

MongooseAdmin.prototype.getAdminTitle = function() {
    return this.title;
};

MongooseAdmin.prototype.setAdminTitle = function(title) {
    this.title = title;
};

/**
 * Stop listening and end the admin process
 *
 * @api public
 */
MongooseAdmin.prototype.close = function() {
    this.app.close();
};

function buildModelFilters (model, filters, dict) {
    if (!filters)
        return;

    setTimeout(function () {
        async.forEach(
            filters,
            function (filter, cbk) {
                model.collection.distinct(filter, function (err, results) {
                    if (results) {
                        if (results[0] && Array.isArray(results[0])) {
                            results = _.flatten(results);
                        }
                        if (results.length > 30)
                            results.splice(5);
                        if (model.schema.paths[filter] && model.schema.paths[filter].options.ref) {
                            mongoose.model(model.schema.paths[filter].options.ref).find()
                                .where('_id').in(results)
                                .exec(function (err, refs) {
                                    if (refs)
                                        dict.push({ key: filter, isString: false, values: _.map(refs, function (ref) {
                                            return { value: ref.id, text: ref.toString()};
                                        }) });
                                    cbk(err);
                                });
                        }
                        else {
                            dict.push({key: filter, values: _.map(results, function (result) {
                                return { value: result, text: result, isString: model.schema.paths[filter] && model.schema.paths[filter].options && model.schema.paths[filter].options.type == String };
                            })});
                            cbk();
                        }
                    }
                    else
                        cbk(err);
                });

            }, function () {

            })
    }, 1000);
}

MongooseAdmin.prototype.registerMongooseModel = function (name, model, fields, options) {
    var models = this.models;

    model.label = model.label || name[0].toUpperCase() + name.slice(1).replace(/_/g,' ');

    options = options || {};
    options.actions = options.actions || [];
    options.actions.push({
        value: 'delete',
        label: 'Delete',
        func: function (user, ids, callback) {
            async.map(
                ids,
                function (id, cb) {
                    require('./dependencies').check(models, name, id, cb);
                },
                function (err, results) {
                    if (err) return callback(err);

                    var no_dependencies = ids.filter(function (result, index) {
                        return !results[index] || !results[index].length;
                    });
                    model.remove({_id: {$in: no_dependencies}}, callback);
                }
            );
        }
    });

    var filters = [];
    buildModelFilters(model, options.filters, filters);

    this.models[name] = {
        model: model,
        filters: filters,
        modelName: name,
        options: options,
        fields: fields
    };

    console.log('\x1b[36mformage-admin:\x1b[0m %s', name);

    permissions.registerModel(name);
};

MongooseAdmin.prototype.registerSingleRowModel = function(model, name, options) {
    model.label = model.label || name[0].toUpperCase() + name.slice(1).replace(/_/g,' ');

    model.is_single = true;
    this.models[name] = {
        model: model,
        options: options || {},
        fields: {},
        is_single: true,
        modelName: name
    };
    permissions.registerModel(name);
};

/**
* Register a new mongoose model/schema with admin
*
* @param {Object} model
* @param {String} name
* @param {Object} options
*
* @api public
*/
MongooseAdmin.prototype.registerModel = function(model, name, options) {
    this.models[name] = {
        model: model,
        modelName: name,
        options: options
    };
    console.log('\x1b[36mformage-admin:\x1b[0m %s', name);
};

/**
 * Retrieve a list of all registered models
 *
 * @param {Function} callback
 *
 * @api public
 */
MongooseAdmin.prototype.getRegisteredModels = function (user, callback) {
    var raw_models = this.models;
    var out_models = Object.keys(raw_models).map(function (collectionName) {
        var out_model = raw_models[collectionName];
        out_model.model.is_single = out_model.is_single;
        return out_model;
    }).filter(function (model) {
        return permissions.hasPermissions(user, model.modelName, 'view');
    });
    callback(null, out_models);
};

/**
 * Get a single model from the registered list with admin
 *
 * @param {String} collectionName
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.getModel = function(collectionName, onReady) {
    var model = this.models[collectionName];
    onReady(null, model.model, model.fields, model.options);
};

/**
 * Get the counts of a model
 *
 * @param {String} collectionName
 *
 * @api public
 */
MongooseAdmin.prototype.modelCounts = function(collectionName,filters, onReady) {
    if(this.models[collectionName].is_single) {
        onReady(null,1);
        return;
    }
    var model = this.models[collectionName].model;
    _.each(filters,function(value,key) {
        if(model.schema && typeof(value) == 'string') {
            var type = model.schema.paths[key].options.type;
            if(type == String)
                filters[key] = new RegExp(value,'i');
            else if(type == Number)
                filters[key] = Number(value) || undefined;
            else if(type == Boolean)
                filters[key] = Boolean(value === 'true');
        }
    });
    this.models[collectionName].model.count(filters, function(err, count) {
        if (err) {
            console.error('Unable to get counts for model because: ' + err);
            onReady(null,0);
        } else {
            onReady(null, count);
        }
    });
};

var IS_OLD_MONGOOSE = Number(mongoose.version.split('.')[0]) < 3;

function mongooseSort(query,sort) {
    if(IS_OLD_MONGOOSE) {
        if(sort[0] === '-')
            query.sort(sort.slice(1),'descending');
        else
            query.sort(sort,'ascending');
    }
    else
        query.sort(sort);
}

/**
 * List a page of documents from a model
 *
 * @param {String} collectionName
 * @param {Number} start
 * @param {Number} count
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.listModelDocuments = function(collectionName, start, count,filters,sort, onReady) {
    var listFields = this.models[collectionName].options.list;
    if(listFields)
    {
	    var model = this.models[collectionName].model;
        _.each(filters, function(value,key) {
            if(model.schema && typeof(value) == 'string') {
                var type = model.schema.paths[key].options.type;
                if(type == String)
                    filters[key] = new RegExp(value,'i');
                else if(type == Number)
                    filters[key] = Number(value) || undefined;
                else if(type == Boolean)
                    filters[key] = Boolean(value === 'true');
            }
        });
        var query = this.models[collectionName].model.find(filters);
        var sorts = this.models[collectionName].options.order_by || [];
        var populates = this.models[collectionName].options.list_populate;
        if(sort)
            sorts.unshift(sort);
        if(sorts) {
                for(var i=0; i<sorts.length; i++)
                    mongooseSort(query,sorts[i]);
        }
        if(populates)
        {
            _.each(populates,function(populate)
            {
                query.populate(populate);
            });
        }
        query.skip(start).limit(count).execFind(function(err, documents) {
            if (err) {
                console.error('Unable to get documents for model because: ' + err);
                onReady(null,[]);
            } else {
                var filteredDocuments = [];
                documents.forEach(function(document) {
                    var d = {};
                    d['_id'] = document['_id'];
                    listFields.forEach(function(listField) {
                      d[listField] = typeof(document[listField])=='function'? document[listField]() : document.get(listField);
                    });
                    filteredDocuments.push(d);
                });

                onReady(null, filteredDocuments);
            }
        });
    }
    else
    {
        onReady(null,[]);
    }
};

/**
 * Retrieve a single document
 *
 * @param {String} collectionName
 * @param {String} documentId
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.getDocument = function(collectionName, documentId, onReady) {
    this.models[collectionName].model.findById(documentId, function(err, document) {
        if (err) {
            console.log('Unable to get document because: ' + err);
            onReady('Unable to get document', null);
        } else {
            onReady(null, document);
        }
    });
};

/**
 * Create a new document
 *
 * @param {String} collectionName
 * @param {Object} params
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.createDocument = function(req,user, collectionName, params, onReady) {
    var self = this;
    var model = this.models[collectionName].model;
    //noinspection LocalVariableNamingConventionJS
    var FormType = this.models[collectionName].options.form || AdminForm;
    if(permissions.hasPermissions(user,collectionName,'create'))
    {

        var form = new FormType(req,{data:params},model);
        form.is_valid(function(err,valid)
        {
            if(err)
            {
                onReady(err);
                return;
            }
            if(valid)
            {
                form.save(function(err,document)
                {
                    if (err) {
                        //console.log('Error saving document: ' + err);
                        onReady(form);
                    } else {

                        if (self.models[collectionName].options && self.models[collectionName].options.post) {
                            document = self.models[collectionName].options.post(document);
                        }
//                        MongooseAdminAudit.logActivity(user, self.models[collectionName].modelName, collectionName, document._id, 'add', null, function(err, auditLog) {
                            onReady(null, document);
//                        });
                    }
                });
            }
            else
            {
                onReady(form,null);
            }
        });
    }
    else
    {
        onReady('unauthorizaed');
    }
};

/**
 * Update a document
 *
 * @api public
 */
MongooseAdmin.prototype.updateDocument = function(req, user, collectionName, documentId, params, onReady) {
    var self = this,
        model = this.models[collectionName].model;

    if (!permissions.hasPermissions(user,collectionName,'update')) {
        return onReady('unauthorized');
    }

    var FormType2 = this.models[collectionName].options.form || AdminForm;
    return model.findById(documentId, function (err, document) {
        if (err) {
            console.log('Error retrieving document to update: ' + err);
            return onReady('Unable to update', null);
        }

        var form = new FormType2(req, { instance: document, data: params }, model);
        form.init_fields();
        form.is_valid(function (err, valid) {
            if (err || !valid)
                return onReady(err || form, null);

            return form.save(function (err, document) {
                if (err)
                    return onReady(form, null);

                if (self.models[collectionName].options && self.models[collectionName].options.post) {
                    document = self.models[collectionName].options.post(document);
                }
                // MongooseAdminAudit.logActivity(user, self.models[collectionName].modelName, collectionName, document._id, 'edit', null, function(err, auditLog) {
                return onReady(null, document);
                // });
            });
        });
    });
};

/**
 * Delete, remove a document
 *
 * @param {String} collectionName
 * @param {String} documentId
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.deleteDocument = function(user, collectionName, documentId, onReady) {
    var self = this;
    var model = this.models[collectionName].model;
    if(permissions.hasPermissions(user,collectionName,'delete'))
    {
        model.findById(documentId, function(err, document) {
        if (err) {
            console.log('Error retrieving document to delete: ' + err);
            onReady('Unable to delete');
        } else {
            if (!document) {
                onReady('Document not found');
            } else {
                require('./dependencies').unlink(self.models, collectionName, documentId, function(err) {
                    if(err)
                        onReady('unlink dependencies failed');
                    else {
                        document.remove();
//                        MongooseAdminAudit.logActivity(user, self.models[collectionName].modelName, collectionName, documentId, 'del', null, function(err, auditLog) {
                            onReady(null);
//                        });
                    }
                });
            }
        }
    });
    }
    else
    {
        onReady('unauthorized')
    }
};

MongooseAdmin.prototype.orderDocuments = function (user, collectionName, data, callback) {
    if (!permissions.hasPermissions(user, collectionName, 'order')) return callback('unauthorized');
    var model = this.models[collectionName];
    var sorting_attr = model.options.sortable;
    if (!sorting_attr) return callback();
    Object.keys(data).forEach(function (id) {
        var set_dict = {};
        set_dict[sorting_attr] = data[id];
        model.model.update({_id: id}, {$set: set_dict}, function (err, r) {});
    });
    return callback();
};

MongooseAdmin.prototype.actionDocuments =function(user,collectionName,actionId,data,onReady)
{
    //console.log(data);
    if(permissions.hasPermissions(user,collectionName,'action'))
    {
            var action = _.find(this.models[collectionName].options.actions, function(action){ return action.value == actionId; });
        if(action)
        {
            action.func(user,data.ids,onReady);
        }
        else
            onReady('no action');
    }
    else
        onReady('unauthorized');
};

/**
 * Deserialize a user from a session store object
 *
 * @param {Object} sessionStore
 *
 * @api private
 */
MongooseAdmin.userFromSessionStore = function(sessionStore) {
    return !sessionStore ? false : MongooseAdminUser.fromSessionStore(sessionStore);
};

/**
 * Create an admin user account
 *
 * @param {String} username
 * @param {String} password
 *
 * @api public
 */
MongooseAdmin.prototype.ensureUserExists = function(username, password) {
    MongooseAdminUser.ensureExists(username, password, function(err, adminUser) {
        if (!err)
            console.log('\x1b[36mformage-admin\x1b[0m user: %s', adminUser.fields.username);
    });
};

/**
 * Log in as a user
 *
 * @param {String} username
 * @param {String} password
 * @param {Function} onReady
 *
 * @api public
 */
MongooseAdmin.prototype.login = function(username, password, onReady) {
    MongooseAdminUser.getByUsernamePassword(username, password, function(err, adminUser) {
        onReady(err, adminUser);
    });
};

exports.loadApi = require('./AdminForm').loadApi;

exports.AdminForm = AdminForm;
<|endoftext|>


<commit_before>/*
   Copyright 2016 Sergi Vladykin (https://github.com/svladykin)

   Version 0.4

   The latest version can be found at https://github.com/NashornTools

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

var NnClassLoader = (function () {

var StaticClass = Java.type('jdk.internal.dynalink.beans.StaticClass'); // TODO fix for JDK9
var Class = java.lang.Class;
var URL = java.net.URL;
var File = java.io.File;
var Files = java.nio.file.Files;
var SCO = java.nio.file.StandardCopyOption;
var System = java.lang.System;

var DEBUG = java.lang.Boolean.getBoolean('NnClassLoader.debug');

var MAVEN_VERSION = '3.3.9';
var MAVEN_MD5 = 'e7ebd0b8d6811b42a5dad91fb27fe9b4';
var MAVERN_URLS = [
	'http://www-us.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
	'http://www-eu.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
	'https://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
];

var WORK_DIR = path(System.getProperty("user.home"), '.mvn_js');
var MVN = path(WORK_DIR, 'mvn-' + MAVEN_VERSION);
var MVN_HOME = path(MVN, 'apache-maven-3.3.9');
var MVN_LIB = path(MVN_HOME , 'lib');
var MVN_BOOT = path(MVN_HOME, 'boot');

function path() {
	var args = Array.prototype.slice.call(arguments); // Convert to array.

	return args.join(File.separator);
}

function debug(str) {
	if (DEBUG)
		System.out.println(str);
}

function file(pathStr) {
	return new File(pathStr);
}

function isDefined(o) {
	return typeof(o) !== 'undefined';
}

function isObject(o) { // Will return true for arrays as well.
	return typeof(o) === 'object';
}

function download(url, filePath) {
	var tmpFile = file(filePath + '.tmp');
	var input = null;

	try {
		input = new URL(url).openConnection().getInputStream();

		tmpFile.createNewFile();

		Files.copy(input, tmpFile.toPath(), SCO.REPLACE_EXISTING);
	}
	catch (e) {
		rm(tmpFile);

		throw e;
	}
	finally {
		if (input != null)
			input.close();
	}

	Files.move(tmpFile.toPath(), file(filePath).toPath(), SCO.REPLACE_EXISTING, SCO.ATOMIC_MOVE);
}

function rm(f) {
	if (!f.exists())
		return;

	if (f.isDirectory()) {
		for each (var c in f.listFiles())
			rm(c);
	}
	if (!f.delete())
		throw "Failed to delete file: " + f;
}

function unzip(zipFilePath, destDirectory) {
	var ZipInputStream = java.util.zip.ZipInputStream;
	var ZipEntry = java.util.zip.ZipEntry;

	var destDir = file(destDirectory);

	if (!destDir.exists())
		destDir.mkdir();

	var zipIn = new ZipInputStream(Files.newInputStream(file(zipFilePath).toPath()));

	try {
		var entry = zipIn.getNextEntry();

		while (entry != null) {
			var filePath = destDirectory + File.separator + entry.getName();
			if (!entry.isDirectory())
				Files.copy(zipIn, file(filePath).toPath(), SCO.REPLACE_EXISTING);
			else
				file(filePath).mkdir();

			zipIn.closeEntry();
			entry = zipIn.getNextEntry();
		}
	}
	finally {
		zipIn.close();
	}
}

function md5(filePath) {
	var MessageDigest = java.security.MessageDigest;
	var DigestInputStream = java.security.DigestInputStream;

	var md = MessageDigest.getInstance("MD5");
	var stream = new DigestInputStream(Files.newInputStream(file(filePath).toPath()), md);

	while(stream.read() != -1);

	return bytesToHex(md.digest());
}

function bytesToHex(b) {
	var Integer = java.lang.Integer;

	var res = '';

	for (var i = 0; i < b.length; i++)
		res += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);

	return res;
}

function withOkLock(fun) {
	var ok = file(path(WORK_DIR, ".ok"));

	if (ok.exists())
		return;

	var workDir = file(WORK_DIR);

	workDir.mkdirs();

	if (!workDir.exists())
		throw "Failed to create directory: " + WORK_DIR;

	var lock = file(path(WORK_DIR, ".lock"));
	lock.createNewFile();

	var RandomAccessFile = java.io.RandomAccessFile;
	var raf = new RandomAccessFile(lock, "rw");

	try {
		var lock = raf.getChannel().lock();

		try {
			if (ok.exists())
				return;

			fun();

			ok.createNewFile();
		}
		finally {
			if (lock != null)
				lock.release();
		}
	}
	finally {
		raf.close();
	}
}

function installMaven() {
	var mvnZipPath = MVN + '.zip';
	var zip = file(mvnZipPath);

	var i = 0;

	while (!zip.exists() || md5(mvnZipPath) !== MAVEN_MD5) {
		try {
			if (i >= MAVERN_URLS.length)
				break; // No more URLs.

			var url = MAVERN_URLS[i++];

			debug("Downloading maven from: " + url);

			download(url, mvnZipPath);

			debug("Download complete, running checksum.");

			var md5hash = md5(mvnZipPath);

			if (md5hash === MAVEN_MD5)
				break; // Success.
			else
				throw "Checksum error in " + mvnZipPath + ", expected: " + MAVEN_MD5 + ", actual: " + md5hash;
		}
		catch(e) {
			if (isDefined(e.printStackTrace)) {
				if (DEBUG)
					e.printStackTrace();
			}
			else
				debug("Error: " + e);

			rm(zip);
		}
	}

	if (!zip.exists())
		throw "Failed to download Maven.";

	debug("Unzipping maven into: " + MVN);

	rm(file(MVN));

	unzip(mvnZipPath, MVN);

	debug("Maven sucessfully installed.");
}

function parseMavenDependency(dep) {
	var arr = dep.split(':');
	var res = {};

	res.version = arr.pop();
	res.artifactId = arr.pop();
	res.groupId = arr.pop();

	return res;
}

function generatePomXmlFile(cfg) {
	var dependenciesXml = '';
	for each(var dep in cfg.maven) {
		var d = parseMavenDependency(dep);

		dependenciesXml += '' +
'		<dependency>\n' +
'			<groupId>' + d.groupId + '</groupId>\n' +
'			<artifactId>' + d.artifactId + '</artifactId>\n' +
'			<version>' + d.version + '</version>\n' +
'		</dependency>\n';
	}

	var pomXml = '' +
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<project>\n' +
'	<modelVersion>4.0.0</modelVersion>\n' +
'	<groupId>nashorn.tools</groupId>\n' +
'	<artifactId>tmp</artifactId>\n' +
'	<packaging>pom</packaging>\n' +
'	<version>1.0-SNAPSHOT</version>\n' +
'	<name>tmp</name>\n' +
'	<dependencies>\n' +
		dependenciesXml +
'	</dependencies>\n' +
'</project>\n';

	debug("Generating pom.xml:\n" + pomXml);

	var pom = Files.createTempFile('pom-', '.xml').toAbsolutePath();
	Files.write(pom, pomXml.toString().getBytes('UTF-8'));

	return pom.toFile();
}

function readTextFile(filePath, charset) {
	var Charset = java.nio.charset.Charset;

	var lines = Files.readAllLines(file(filePath).toPath(), Charset.forName(charset));
	var contents = Java.from(lines).join('\n');

	debug("Contents of file '" + filePath + "':\n" + contents);

	return contents;
}

function debugPrintStream() {
	if (DEBUG)
		return System.out;

	var PrintStream = java.io.PrintStream;

	return new PrintStream(function(b) {}, true, 'UTF-8'); // /dev/null
}

function setContextClassLoader(ldr) {
	var th = java.lang.Thread.currentThread();

	var oldLdr = th.getContextClassLoader();

	th.setContextClassLoader(ldr);

	return oldLdr;
}

function collectMavenDependencies(cfg, urls) {
	withOkLock(installMaven);

	var cp = null;

	var mvnTmp = Files.createTempDirectory("mvn-js-tmpdir-").toFile();

	try {
		// Set system properties for Maven.
		System.setProperty("maven.multiModuleProjectDirectory", mvnTmp.getCanonicalPath())
		System.setProperty("maven.home", file(MVN_HOME).getCanonicalPath());
		System.setProperty("classworlds.conf", file(path(MVN_HOME, 'bin', 'm2.conf')).getCanonicalPath());

		var L = new NnClassLoader({dirs:[MVN_LIB, MVN_BOOT]});

		debug("Maven CLI classpath: " + L.getUrls());

		// Temporary set context class loader to Maven.
		var oldLdr = setContextClassLoader(L.getJavaClassLoader());

		var MavenCli = L.type('org.apache.maven.cli.MavenCli');

		var cli = new MavenCli();

		var cpFile = Files.createTempFile('cp-', '.txt').toFile();

		try {
			var pomFile = generatePomXmlFile(cfg);

			try {
				var printStream = debugPrintStream();

				var mvnArgs = ['-f', pomFile.getCanonicalPath(), "-Dmdep.outputFile=" + cpFile.getCanonicalPath(),
					'dependency:go-offline', 'dependency:build-classpath', 'verify'];

				if (DEBUG)
					mvnArgs = ['--debug', '--errors'].concat(mvnArgs);

				var exitCode = cli.doMain(mvnArgs, mvnTmp.getCanonicalPath(), printStream, printStream);

				if (exitCode !== 0)
					throw "Exit code of maven " + exitCode;

				setContextClassLoader(oldLdr)

				cp = readTextFile(cpFile.getCanonicalPath(), 'UTF-8');
			}
			finally {
				rm(pomFile);
			}
		}
		finally {
			rm(cpFile);
		}
	}
	finally {
		rm(mvnTmp);
	}

	if (cp !== null) {
		cp = cp.trim();

		for each(var jar in cp.split(File.pathSeparator))
			urls.add(toURL(file(jar)));
	}
}

function loadType(className, ldr) {
	var cls = Class.forName(className, true, ldr);
	return StaticClass.forClass(cls);
}

function toURL(f) {
	return f.getCanonicalFile().toURI().toURL();
}

function scanDirForJars(f, filter, urls) {
	if (!f.exists())
		return;
	if (f.isDirectory()) {
		if (filter(f)) {
			for each (var x in f.listFiles())
				scanDirForJars(x, filter, urls);
		}
	}
	else if (f.isFile() && f.getName().toLowerCase().endsWith('.jar') && filter(f))
		urls.add(toURL(f));
}

function collectAllJarUrls(cfg) {
	if (!isObject(cfg))
		throw "Class loader configuration object is not provided.\nFor example: new NnClassLoader({jars:['/myapp/bla.jar'], urls:['http://.../bla.jar']})";

	var HashSet = java.util.HashSet;
	var UrlArray = Java.type('java.net.URL[]');

	var urls = new HashSet();

	if (isObject(cfg.urls)) {
		for each (var url in cfg.urls)
			urls.add(new URL(url));
	}

	if (isObject(cfg.jars)) {
		for each (var jar in cfg.jars) {
			var f = file(jar);

			if (f.isFile())
				urls.add(toURL(f));
		}
	}

	if (isObject(cfg.dirs)) {
		var filter = isDefined(cfg.filter) ? cfg.filter : function(f) {return true;};

		for each (var dir in cfg.dirs)
			scanDirForJars(file(dir), filter, urls);
	}

	if (isObject(cfg.classes)) {
		for each (var dir in cfg.classes) {
			var f = file(dir);

			if (f.isDirectory())
				urls.add(toURL(f));
		}
	}

	if (isObject(cfg.maven))
		collectMavenDependencies(cfg, urls);

	return urls.toArray(new UrlArray(0));
}

function NnClassLoader(cfg) {
	var URLClassLoader = java.net.URLClassLoader;

	var jarUrls = collectAllJarUrls(cfg);
	var ldr = isObject(cfg.parent) ?
		new URLClassLoader(jarUrls, cfg.parent):
		new URLClassLoader(jarUrls);

	this.type = function(className) {
		return loadType(className, ldr);
	}

	this.getUrls = function() {
		var res = [];

		for each (var url in jarUrls)
			res.push(url.toString());

		return res;
	}

	this.getJavaClassLoader = function() {
		return ldr;
	}
}

return NnClassLoader;
})();
<commit_msg>Bump version to 1.0<commit_after>/*
   Copyright 2016 Sergi Vladykin (https://github.com/svladykin)

   Version 1.0

   The latest version can be found at https://github.com/NashornTools

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*/

var NnClassLoader = (function () {

var StaticClass = Java.type('jdk.internal.dynalink.beans.StaticClass'); // TODO fix for JDK9
var Class = java.lang.Class;
var URL = java.net.URL;
var File = java.io.File;
var Files = java.nio.file.Files;
var SCO = java.nio.file.StandardCopyOption;
var System = java.lang.System;

var DEBUG = java.lang.Boolean.getBoolean('NnClassLoader.debug');

var MAVEN_VERSION = '3.3.9';
var MAVEN_MD5 = 'e7ebd0b8d6811b42a5dad91fb27fe9b4';
var MAVERN_URLS = [
	'http://www-us.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
	'http://www-eu.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
	'https://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
];

var WORK_DIR = path(System.getProperty("user.home"), '.mvn_js');
var MVN = path(WORK_DIR, 'mvn-' + MAVEN_VERSION);
var MVN_HOME = path(MVN, 'apache-maven-3.3.9');
var MVN_LIB = path(MVN_HOME , 'lib');
var MVN_BOOT = path(MVN_HOME, 'boot');

function path() {
	var args = Array.prototype.slice.call(arguments); // Convert to array.

	return args.join(File.separator);
}

function debug(str) {
	if (DEBUG)
		System.out.println(str);
}

function file(pathStr) {
	return new File(pathStr);
}

function isDefined(o) {
	return typeof(o) !== 'undefined';
}

function isObject(o) { // Will return true for arrays as well.
	return typeof(o) === 'object';
}

function download(url, filePath) {
	var tmpFile = file(filePath + '.tmp');
	var input = null;

	try {
		input = new URL(url).openConnection().getInputStream();

		tmpFile.createNewFile();

		Files.copy(input, tmpFile.toPath(), SCO.REPLACE_EXISTING);
	}
	catch (e) {
		rm(tmpFile);

		throw e;
	}
	finally {
		if (input != null)
			input.close();
	}

	Files.move(tmpFile.toPath(), file(filePath).toPath(), SCO.REPLACE_EXISTING, SCO.ATOMIC_MOVE);
}

function rm(f) {
	if (!f.exists())
		return;

	if (f.isDirectory()) {
		for each (var c in f.listFiles())
			rm(c);
	}
	if (!f.delete())
		throw "Failed to delete file: " + f;
}

function unzip(zipFilePath, destDirectory) {
	var ZipInputStream = java.util.zip.ZipInputStream;
	var ZipEntry = java.util.zip.ZipEntry;

	var destDir = file(destDirectory);

	if (!destDir.exists())
		destDir.mkdir();

	var zipIn = new ZipInputStream(Files.newInputStream(file(zipFilePath).toPath()));

	try {
		var entry = zipIn.getNextEntry();

		while (entry != null) {
			var filePath = destDirectory + File.separator + entry.getName();
			if (!entry.isDirectory())
				Files.copy(zipIn, file(filePath).toPath(), SCO.REPLACE_EXISTING);
			else
				file(filePath).mkdir();

			zipIn.closeEntry();
			entry = zipIn.getNextEntry();
		}
	}
	finally {
		zipIn.close();
	}
}

function md5(filePath) {
	var MessageDigest = java.security.MessageDigest;
	var DigestInputStream = java.security.DigestInputStream;

	var md = MessageDigest.getInstance("MD5");
	var stream = new DigestInputStream(Files.newInputStream(file(filePath).toPath()), md);

	while(stream.read() != -1);

	return bytesToHex(md.digest());
}

function bytesToHex(b) {
	var Integer = java.lang.Integer;

	var res = '';

	for (var i = 0; i < b.length; i++)
		res += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);

	return res;
}

function withOkLock(fun) {
	var ok = file(path(WORK_DIR, ".ok"));

	if (ok.exists())
		return;

	var workDir = file(WORK_DIR);

	workDir.mkdirs();

	if (!workDir.exists())
		throw "Failed to create directory: " + WORK_DIR;

	var lock = file(path(WORK_DIR, ".lock"));
	lock.createNewFile();

	var RandomAccessFile = java.io.RandomAccessFile;
	var raf = new RandomAccessFile(lock, "rw");

	try {
		var lock = raf.getChannel().lock();

		try {
			if (ok.exists())
				return;

			fun();

			ok.createNewFile();
		}
		finally {
			if (lock != null)
				lock.release();
		}
	}
	finally {
		raf.close();
	}
}

function installMaven() {
	var mvnZipPath = MVN + '.zip';
	var zip = file(mvnZipPath);

	var i = 0;

	while (!zip.exists() || md5(mvnZipPath) !== MAVEN_MD5) {
		try {
			if (i >= MAVERN_URLS.length)
				break; // No more URLs.

			var url = MAVERN_URLS[i++];

			debug("Downloading maven from: " + url);

			download(url, mvnZipPath);

			debug("Download complete, running checksum.");

			var md5hash = md5(mvnZipPath);

			if (md5hash === MAVEN_MD5)
				break; // Success.
			else
				throw "Checksum error in " + mvnZipPath + ", expected: " + MAVEN_MD5 + ", actual: " + md5hash;
		}
		catch(e) {
			if (isDefined(e.printStackTrace)) {
				if (DEBUG)
					e.printStackTrace();
			}
			else
				debug("Error: " + e);

			rm(zip);
		}
	}

	if (!zip.exists())
		throw "Failed to download Maven.";

	debug("Unzipping maven into: " + MVN);

	rm(file(MVN));

	unzip(mvnZipPath, MVN);

	debug("Maven sucessfully installed.");
}

function parseMavenDependency(dep) {
	var arr = dep.split(':');
	var res = {};

	res.version = arr.pop();
	res.artifactId = arr.pop();
	res.groupId = arr.pop();

	return res;
}

function generatePomXmlFile(cfg) {
	var dependenciesXml = '';
	for each(var dep in cfg.maven) {
		var d = parseMavenDependency(dep);

		dependenciesXml += '' +
'		<dependency>\n' +
'			<groupId>' + d.groupId + '</groupId>\n' +
'			<artifactId>' + d.artifactId + '</artifactId>\n' +
'			<version>' + d.version + '</version>\n' +
'		</dependency>\n';
	}

	var pomXml = '' +
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<project>\n' +
'	<modelVersion>4.0.0</modelVersion>\n' +
'	<groupId>nashorn.tools</groupId>\n' +
'	<artifactId>tmp</artifactId>\n' +
'	<packaging>pom</packaging>\n' +
'	<version>1.0-SNAPSHOT</version>\n' +
'	<name>tmp</name>\n' +
'	<dependencies>\n' +
		dependenciesXml +
'	</dependencies>\n' +
'</project>\n';

	debug("Generating pom.xml:\n" + pomXml);

	var pom = Files.createTempFile('pom-', '.xml').toAbsolutePath();
	Files.write(pom, pomXml.toString().getBytes('UTF-8'));

	return pom.toFile();
}

function readTextFile(filePath, charset) {
	var Charset = java.nio.charset.Charset;

	var lines = Files.readAllLines(file(filePath).toPath(), Charset.forName(charset));
	var contents = Java.from(lines).join('\n');

	debug("Contents of file '" + filePath + "':\n" + contents);

	return contents;
}

function debugPrintStream() {
	if (DEBUG)
		return System.out;

	var PrintStream = java.io.PrintStream;

	return new PrintStream(function(b) {}, true, 'UTF-8'); // /dev/null
}

function setContextClassLoader(ldr) {
	var th = java.lang.Thread.currentThread();

	var oldLdr = th.getContextClassLoader();

	th.setContextClassLoader(ldr);

	return oldLdr;
}

function collectMavenDependencies(cfg, urls) {
	withOkLock(installMaven);

	var cp = null;

	var mvnTmp = Files.createTempDirectory("mvn-js-tmpdir-").toFile();

	try {
		// Set system properties for Maven.
		System.setProperty("maven.multiModuleProjectDirectory", mvnTmp.getCanonicalPath())
		System.setProperty("maven.home", file(MVN_HOME).getCanonicalPath());
		System.setProperty("classworlds.conf", file(path(MVN_HOME, 'bin', 'm2.conf')).getCanonicalPath());

		var L = new NnClassLoader({dirs:[MVN_LIB, MVN_BOOT]});

		debug("Maven CLI classpath: " + L.getUrls());

		// Temporary set context class loader to Maven.
		var oldLdr = setContextClassLoader(L.getJavaClassLoader());

		var MavenCli = L.type('org.apache.maven.cli.MavenCli');

		var cli = new MavenCli();

		var cpFile = Files.createTempFile('cp-', '.txt').toFile();

		try {
			var pomFile = generatePomXmlFile(cfg);

			try {
				var printStream = debugPrintStream();

				var mvnArgs = ['-f', pomFile.getCanonicalPath(), "-Dmdep.outputFile=" + cpFile.getCanonicalPath(),
					'dependency:go-offline', 'dependency:build-classpath', 'verify'];

				if (DEBUG)
					mvnArgs = ['--debug', '--errors'].concat(mvnArgs);

				var exitCode = cli.doMain(mvnArgs, mvnTmp.getCanonicalPath(), printStream, printStream);

				if (exitCode !== 0)
					throw "Exit code of maven " + exitCode;

				setContextClassLoader(oldLdr)

				cp = readTextFile(cpFile.getCanonicalPath(), 'UTF-8');
			}
			finally {
				rm(pomFile);
			}
		}
		finally {
			rm(cpFile);
		}
	}
	finally {
		rm(mvnTmp);
	}

	if (cp !== null) {
		cp = cp.trim();

		for each(var jar in cp.split(File.pathSeparator))
			urls.add(toURL(file(jar)));
	}
}

function loadType(className, ldr) {
	var cls = Class.forName(className, true, ldr);
	return StaticClass.forClass(cls);
}

function toURL(f) {
	return f.getCanonicalFile().toURI().toURL();
}

function scanDirForJars(f, filter, urls) {
	if (!f.exists())
		return;
	if (f.isDirectory()) {
		if (filter(f)) {
			for each (var x in f.listFiles())
				scanDirForJars(x, filter, urls);
		}
	}
	else if (f.isFile() && f.getName().toLowerCase().endsWith('.jar') && filter(f))
		urls.add(toURL(f));
}

function collectAllJarUrls(cfg) {
	if (!isObject(cfg))
		throw "Class loader configuration object is not provided.\nFor example: new NnClassLoader({jars:['/myapp/bla.jar'], urls:['http://.../bla.jar']})";

	var HashSet = java.util.HashSet;
	var UrlArray = Java.type('java.net.URL[]');

	var urls = new HashSet();

	if (isObject(cfg.urls)) {
		for each (var url in cfg.urls)
			urls.add(new URL(url));
	}

	if (isObject(cfg.jars)) {
		for each (var jar in cfg.jars) {
			var f = file(jar);

			if (f.isFile())
				urls.add(toURL(f));
		}
	}

	if (isObject(cfg.dirs)) {
		var filter = isDefined(cfg.filter) ? cfg.filter : function(f) {return true;};

		for each (var dir in cfg.dirs)
			scanDirForJars(file(dir), filter, urls);
	}

	if (isObject(cfg.classes)) {
		for each (var dir in cfg.classes) {
			var f = file(dir);

			if (f.isDirectory())
				urls.add(toURL(f));
		}
	}

	if (isObject(cfg.maven))
		collectMavenDependencies(cfg, urls);

	return urls.toArray(new UrlArray(0));
}

function NnClassLoader(cfg) {
	var URLClassLoader = java.net.URLClassLoader;

	var jarUrls = collectAllJarUrls(cfg);
	var ldr = isObject(cfg.parent) ?
		new URLClassLoader(jarUrls, cfg.parent):
		new URLClassLoader(jarUrls);

	this.type = function(className) {
		return loadType(className, ldr);
	}

	this.getUrls = function() {
		var res = [];

		for each (var url in jarUrls)
			res.push(url.toString());

		return res;
	}

	this.getJavaClassLoader = function() {
		return ldr;
	}
}

return NnClassLoader;
})();
<|endoftext|>


<commit_before>Q.page("Streams/participating", function () {
	var userId = Q.Users.loggedInUserId();

	$(".Streams_participating_stream_checkmark").on("change", function () {
		var $this = $(this);
		var publisherId = $this.attr('data-publisherId');
		var name = $this.prop('name');

		if ($this.prop('checked')) {
			Q.Streams.Stream.subscribe(publisherId, name);
		} else {
			Q.Streams.Stream.unsubscribe(publisherId, name);
		}
	});

	var _modIdentified = function () {
		var $this = $(this);
		var $item = $this.closest('.Streams_participating_item');
		var type = $item.attr('data-type');

		Q.Users.setIdentifier({
			identifierType: type,
			onSuccess: function () {
				Q.Text.get('Streams/content', function (err, text) {
					var msg = Q.firstErrorMessage(err);
					if (msg) {
						return console.warn(msg);
					}

					var text = Q.getObject('followup.'+type+'.CheckYour' + type.toCapitalized(), text);
					Q.alert(text);
				});
			}
		});
	};

	$(".Streams_participating_item .Streams_participant_plus_icon").on(Q.Pointer.fastclick, _modIdentified);
	$(".Streams_participating_item span.Streams_participating_id").on(Q.Pointer.fastclick, _modIdentified);
	$(".Streams_participating_item .Streams_participant_subscribed_icon").on(Q.Pointer.fastclick, function () {
		var $this = $(this);
		var $item = $this.closest('.Streams_participating_item');
		var subscribed = $item.attr('data-subscribed') === 'true';
		var $identifier = $('span.Streams_participating_id', $item);
		var slot = subscribed ? 'unsubscribe' : 'subscribe';

		var _subscriptionRequest = function () {
			$item.addClass('Q_working');

			Q.req('Users/identifier', [slot], function (err, data) {
				$item.removeClass('Q_working');
				var fem = Q.firstErrorMessage(err, data && data.errors);
				if (fem) {
					return Q.alert(fem);
				}

				$item.attr('data-subscribed', subscribed ? 'false' : 'true');
			}, {
				fields: {
					identifier: $identifier.text(),
					type: $item.attr('data-type')
				}
			});
		};

		if (!subscribed) {
			return _subscriptionRequest();
		}

		Q.Text.get('Streams/content', function (err, text) {
			var msg = Q.firstErrorMessage(err);
			if (msg) {
				return console.warn(msg);
			}

			var text = Q.getObject('followup.AreYouSureUnsubscribeIdentifier', text);
			Q.confirm(text, function (res) {
				if (!res) {
					return;
				}

				_subscriptionRequest();
			});
		});
	});

	$(".Streams_participating_item .Streams_participant_delete_icon").on(Q.Pointer.fastclick, function () {
		var $this = $(this);
		var $item = $this.closest('.Streams_participating_item');
		var subscribed = $item.attr('data-subscribed') === 'true';
		var $identifier = $('span.Streams_participating_id', $item);
		var slot = subscribed ? 'unsubscribe' : 'subscribe';

		$item.addClass('Q_working');

		Q.req('Users/identifier', [], function (err, data) {
			$item.removeClass('Q_working');
			var fem = Q.firstErrorMessage(err, data && data.errors);
			if (fem) {
				return Q.alert(fem);
			}

			$item.attr('data-defined', 'false');
			$identifier.html('');
		}, {
			method: 'delete',
			fields: {
				identifier: $identifier.text()
			}
		});
	});

	// listen Streams/user/emailAddress stream to reflect changes
	Q.Streams.get(userId, 'Streams/user/emailAddress', function (err) {
		var fem = Q.firstErrorMessage(err);
		if (fem) {
			return console.warn("Streams/participating: " + fem);
		}

		this.onFieldChanged('content').set(function (fields) {
			document.location.reload();
		}, true);
	});

	// listen Streams/user/mobileNumber stream to reflect changes
	Q.Streams.get(userId, 'Streams/user/mobileNumber', function (err) {
		var fem = Q.firstErrorMessage(err);
		if (fem) {
			return console.warn("Streams/participating: " + fem);
		}

		this.onFieldChanged('content').set(function (fields) {
			document.location.reload();
		}, true);
	});

	return function () {

	};

}, 'Communities');

Q.Tool.onActivate("Q/expandable").set(function () {
	this.state.beforeExpand.set(function () {
		// create Streams/participants tools
		$(".Streams_participating_stream td[data-type=participants][data-processed=0]", this.element).each(function () {
			$("<div>").tool("Streams/participants", {
				'publisherId': this.getAttribute("data-publisherId"),
				'streamName': this.getAttribute("data-streamName"),
				'showSummary': true,
				'showBlanks': false,
				'showControls': true,
				'maxShow': 100
			}).appendTo(this).activate();

			this.setAttribute("data-processed", 1);
		});
	});
}, true);
<commit_msg>After identificator changed, reload Streams/participating page with time out 2 seconds. Because otherwise reloading return error "You are not logged in".<commit_after>Q.page("Streams/participating", function () {
	var userId = Q.Users.loggedInUserId();

	$(".Streams_participating_stream_checkmark").on("change", function () {
		var $this = $(this);
		var publisherId = $this.attr('data-publisherId');
		var name = $this.prop('name');

		if ($this.prop('checked')) {
			Q.Streams.Stream.subscribe(publisherId, name);
		} else {
			Q.Streams.Stream.unsubscribe(publisherId, name);
		}
	});

	var _modIdentified = function () {
		var $this = $(this);
		var $item = $this.closest('.Streams_participating_item');
		var type = $item.attr('data-type');

		Q.Users.setIdentifier({
			identifierType: type,
			onSuccess: function () {
				Q.Text.get('Streams/content', function (err, text) {
					var msg = Q.firstErrorMessage(err);
					if (msg) {
						return console.warn(msg);
					}

					var text = Q.getObject('followup.'+type+'.CheckYour' + type.toCapitalized(), text);
					Q.alert(text);
				});
			}
		});
	};

	$(".Streams_participating_item .Streams_participant_plus_icon").on(Q.Pointer.fastclick, _modIdentified);
	$(".Streams_participating_item span.Streams_participating_id").on(Q.Pointer.fastclick, _modIdentified);
	$(".Streams_participating_item .Streams_participant_subscribed_icon").on(Q.Pointer.fastclick, function () {
		var $this = $(this);
		var $item = $this.closest('.Streams_participating_item');
		var subscribed = $item.attr('data-subscribed') === 'true';
		var $identifier = $('span.Streams_participating_id', $item);
		var slot = subscribed ? 'unsubscribe' : 'subscribe';

		var _subscriptionRequest = function () {
			$item.addClass('Q_working');

			Q.req('Users/identifier', [slot], function (err, data) {
				$item.removeClass('Q_working');
				var fem = Q.firstErrorMessage(err, data && data.errors);
				if (fem) {
					return Q.alert(fem);
				}

				$item.attr('data-subscribed', subscribed ? 'false' : 'true');
			}, {
				fields: {
					identifier: $identifier.text(),
					type: $item.attr('data-type')
				}
			});
		};

		if (!subscribed) {
			return _subscriptionRequest();
		}

		Q.Text.get('Streams/content', function (err, text) {
			var msg = Q.firstErrorMessage(err);
			if (msg) {
				return console.warn(msg);
			}

			var text = Q.getObject('followup.AreYouSureUnsubscribeIdentifier', text);
			Q.confirm(text, function (res) {
				if (!res) {
					return;
				}

				_subscriptionRequest();
			});
		});
	});

	$(".Streams_participating_item .Streams_participant_delete_icon").on(Q.Pointer.fastclick, function () {
		var $this = $(this);
		var $item = $this.closest('.Streams_participating_item');
		var subscribed = $item.attr('data-subscribed') === 'true';
		var $identifier = $('span.Streams_participating_id', $item);
		var slot = subscribed ? 'unsubscribe' : 'subscribe';

		$item.addClass('Q_working');

		Q.req('Users/identifier', [], function (err, data) {
			$item.removeClass('Q_working');
			var fem = Q.firstErrorMessage(err, data && data.errors);
			if (fem) {
				return Q.alert(fem);
			}

			$item.attr('data-defined', 'false');
			$identifier.html('');
		}, {
			method: 'delete',
			fields: {
				identifier: $identifier.text()
			}
		});
	});

	// listen Streams/user/emailAddress stream to reflect changes
	Q.Streams.get(userId, 'Streams/user/emailAddress', function (err) {
		var fem = Q.firstErrorMessage(err);
		if (fem) {
			return console.warn("Streams/participating: " + fem);
		}

		this.onFieldChanged('content').set(function (fields) {
			setTimeout(function () { document.location.reload(); }, 2000);
		}, true);
	});

	// listen Streams/user/mobileNumber stream to reflect changes
	Q.Streams.get(userId, 'Streams/user/mobileNumber', function (err) {
		var fem = Q.firstErrorMessage(err);
		if (fem) {
			return console.warn("Streams/participating: " + fem);
		}

		this.onFieldChanged('content').set(function (fields) {
			setTimeout(function () { document.location.reload(); }, 2000);
		}, true);
	});

	return function () {

	};

}, 'Communities');

Q.Tool.onActivate("Q/expandable").set(function () {
	this.state.beforeExpand.set(function () {
		// create Streams/participants tools
		$(".Streams_participating_stream td[data-type=participants][data-processed=0]", this.element).each(function () {
			$("<div>").tool("Streams/participants", {
				'publisherId': this.getAttribute("data-publisherId"),
				'streamName': this.getAttribute("data-streamName"),
				'showSummary': true,
				'showBlanks': false,
				'showControls': true,
				'maxShow': 100
			}).appendTo(this).activate();

			this.setAttribute("data-processed", 1);
		});
	});
}, true);
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';

import { MODULE_TYPES } from '@ohif/core';
import {
  ExpandableToolMenu,
  RoundedButtonGroup,
  ToolbarButton,
  withModal,
  withDialog,
} from '@ohif/ui';

import './ToolbarRow.css';
import { commandsManager, extensionManager } from './../App.js';

import ConnectedCineDialog from './ConnectedCineDialog';
import ConnectedLayoutButton from './ConnectedLayoutButton';

class ToolbarRow extends Component {
  // TODO: Simplify these? isOpen can be computed if we say "any" value for selected,
  // closed if selected is null/undefined
  static propTypes = {
    isLeftSidePanelOpen: PropTypes.bool.isRequired,
    isRightSidePanelOpen: PropTypes.bool.isRequired,
    selectedLeftSidePanel: PropTypes.string.isRequired,
    selectedRightSidePanel: PropTypes.string.isRequired,
    handleSidePanelChange: PropTypes.func,
    activeContexts: PropTypes.arrayOf(PropTypes.string).isRequired,
    studies: PropTypes.array,
  };

  constructor(props) {
    super(props);

    const toolbarButtonDefinitions = _getVisibleToolbarButtons.call(this);
    // TODO:
    // If it's a tool that can be active... Mark it as active?
    // - Tools that are on/off?
    // - Tools that can be bound to multiple buttons?

    // Normal ToolbarButtons...
    // Just how high do we need to hoist this state?
    // Why ToolbarRow instead of just Toolbar? Do we have any others?
    this.state = {
      toolbarButtons: toolbarButtonDefinitions,
      activeButtons: [],
    };

    this._handleBuiltIn = _handleBuiltIn.bind(this);

    const panelModules = extensionManager.modules[MODULE_TYPES.PANEL];
    this.buttonGroups = {
      left: [
        // TODO: This should come from extensions, instead of being baked in
        {
          value: 'studies',
          icon: 'th-large',
          bottomLabel: this.props.t('Series'),
        },
      ],
      right: [],
    };

    panelModules.forEach(panelExtension => {
      const panelModule = panelExtension.module;
      const defaultContexts = Array.from(panelModule.defaultContext);

      // MENU OPTIONS
      panelModule.menuOptions.forEach(menuOption => {
        const contexts = Array.from(menuOption.context || defaultContexts);

        const activeContextIncludesAnyPanelContexts = this.props.activeContexts.some(
          actx => contexts.includes(actx)
        );
        if (activeContextIncludesAnyPanelContexts) {
          const menuOptionEntry = {
            value: menuOption.target,
            icon: menuOption.icon,
            bottomLabel: menuOption.label,
          };
          const from = menuOption.from || 'right';

          this.buttonGroups[from].push(menuOptionEntry);
        }
      });
    });
  }

  componentDidUpdate(prevProps) {
    const activeContextsChanged =
      prevProps.activeContexts !== this.props.activeContexts;

    if (activeContextsChanged) {
      this.setState({
        toolbarButtons: _getVisibleToolbarButtons.call(this),
      });
    }
  }

  render() {
    const buttonComponents = _getButtonComponents.call(
      this,
      this.state.toolbarButtons,
      this.state.activeButtons
    );

    const onPress = (side, value) => {
      this.props.handleSidePanelChange(side, value);
    };
    const onPressLeft = onPress.bind(this, 'left');
    const onPressRight = onPress.bind(this, 'right');

    return (
      <>

            <RoundedButtonGroup
              options={this.buttonGroups.left}
              value={this.props.selectedLeftSidePanel || ''}
              onValueChanged={onPressLeft}
            />

          {buttonComponents}
          <ConnectedLayoutButton />

            {this.buttonGroups.right.length && (
              <RoundedButtonGroup
                options={this.buttonGroups.right}
                value={this.props.selectedRightSidePanel || ''}
                onValueChanged={onPressRight}
              />
            )}

      </>
    );
  }
}

function _getCustomButtonComponent(button, activeButtons) {
  const CustomComponent = button.CustomComponent;
  const isValidComponent = typeof CustomComponent === 'function';

  // Check if its a valid customComponent. Later on an CustomToolbarComponent interface could be implemented.
  if (isValidComponent) {
    const parentContext = this;
    const activeButtonsIds = activeButtons.map(button => button.id);
    const isActive = activeButtonsIds.includes(button.id);

    return (
      <CustomComponent
        parentContext={parentContext}
        toolbarClickCallback={_handleToolbarButtonClick.bind(this)}
        button={button}
        key={button.id}
        activeButtons={activeButtonsIds}
        isActive={isActive}
      />
    );
  }
}

function _getExpandableButtonComponent(button, activeButtons) {
  // Iterate over button definitions and update `onClick` behavior
  let activeCommand;
  const childButtons = button.buttons.map(childButton => {
    childButton.onClick = _handleToolbarButtonClick.bind(this, childButton);

    if (activeButtons.map(button => button.id).indexOf(childButton.id) > -1) {
      activeCommand = childButton.id;
    }

    return childButton;
  });

  return (
    <ExpandableToolMenu
      key={button.id}
      label={button.label}
      icon={button.icon}
      buttons={childButtons}
      activeCommand={activeCommand}
    />
  );
}

function _getDefaultButtonComponent(button, activeButtons) {
  return (
    <ToolbarButton
      key={button.id}
      label={button.label}
      icon={button.icon}
      onClick={_handleToolbarButtonClick.bind(this, button)}
      isActive={activeButtons.map(button => button.id).includes(button.id)}
    />
  );
}
/**
 * Determine which extension buttons should be showing, if they're
 * active, and what their onClick behavior should be.
 */
function _getButtonComponents(toolbarButtons, activeButtons) {
  const _this = this;
  return toolbarButtons.map(button => {
    const hasCustomComponent = button.CustomComponent;
    const hasNestedButtonDefinitions = button.buttons && button.buttons.length;

    if (hasCustomComponent) {
      return _getCustomButtonComponent.call(_this, button, activeButtons);
    }

    if (hasNestedButtonDefinitions) {
      return _getExpandableButtonComponent.call(_this, button, activeButtons);
    }

    return _getDefaultButtonComponent.call(_this, button, activeButtons);
  });
}

/**
 * A handy way for us to handle different button types. IE. firing commands for
 * buttons, or initiation built in behavior.
 *
 * @param {*} button
 * @param {*} evt
 * @param {*} props
 */
function _handleToolbarButtonClick(button, evt, props) {
  const { activeButtons } = this.state;

  if (button.commandName) {
    const options = Object.assign({ evt }, button.commandOptions);
    commandsManager.runCommand(button.commandName, options);
  }

  // TODO: Use Types ENUM
  // TODO: We can update this to be a `getter` on the extension to query
  //       For the active tools after we apply our updates?
  if (button.type === 'setToolActive') {
    const toggables = activeButtons.filter(
      ({ options }) => options && !options.togglable
    );
    this.setState({ activeButtons: [...toggables, button] });
  } else if (button.type === 'builtIn') {
    this._handleBuiltIn(button);
  }
}

/**
 *
 */
function _getVisibleToolbarButtons() {
  const toolbarModules = extensionManager.modules[MODULE_TYPES.TOOLBAR];
  const toolbarButtonDefinitions = [];

  toolbarModules.forEach(extension => {
    const { definitions, defaultContext } = extension.module;
    definitions.forEach(definition => {
      const context = definition.context || defaultContext;

      if (this.props.activeContexts.includes(context)) {
        toolbarButtonDefinitions.push(definition);
      }
    });
  });

  return toolbarButtonDefinitions;
}

function _handleBuiltIn(button) {
  /* TODO: Keep cine button active until its unselected. */
  const { dialog, modal, t } = this.props;
  const { dialogId } = this.state;
  const { id, options } = button;

  if (options.behavior === 'CINE') {
    if (dialogId) {
      dialog.dismiss({ id: dialogId });
      this.setState(state => ({
        dialogId: null,
        activeButtons: [
          ...state.activeButtons.filter(button => button.id !== id),
        ],
      }));
    } else {
      const spacing = 20;
      const { x, y } = document
        .querySelector(`.ViewerMain`)
        .getBoundingClientRect();
      const newDialogId = dialog.create({
        content: ConnectedCineDialog,
        defaultPosition: {
          x: x + spacing || 0,
          y: y + spacing || 0,
        },
      });
      this.setState(state => ({
        dialogId: newDialogId,
        activeButtons: [...state.activeButtons, button],
      }));
    }
  }

  if (options.behavior === 'DOWNLOAD_SCREEN_SHOT') {
    commandsManager.runCommand('showDownloadViewportModal', {
      title: t('Download High Quality Image'),
    });
  }
}

export default withTranslation(['Common', 'ViewportDownloadForm'])(
  withModal(withDialog(ToolbarRow))
);
<commit_msg>chore: sketch out beginnings of isDisabled method for sidePanel menuOptions<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';

import { MODULE_TYPES } from '@ohif/core';
import {
  ExpandableToolMenu,
  RoundedButtonGroup,
  ToolbarButton,
  withModal,
  withDialog,
} from '@ohif/ui';

import './ToolbarRow.css';
import { commandsManager, extensionManager } from './../App.js';

import ConnectedCineDialog from './ConnectedCineDialog';
import ConnectedLayoutButton from './ConnectedLayoutButton';

class ToolbarRow extends Component {
  // TODO: Simplify these? isOpen can be computed if we say "any" value for selected,
  // closed if selected is null/undefined
  static propTypes = {
    isLeftSidePanelOpen: PropTypes.bool.isRequired,
    isRightSidePanelOpen: PropTypes.bool.isRequired,
    selectedLeftSidePanel: PropTypes.string.isRequired,
    selectedRightSidePanel: PropTypes.string.isRequired,
    handleSidePanelChange: PropTypes.func.isRequired,
    activeContexts: PropTypes.arrayOf(PropTypes.string).isRequired,
    studies: PropTypes.array,
    t: PropTypes.func.isRequired,
  };

  static defaultProps = {
    studies: [],
  };

  constructor(props) {
    super(props);

    const toolbarButtonDefinitions = _getVisibleToolbarButtons.call(this);
    // TODO:
    // If it's a tool that can be active... Mark it as active?
    // - Tools that are on/off?
    // - Tools that can be bound to multiple buttons?

    // Normal ToolbarButtons...
    // Just how high do we need to hoist this state?
    // Why ToolbarRow instead of just Toolbar? Do we have any others?
    this.state = {
      toolbarButtons: toolbarButtonDefinitions,
      activeButtons: [],
    };

    this._handleBuiltIn = _handleBuiltIn.bind(this);

    const panelModules = extensionManager.modules[MODULE_TYPES.PANEL];

    this.buttonGroups = {
      left: [],
      right: [],
    };

    // ~ FIND MENU OPTIONS
    panelModules.forEach(panelExtension => {
      const panelModule = panelExtension.module;
      const defaultContexts = Array.from(panelModule.defaultContext);

      panelModule.menuOptions.forEach(menuOption => {
        const contexts = Array.from(menuOption.context || defaultContexts);
        const hasActiveContext = this.props.activeContexts.some(actx =>
          contexts.includes(actx)
        );
        // TODO: what should `isDisabled` receive?
        const isDisabled = menuOption.isDisabled();

        if (hasActiveContext && !isDisabled) {
          const menuOptionEntry = {
            value: menuOption.target,
            icon: menuOption.icon,
            bottomLabel: menuOption.label,
          };
          const from = menuOption.from || 'right';

          this.buttonGroups[from].push(menuOptionEntry);
        }
      });
    });

    //   });
    // });

    // TODO: This should come from extensions, instead of being baked in
    this.buttonGroups.right.unshift({
      value: 'studies',
      icon: 'th-large',
      bottomLabel: this.props.t('Series'),
    });
  }

  componentDidUpdate(prevProps) {
    const activeContextsChanged =
      prevProps.activeContexts !== this.props.activeContexts;

    if (activeContextsChanged) {
      this.setState({
        toolbarButtons: _getVisibleToolbarButtons.call(this),
      });
    }
  }

  render() {
    const buttonComponents = _getButtonComponents.call(
      this,
      this.state.toolbarButtons,
      this.state.activeButtons
    );

    const onPress = (side, value) => {
      this.props.handleSidePanelChange(side, value);
    };
    const onPressLeft = onPress.bind(this, 'left');
    const onPressRight = onPress.bind(this, 'right');

    return (
      <>

            <RoundedButtonGroup
              options={this.buttonGroups.left}
              value={this.props.selectedLeftSidePanel || ''}
              onValueChanged={onPressLeft}
            />

          {buttonComponents}
          <ConnectedLayoutButton />

            {this.buttonGroups.right.length && (
              <RoundedButtonGroup
                options={this.buttonGroups.right}
                value={this.props.selectedRightSidePanel || ''}
                onValueChanged={onPressRight}
              />
            )}

      </>
    );
  }
}

function _getCustomButtonComponent(button, activeButtons) {
  const CustomComponent = button.CustomComponent;
  const isValidComponent = typeof CustomComponent === 'function';

  // Check if its a valid customComponent. Later on an CustomToolbarComponent interface could be implemented.
  if (isValidComponent) {
    const parentContext = this;
    const activeButtonsIds = activeButtons.map(button => button.id);
    const isActive = activeButtonsIds.includes(button.id);

    return (
      <CustomComponent
        parentContext={parentContext}
        toolbarClickCallback={_handleToolbarButtonClick.bind(this)}
        button={button}
        key={button.id}
        activeButtons={activeButtonsIds}
        isActive={isActive}
      />
    );
  }
}

function _getExpandableButtonComponent(button, activeButtons) {
  // Iterate over button definitions and update `onClick` behavior
  let activeCommand;
  const childButtons = button.buttons.map(childButton => {
    childButton.onClick = _handleToolbarButtonClick.bind(this, childButton);

    if (activeButtons.map(button => button.id).indexOf(childButton.id) > -1) {
      activeCommand = childButton.id;
    }

    return childButton;
  });

  return (
    <ExpandableToolMenu
      key={button.id}
      label={button.label}
      icon={button.icon}
      buttons={childButtons}
      activeCommand={activeCommand}
    />
  );
}

function _getDefaultButtonComponent(button, activeButtons) {
  return (
    <ToolbarButton
      key={button.id}
      label={button.label}
      icon={button.icon}
      onClick={_handleToolbarButtonClick.bind(this, button)}
      isActive={activeButtons.map(button => button.id).includes(button.id)}
    />
  );
}
/**
 * Determine which extension buttons should be showing, if they're
 * active, and what their onClick behavior should be.
 */
function _getButtonComponents(toolbarButtons, activeButtons) {
  const _this = this;
  return toolbarButtons.map(button => {
    const hasCustomComponent = button.CustomComponent;
    const hasNestedButtonDefinitions = button.buttons && button.buttons.length;

    if (hasCustomComponent) {
      return _getCustomButtonComponent.call(_this, button, activeButtons);
    }

    if (hasNestedButtonDefinitions) {
      return _getExpandableButtonComponent.call(_this, button, activeButtons);
    }

    return _getDefaultButtonComponent.call(_this, button, activeButtons);
  });
}

/**
 * A handy way for us to handle different button types. IE. firing commands for
 * buttons, or initiation built in behavior.
 *
 * @param {*} button
 * @param {*} evt
 * @param {*} props
 */
function _handleToolbarButtonClick(button, evt, props) {
  const { activeButtons } = this.state;

  if (button.commandName) {
    const options = Object.assign({ evt }, button.commandOptions);
    commandsManager.runCommand(button.commandName, options);
  }

  // TODO: Use Types ENUM
  // TODO: We can update this to be a `getter` on the extension to query
  //       For the active tools after we apply our updates?
  if (button.type === 'setToolActive') {
    const toggables = activeButtons.filter(
      ({ options }) => options && !options.togglable
    );
    this.setState({ activeButtons: [...toggables, button] });
  } else if (button.type === 'builtIn') {
    this._handleBuiltIn(button);
  }
}

/**
 *
 */
function _getVisibleToolbarButtons() {
  const toolbarModules = extensionManager.modules[MODULE_TYPES.TOOLBAR];
  const toolbarButtonDefinitions = [];

  toolbarModules.forEach(extension => {
    const { definitions, defaultContext } = extension.module;
    definitions.forEach(definition => {
      const context = definition.context || defaultContext;

      if (this.props.activeContexts.includes(context)) {
        toolbarButtonDefinitions.push(definition);
      }
    });
  });

  return toolbarButtonDefinitions;
}

function _handleBuiltIn(button) {
  /* TODO: Keep cine button active until its unselected. */
  const { dialog, modal, t } = this.props;
  const { dialogId } = this.state;
  const { id, options } = button;

  if (options.behavior === 'CINE') {
    if (dialogId) {
      dialog.dismiss({ id: dialogId });
      this.setState(state => ({
        dialogId: null,
        activeButtons: [
          ...state.activeButtons.filter(button => button.id !== id),
        ],
      }));
    } else {
      const spacing = 20;
      const { x, y } = document
        .querySelector(`.ViewerMain`)
        .getBoundingClientRect();
      const newDialogId = dialog.create({
        content: ConnectedCineDialog,
        defaultPosition: {
          x: x + spacing || 0,
          y: y + spacing || 0,
        },
      });
      this.setState(state => ({
        dialogId: newDialogId,
        activeButtons: [...state.activeButtons, button],
      }));
    }
  }

  if (options.behavior === 'DOWNLOAD_SCREEN_SHOT') {
    commandsManager.runCommand('showDownloadViewportModal', {
      title: t('Download High Quality Image'),
    });
  }
}

export default withTranslation(['Common', 'ViewportDownloadForm'])(
  withModal(withDialog(ToolbarRow))
);
<|endoftext|>