<commit_before>"use strict";

var util = require("util");

var request = require("request");
var when = require("when");

var backendUrl = "https://api.voucherify.io/v1";

module.exports = function(options) {
    var headers = {
        "X-App-Id": options.applicationId,
        "X-App-Token": options.clientSecretKey,
        "X-Voucherify-Channel": "Node.js-SDK"
    };

    function errorMessage(statusCode, body) {
        return util.format("Unexpected status code: %d - Details: %j", statusCode, body);
    }

    function prepare(callback) {
        var deferred = when.defer();

        if (typeof(callback) === "function") {
            return {
                callback: function(error, res, body) {
                    if (error || res.statusCode >= 400) {
                        var message = errorMessage(res.statusCode, body);

                        callback(error || new Error(message));
                        return;
                    }

                    callback(null, body);
                }
            };
        } else {
            return {
                promise: deferred.promise,
                callback: function(error, res, body) {
                    if (error || res.statusCode >= 400) {
                        var message = errorMessage(res.statusCode, body);

                        deferred.reject(error || new Error(message));
                        return;
                    }

                    deferred.resolve(body);
                }
            };
        }
    }

    return {
        /*
         *  List vouchers. Sample query: { limit: 100, skip: 200, category: "Loyalty" }
         */
        list: function(query, callback) {
            var url = util.format("%s/vouchers/", backendUrl);
            var handler = prepare(callback);

            request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        get: function(code, callback) {
            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.get({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        create: function(voucher, callback) {
            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code || ""));
            var handler = prepare(callback);

            request.post({ url: url, headers: headers, json: voucher }, handler.callback);

            return handler.promise;
        },

        delete: function(voucher_code, params, callback) {
            if (typeof(params) === "undefined") {
                params = {};
            }

            if (typeof(params) === "function") {
                callback = params;
                params = {};
            }

            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher_code || ""));
            if (params.force) { url += "?force=true"; }

            var handler = prepare(callback);

            request.del({ url: url, headers: headers }, handler.callback);

            return handler.promise;
        },

        update: function(voucher, callback) {
            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code));
            var handler = prepare(callback);

            request.put({ url: url, headers: headers, json: voucher }, handler.callback);

            return handler.promise;
        },

        enable: function(code, callback) {
            var url = util.format("%s/vouchers/%s/enable", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.post({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        disable: function(code, callback) {
            var url = util.format("%s/vouchers/%s/disable", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.post({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        validate: function(code, context, callback) {
            if (typeof(context) === "undefined") {
                context = {};
            }

            if (typeof(context) === "function") {
                callback = context;
                context = {};
            }

            var handler = prepare(callback);
            var url = util.format("%s/vouchers/%s/validate", backendUrl, encodeURIComponent(code));

            request.post({ url: url, headers: headers, json: context }, handler.callback);

            return handler.promise;
        },

        redemption: function(code, callback) {
            var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.get({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        /*
         *  List redemptions. Sample query (1000 successful redemptions from April 2016):
         *  {
         *      limit: 1000,
         *      page: 0,
         *      start_date: "2016-04-01T00:00:00",
         *      end_date: "2016-04-30T23:59:59",
         *      result: "Success"
         *  }
         */
        redemptions: function(query, callback) {
            var url = util.format("%s/redemptions/", backendUrl);
            var handler = prepare(callback);

            request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        redeem: function(code, trackingId, callback) {
            var context = {};
            if (typeof(code) === "object") {
                context = code;
                code = context.voucher;
                delete context.voucher;
            }
            // No `tracking_id` passed here,
            // use callback from 2n argument.
            if (typeof(trackingId) === "function") {
                callback = trackingId;
                trackingId = undefined;
            }

            var handler = prepare(callback);
            var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code));

            // If `tracking_id` passed, use it in query string.
            if (typeof(trackingId) === "string" && trackingId) {
                url += "?tracking_id=" + encodeURIComponent(trackingId);
            }

            request.post({ url: url, headers: headers, json: context }, handler.callback);

            return handler.promise;
        },

        rollback: function(redemptionId, data, callback) {
            if (typeof(data) === "function") {
                callback = data;
                data = undefined;
            }

            var qs = {};
            var payload = {};

            // If `reason` passed, use it in query string.
            if (typeof(data) === "string") {
                qs["reason"] = encodeURIComponent(data);
            }

            if (typeof(data) === "object") {
                qs["reason"] = data["reason"] || undefined;
                qs["tracking_id"] = data["tracking_id"] || undefined;
                payload["customer"] = data["customer"] || undefined;
            }

            var handler = prepare(callback);
            var url = util.format("%s/redemptions/%s/rollback", backendUrl, encodeURIComponent(redemptionId));

            request.post({ url: url, headers: headers, qs: qs, body: payload, json: true }, handler.callback);

            return handler.promise;
        },

        publish: function(campaignName, callback) {
            var url = util.format("%s/vouchers/publish", backendUrl);
            var payload = {};
            if (typeof(campaignName) === "string") {
                url += "?campaign=" + encodeURIComponent(campaignName);
            }
            if (typeof(campaignName) === "object") {
                payload = campaignName;
            }
            var handler = prepare(callback);

            request.post({ url: url, headers: headers, json: payload }, handler.callback);

            return handler.promise;
        },

        campaign: {
            voucher: {
                create: function(campaignName, voucher, callback) {
                    var url = util.format("%s/campaigns/%s/vouchers", backendUrl, encodeURIComponent(campaignName || ""));
                    var handler = prepare(callback);

                    request.post({ url: url, headers: headers, json: voucher || {} }, handler.callback);

                    return handler.promise;
                }
            }
        },

        customer: {
            create: function(customer, callback) {
                var url = util.format("%s/customers", backendUrl);
                var handler = prepare(callback);

                request.post({ url: url, headers: headers, json: customer }, handler.callback);

                return handler.promise;
            },

            get: function(customerId, callback) {
                var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || ""));
                var handler = prepare(callback);

                request.get({ url: url, headers: headers, json: true }, handler.callback);

                return handler.promise;
            },

            update: function(customer, callback) {
                var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customer.id || ""));
                var handler = prepare(callback);

                request.put({ url: url, headers: headers, json: customer }, handler.callback);

                return handler.promise;
            },

            delete: function(customerId, callback) {
                var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || ""));
                var handler = prepare(callback);

                request.del({ url: url, headers: headers }, handler.callback);

                return handler.promise;
            }
        },

        product: {
            create: function (product, callback) {
                var url = util.format("%s/products", backendUrl);
                var handler = prepare(callback);

                request.post({ url: url, headers: headers, json: product }, handler.callback);

                return handler.promise;
            },

            get: function (productId, callback) {
                var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || ""));
                var handler = prepare(callback);

                request.get({ url: url, headers: headers }, handler.callback);

                return handler.promise;
            },

            update: function (product, callback) {
                var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(product.id || ""));
                var handler = prepare(callback);

                request.put({ url: url, headers: headers, json: product }, handler.callback);

                return handler.promise;
            },

            delete: function (productId, callback) {
                var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || ""));
                var handler = prepare(callback);

                request.del({ url: url, headers: headers }, handler.callback);

                return handler.promise;
            },

            sku: {
                create: function (productId, sku, callback) {
                    var url = util.format("%s/products/%s/skus", backendUrl,
                        encodeURIComponent(productId || ""));
                    var handler = prepare(callback);

                    request.post({ url: url, headers: headers, json: sku }, handler.callback);

                    return handler.promise;
                },

                get: function (productId, skuId, callback) {
                    var url = util.format("%s/products/%s/skus/%s", backendUrl,
                        encodeURIComponent(productId || ""), encodeURIComponent(skuId || ""));
                    var handler = prepare(callback);

                    request.get({ url: url, headers: headers }, handler.callback);

                    return handler.promise;
                },

                update: function (productId, sku, callback) {
                    var url = util.format("%s/products/%s/skus/%s", backendUrl,
                        encodeURIComponent(productId || ""), encodeURIComponent(sku.id || ""));
                    var handler = prepare(callback);

                    request.put({ url: url, headers: headers, json: sku }, handler.callback);

                    return handler.promise;
                },

                delete: function (productId, skuId, callback) {
                    var url = util.format("%s/products/%s/skus/%s", backendUrl,
                        encodeURIComponent(productId || ""), encodeURIComponent(skuId || ""));
                    var handler = prepare(callback);

                    request.del({ url: url, headers: headers }, handler.callback);

                    return handler.promise;
                }
            }
        }
    };
};<commit_msg>Return JSON object insted of plain text<commit_after>"use strict";

var util = require("util");

var request = require("request");
var when = require("when");

var backendUrl = "https://api.voucherify.io/v1";

module.exports = function(options) {
    var headers = {
        "X-App-Id": options.applicationId,
        "X-App-Token": options.clientSecretKey,
        "X-Voucherify-Channel": "Node.js-SDK"
    };

    function errorMessage(statusCode, body) {
        body = body || {};
        body.toString = function() {
            return util.format("Unexpected status code: %d - Details: %j", statusCode, body);
        };
        return body;
    }

    function prepare(callback) {
        var deferred = when.defer();

        if (typeof(callback) === "function") {
            return {
                callback: function(error, res, body) {
                    if (error || res.statusCode >= 400) {
                        callback(error || errorMessage(res.statusCode, body));
                        return;
                    }

                    callback(null, body);
                }
            };
        } else {
            return {
                promise: deferred.promise,
                callback: function(error, res, body) {
                    if (error || res.statusCode >= 400) {
                        deferred.reject(error || errorMessage(res.statusCode, body));
                        return;
                    }

                    deferred.resolve(body);
                }
            };
        }
    }

    return {
        /*
         *  List vouchers. Sample query: { limit: 100, skip: 200, category: "Loyalty" }
         */
        list: function(query, callback) {
            var url = util.format("%s/vouchers/", backendUrl);
            var handler = prepare(callback);

            request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        get: function(code, callback) {
            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.get({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        create: function(voucher, callback) {
            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code || ""));
            var handler = prepare(callback);

            request.post({ url: url, headers: headers, json: voucher }, handler.callback);

            return handler.promise;
        },

        delete: function(voucher_code, params, callback) {
            if (typeof(params) === "undefined") {
                params = {};
            }

            if (typeof(params) === "function") {
                callback = params;
                params = {};
            }

            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher_code || ""));
            if (params.force) { url += "?force=true"; }

            var handler = prepare(callback);

            request.del({ url: url, headers: headers }, handler.callback);

            return handler.promise;
        },

        update: function(voucher, callback) {
            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(voucher.code));
            var handler = prepare(callback);

            request.put({ url: url, headers: headers, json: voucher }, handler.callback);

            return handler.promise;
        },

        enable: function(code, callback) {
            var url = util.format("%s/vouchers/%s/enable", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.post({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        disable: function(code, callback) {
            var url = util.format("%s/vouchers/%s/disable", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.post({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        validate: function(code, context, callback) {
            if (typeof(context) === "undefined") {
                context = {};
            }

            if (typeof(context) === "function") {
                callback = context;
                context = {};
            }

            var handler = prepare(callback);
            var url = util.format("%s/vouchers/%s/validate", backendUrl, encodeURIComponent(code));

            request.post({ url: url, headers: headers, json: context }, handler.callback);

            return handler.promise;
        },

        redemption: function(code, callback) {
            var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.get({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        /*
         *  List redemptions. Sample query (1000 successful redemptions from April 2016):
         *  {
         *      limit: 1000,
         *      page: 0,
         *      start_date: "2016-04-01T00:00:00",
         *      end_date: "2016-04-30T23:59:59",
         *      result: "Success"
         *  }
         */
        redemptions: function(query, callback) {
            var url = util.format("%s/redemptions/", backendUrl);
            var handler = prepare(callback);

            request.get({ url: url, qs: query, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        redeem: function(code, trackingId, callback) {
            var context = {};
            if (typeof(code) === "object") {
                context = code;
                code = context.voucher;
                delete context.voucher;
            }
            // No `tracking_id` passed here,
            // use callback from 2n argument.
            if (typeof(trackingId) === "function") {
                callback = trackingId;
                trackingId = undefined;
            }

            var handler = prepare(callback);
            var url = util.format("%s/vouchers/%s/redemption", backendUrl, encodeURIComponent(code));

            // If `tracking_id` passed, use it in query string.
            if (typeof(trackingId) === "string" && trackingId) {
                url += "?tracking_id=" + encodeURIComponent(trackingId);
            }

            request.post({ url: url, headers: headers, json: context }, handler.callback);

            return handler.promise;
        },

        rollback: function(redemptionId, data, callback) {
            if (typeof(data) === "function") {
                callback = data;
                data = undefined;
            }

            var qs = {};
            var payload = {};

            // If `reason` passed, use it in query string.
            if (typeof(data) === "string") {
                qs["reason"] = encodeURIComponent(data);
            }

            if (typeof(data) === "object") {
                qs["reason"] = data["reason"] || undefined;
                qs["tracking_id"] = data["tracking_id"] || undefined;
                payload["customer"] = data["customer"] || undefined;
            }

            var handler = prepare(callback);
            var url = util.format("%s/redemptions/%s/rollback", backendUrl, encodeURIComponent(redemptionId));

            request.post({ url: url, headers: headers, qs: qs, body: payload, json: true }, handler.callback);

            return handler.promise;
        },

        publish: function(campaignName, callback) {
            var url = util.format("%s/vouchers/publish", backendUrl);
            var payload = {};
            if (typeof(campaignName) === "string") {
                url += "?campaign=" + encodeURIComponent(campaignName);
            }
            if (typeof(campaignName) === "object") {
                payload = campaignName;
            }
            var handler = prepare(callback);

            request.post({ url: url, headers: headers, json: payload }, handler.callback);

            return handler.promise;
        },

        campaign: {
            voucher: {
                create: function(campaignName, voucher, callback) {
                    var url = util.format("%s/campaigns/%s/vouchers", backendUrl, encodeURIComponent(campaignName || ""));
                    var handler = prepare(callback);

                    request.post({ url: url, headers: headers, json: voucher || {} }, handler.callback);

                    return handler.promise;
                }
            }
        },

        customer: {
            create: function(customer, callback) {
                var url = util.format("%s/customers", backendUrl);
                var handler = prepare(callback);

                request.post({ url: url, headers: headers, json: customer }, handler.callback);

                return handler.promise;
            },

            get: function(customerId, callback) {
                var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || ""));
                var handler = prepare(callback);

                request.get({ url: url, headers: headers, json: true }, handler.callback);

                return handler.promise;
            },

            update: function(customer, callback) {
                var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customer.id || ""));
                var handler = prepare(callback);

                request.put({ url: url, headers: headers, json: customer }, handler.callback);

                return handler.promise;
            },

            delete: function(customerId, callback) {
                var url = util.format("%s/customers/%s", backendUrl, encodeURIComponent(customerId || ""));
                var handler = prepare(callback);

                request.del({ url: url, headers: headers }, handler.callback);

                return handler.promise;
            }
        },

        product: {
            create: function (product, callback) {
                var url = util.format("%s/products", backendUrl);
                var handler = prepare(callback);

                request.post({ url: url, headers: headers, json: product }, handler.callback);

                return handler.promise;
            },

            get: function (productId, callback) {
                var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || ""));
                var handler = prepare(callback);

                request.get({ url: url, headers: headers }, handler.callback);

                return handler.promise;
            },

            update: function (product, callback) {
                var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(product.id || ""));
                var handler = prepare(callback);

                request.put({ url: url, headers: headers, json: product }, handler.callback);

                return handler.promise;
            },

            delete: function (productId, callback) {
                var url = util.format("%s/products/%s", backendUrl, encodeURIComponent(productId || ""));
                var handler = prepare(callback);

                request.del({ url: url, headers: headers }, handler.callback);

                return handler.promise;
            },

            sku: {
                create: function (productId, sku, callback) {
                    var url = util.format("%s/products/%s/skus", backendUrl,
                        encodeURIComponent(productId || ""));
                    var handler = prepare(callback);

                    request.post({ url: url, headers: headers, json: sku }, handler.callback);

                    return handler.promise;
                },

                get: function (productId, skuId, callback) {
                    var url = util.format("%s/products/%s/skus/%s", backendUrl,
                        encodeURIComponent(productId || ""), encodeURIComponent(skuId || ""));
                    var handler = prepare(callback);

                    request.get({ url: url, headers: headers }, handler.callback);

                    return handler.promise;
                },

                update: function (productId, sku, callback) {
                    var url = util.format("%s/products/%s/skus/%s", backendUrl,
                        encodeURIComponent(productId || ""), encodeURIComponent(sku.id || ""));
                    var handler = prepare(callback);

                    request.put({ url: url, headers: headers, json: sku }, handler.callback);

                    return handler.promise;
                },

                delete: function (productId, skuId, callback) {
                    var url = util.format("%s/products/%s/skus/%s", backendUrl,
                        encodeURIComponent(productId || ""), encodeURIComponent(skuId || ""));
                    var handler = prepare(callback);

                    request.del({ url: url, headers: headers }, handler.callback);

                    return handler.promise;
                }
            }
        }
    };
};<|endoftext|>


<commit_before>var EventEmitter = require('events').EventEmitter;
var util = require('util');
var exec = require('child_process').exec
var spawn = require('child_process').spawn
var Dockerrun = require('./dockerrun');
var concat = require('concat-stream')
var wrench = require('wrench');
var async = require('async');

var Job = require('./job')
var Volume = require('./volume')
var logger = require('./logger')
var Endpoints = require('../deployment/endpoints')
var CombineStream = require("combine-stream")
var stamp = require('stamp-stream')

function Container(job){
	var self = this
	EventEmitter.call(this)

	if(typeof(job)=='string'){
		job = Job.fromKey(job)._data
	}

	this._job = job
	this._id = job.id
	this._containerid = (job.id || '').replace(/\//g, '-')
}

util.inherits(Container, EventEmitter)

Container.prototype.id = function(){
	return this._containerid
}

// return a readable stream
Container.prototype.attach = function(){
	throw new Error('TBC')
}

Container.prototype.options = function(){
	var self = this;
	return JSON.parse(JSON.stringify(self._job))
}

Container.prototype.isStream = function(){
	if(this.options().deamon || this.options().deamonize){
		return false
	}
	else{
		return true
	}
}

Container.prototype.checkRunning = function(opts, callback){

	var self = this;
	if(!callback){
		callback = opts
		opts = {}
	}

	this.data(function(err, data){
		if(err){
			callback(err)
		}
		else{
			if(data && data.State.Running){
				callback(null, true)
			}
			else if(data && opts.clean){
				self.remove(function(){
					self.emit('removed')
					callback(null, false)
				})
			}
			else{
				callback(null, false)
			}
		}
	})
}

Container.prototype.combineStream = function(proc){
	var stdout = stamp('[stdout] ')
	var stderr = stamp('[stdout] ')

	proc.stdout.pipe(stdout)
	proc.stderr.pipe(stderr)

	return new CombineStream([stdout, stderr])
}

// run a container in interactive mode
// return a the spawned process in pipe mode
// trigger -i and --rm on the docker container
Container.prototype.stream = function(){
	var self = this

	var args = Dockerrun(self.options())

	args = ['run', '-i', '--rm'].concat(args)

	var stream = spawn('docker', args, {
		stdio: 'pipe'
	})

	this.emit('stream', this.combineStream(stream))

	return stream
}

Container.prototype.run = function(done){
	var self = this

	var args = Dockerrun(self.options())

	args = ['run', '--rm'].concat(args)

	logger('[docker] ' + args.join(' '))

	var stream = spawn('docker', args, {
		stdio: 'pipe'
	})

	this.emit('stream', this.combineStream(stream))

	stream.on('close', done)
	stream.on('error', done)

	return stream

/*
	exec('docker ' + args.join(' '), function(err, stdout, stderr){
		done(err || stderr.toString(), stdout.toString())
	})
*/
}

Container.prototype.deamon = function(done){
	var self = this

	var args = Dockerrun(self.options())

	args = ['run', '-d'].concat(args)

	var command = 'docker ' + args.join(' ')

	logger('[docker deamon] ' + command)

	var stream = spawn('docker', args, {
		stdio: 'pipe'
	})

	this.emit('stream', this.combineStream(stream))

	stream.on('close', function(exitCode){
		done(exitCode ? 'process error ' + exitCode : null)
	})
	stream.on('error', done)

	return stream

/*
	exec(command, function(err, stdout, stderr){
		if(err || stderr){
			return callback(err || stderr.toString())
		}
		logger('[docker deamon output] [stdout]')
		console.log(stdout.toString())
		console.log('[/stdout]')
		callback(null, stdout.toString())
	})
	*/
}

// run a container in Deamon mode
// this checks to see if there is not one already running
Container.prototype.start = function(opts, callback){
	var self = this

	if(!callback){
		callback = opts
		opts = {}
	}

	this.checkRunning({
		clean:true
	}, function(err, running){

		if(err){
			return callback(err)
		}

		if(running){
			self.emit('running')
			return callback('already running')
		}

		self.deamon(function(err){
			if(err){
				return callback(err)
			}
			// let the container get going and then determine its status
			setTimeout(function(){
				self.data(function(err, data){

					if(err) return callback(err)
					var State = data.State

					if(State.ExitCode==1 || !State.Running){
						return callback('container failed ' + State.ExitCode)
					}

					return callback(null, data)
				})
			}, 2000)

		})
	})

}

Container.prototype.reset = function(callback){
	var self = this;
	(this._job.volumes || []).forEach(function(v){
		var parts = v.split(':')
		wrench.rmdirSyncRecursive(parts[0], true)
		self.emit('reset', parts[0])
	})
	callback()
}

Container.prototype.remove = function(callback){
	var self = this
	this.data(function(err, data){
		if(err) return callback(err)
		if(!data) return callback()

		var id = data.ID || data.Id
		if(!id){
			return callback('no id for container')
		}
		logger('[docker remove] ' + id)
		exec('docker rm ' + id, function(err, stdout, stderr){
			if(err){
				return callback(err)
			}
			self.emit('removed')
			callback()
		})
	})
}

Container.prototype.stop = function(remove, callback){
	var self = this
	if(arguments.length<=1){
		callback = remove
		remove = null
	}
	this.data(function(err, data){
		if(err){
			callback(err)
		}
		else{
			if(data && data.State.Running){

				var id = data.ID || data.Id
				if(!id){
					return callback('no id for container')
				}
				logger('[docker stop] ' + id)
				exec('docker stop ' + id , function(err, stdout, stderr){
					if(err){
						callback(err)
						return
					}
					self.emit('stopped')

					if(remove){
						self.remove(callback)
					}
					else{
						callback()
					}
				})
			}
			else if(data){
				self.emit('alreadystopped')
				if(remove){
					self.remove(callback)
				}
				else{
					callback()
				}

			}
			else{
				self.emit('alreadystopped')
				callback()
			}
		}
	})
}

Container.prototype.data = function(done){
	var self = this
	exec('docker inspect ' + this._containerid, function(err, stdout, stderr){
		if(err) return done()
		if(!stdout){
			return done()
		}
		var data = JSON.parse(stdout.toString())
		done(null, data[0])
	})

}

Container.prototype.ports = function(callback){
	var self = this

	self.data(function(err, data){
		if(err || !data){
			callback(err)
		}
		else{
			var ports = data.NetworkSettings.Ports

			var ret = {}
			Object.keys(ports || {}).forEach(function(key){
				var info = ports[key]
				ret[key] = info[0].HostPort
			})

			callback(null, ret)
		}
	})

}

module.exports = function(job){
	return new Container(job)
}<commit_msg>remove container if failed<commit_after>var EventEmitter = require('events').EventEmitter;
var util = require('util');
var exec = require('child_process').exec
var spawn = require('child_process').spawn
var Dockerrun = require('./dockerrun');
var concat = require('concat-stream')
var wrench = require('wrench');
var async = require('async');

var Job = require('./job')
var Volume = require('./volume')
var logger = require('./logger')
var Endpoints = require('../deployment/endpoints')
var CombineStream = require("combine-stream")
var stamp = require('stamp-stream')

function Container(job){
	var self = this
	EventEmitter.call(this)

	if(typeof(job)=='string'){
		job = Job.fromKey(job)._data
	}

	this._job = job
	this._id = job.id
	this._containerid = (job.id || '').replace(/\//g, '-')
}

util.inherits(Container, EventEmitter)

Container.prototype.id = function(){
	return this._containerid
}

// return a readable stream
Container.prototype.attach = function(){
	throw new Error('TBC')
}

Container.prototype.options = function(){
	var self = this;
	return JSON.parse(JSON.stringify(self._job))
}

Container.prototype.isStream = function(){
	if(this.options().deamon || this.options().deamonize){
		return false
	}
	else{
		return true
	}
}

Container.prototype.checkRunning = function(opts, callback){

	var self = this;
	if(!callback){
		callback = opts
		opts = {}
	}

	this.data(function(err, data){
		if(err){
			callback(err)
		}
		else{
			if(data && data.State.Running){
				callback(null, true)
			}
			else if(data && opts.clean){
				self.remove(function(){
					self.emit('removed')
					callback(null, false)
				})
			}
			else{
				callback(null, false)
			}
		}
	})
}

Container.prototype.combineStream = function(proc){
	var stdout = stamp('[stdout] ')
	var stderr = stamp('[stdout] ')

	proc.stdout.pipe(stdout)
	proc.stderr.pipe(stderr)

	return new CombineStream([stdout, stderr])
}

// run a container in interactive mode
// return a the spawned process in pipe mode
// trigger -i and --rm on the docker container
Container.prototype.stream = function(){
	var self = this

	var args = Dockerrun(self.options())

	args = ['run', '-i', '--rm'].concat(args)

	var stream = spawn('docker', args, {
		stdio: 'pipe'
	})

	this.emit('stream', this.combineStream(stream))

	return stream
}

Container.prototype.run = function(done){
	var self = this

	var args = Dockerrun(self.options())

	args = ['run', '--rm'].concat(args)

	logger('[docker] ' + args.join(' '))

	var stream = spawn('docker', args, {
		stdio: 'pipe'
	})

	this.emit('stream', this.combineStream(stream))

	stream.on('close', done)
	stream.on('error', done)

	return stream

/*
	exec('docker ' + args.join(' '), function(err, stdout, stderr){
		done(err || stderr.toString(), stdout.toString())
	})
*/
}

Container.prototype.deamon = function(done){
	var self = this

	var args = Dockerrun(self.options())

	args = ['run', '-d'].concat(args)

	var command = 'docker ' + args.join(' ')

	logger('[docker deamon] ' + command)

	var stream = spawn('docker', args, {
		stdio: 'pipe'
	})

	this.emit('stream', this.combineStream(stream))

	stream.on('close', function(exitCode){
		done(exitCode ? 'process error ' + exitCode : null)
	})
	stream.on('error', done)

	return stream

/*
	exec(command, function(err, stdout, stderr){
		if(err || stderr){
			return callback(err || stderr.toString())
		}
		logger('[docker deamon output] [stdout]')
		console.log(stdout.toString())
		console.log('[/stdout]')
		callback(null, stdout.toString())
	})
	*/
}

// run a container in Deamon mode
// this checks to see if there is not one already running
Container.prototype.start = function(opts, callback){
	var self = this

	if(!callback){
		callback = opts
		opts = {}
	}

	this.checkRunning({
		clean:true
	}, function(err, running){

		if(err){
			return callback(err)
		}

		if(running){
			self.emit('running')
			return callback('already running')
		}

		self.deamon(function(err){
			if(err){
				return callback(err)
			}
			// let the container get going and then determine its status
			setTimeout(function(){
				self.data(function(err, data){

					if(err) return callback(err)
					var State = data.State

					if(State.ExitCode==1 || !State.Running){
						self.remove(function(){
							callback('container failed ' + State.ExitCode)
						})
						return
					}

					return callback(null, data)
				})
			}, 2000)

		})
	})

}

Container.prototype.reset = function(callback){
	var self = this;
	(this._job.volumes || []).forEach(function(v){
		var parts = v.split(':')
		wrench.rmdirSyncRecursive(parts[0], true)
		self.emit('reset', parts[0])
	})
	callback()
}

Container.prototype.remove = function(callback){
	var self = this
	this.data(function(err, data){
		if(err) return callback(err)
		if(!data) return callback()

		var id = data.ID || data.Id
		if(!id){
			return callback('no id for container')
		}
		logger('[docker remove] ' + id)
		exec('docker rm ' + id, function(err, stdout, stderr){
			if(err){
				return callback(err)
			}
			self.emit('removed')
			callback()
		})
	})
}

Container.prototype.stop = function(remove, callback){
	var self = this
	if(arguments.length<=1){
		callback = remove
		remove = null
	}
	this.data(function(err, data){
		if(err){
			callback(err)
		}
		else{
			if(data && data.State.Running){

				var id = data.ID || data.Id
				if(!id){
					return callback('no id for container')
				}
				logger('[docker stop] ' + id)
				exec('docker stop ' + id , function(err, stdout, stderr){
					if(err){
						callback(err)
						return
					}
					self.emit('stopped')

					if(remove){
						self.remove(callback)
					}
					else{
						callback()
					}
				})
			}
			else if(data){
				self.emit('alreadystopped')
				if(remove){
					self.remove(callback)
				}
				else{
					callback()
				}

			}
			else{
				self.emit('alreadystopped')
				callback()
			}
		}
	})
}

Container.prototype.data = function(done){
	var self = this
	exec('docker inspect ' + this._containerid, function(err, stdout, stderr){
		if(err) return done()
		if(!stdout){
			return done()
		}
		var data = JSON.parse(stdout.toString())
		done(null, data[0])
	})

}

Container.prototype.ports = function(callback){
	var self = this

	self.data(function(err, data){
		if(err || !data){
			callback(err)
		}
		else{
			var ports = data.NetworkSettings.Ports

			var ret = {}
			Object.keys(ports || {}).forEach(function(key){
				var info = ports[key]
				ret[key] = info[0].HostPort
			})

			callback(null, ret)
		}
	})

}

module.exports = function(job){
	return new Container(job)
}<|endoftext|>


<commit_before>"use strict";

var util = require("util");

var request = require("request");
var when = require("when");

var backendUrl = "https://voucherify-bouncer.herokuapp.com/v1";

module.exports = function(options) {
    var headers = {
        "X-App-Id": options.applicationId,
        "X-App-Token": options.clientSecretKey
    };

    function errorMessage(statusCode, body) {
        return util.format("Unexpected status code: %d - Details: %j", statusCode, body);
    }

    function prepare(callback) {
        var deferred = when.defer();

        if (typeof(callback) === "function") {
            return {
                callback: function(error, res, body) {
                    if (error || res.statusCode >= 400) {
                        var message = errorMessage(res.statusCode, body);

                        callback(error || new Error(message));
                        return;
                    }

                    callback(null, body);
                }
            };
        } else {
            return {
                promise: deferred.promise,
                callback: function(error, res, body) {
                    if (error || res.statusCode >= 400) {
                        var message = errorMessage(res.statusCode, body);

                        deferred.reject(error || new Error(message));
                        return;
                    }

                    deferred.resolve(body);
                }
            };
        }
    }

    return {
        get: function(code, callback) {
            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.get({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        usage: function(code, callback) {
            var url = util.format("%s/vouchers/%s/usage", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.get({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        use: function(code, trackingId, callback) {
            // No `tracking_id` passed here,
            // use callback from 2n argument.
            if (typeof(trackingId) === "function") {
                callback = trackingId;
                trackingId = undefined;
            }

            var handler = prepare(callback);
            var url = util.format("%s/vouchers/%s/usage", backendUrl, encodeURIComponent(code));

            // If `tracking_id` passed, use it in query string.
            if (typeof(trackingId) === "string" && trackingId) {
                url += "?tracking_id=" + encodeURIComponent(trackingId);
            }

            console.log(url);

            request.post({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        }
    };
};<commit_msg>Removed unused log<commit_after>"use strict";

var util = require("util");

var request = require("request");
var when = require("when");

var backendUrl = "https://voucherify-bouncer.herokuapp.com/v1";

module.exports = function(options) {
    var headers = {
        "X-App-Id": options.applicationId,
        "X-App-Token": options.clientSecretKey
    };

    function errorMessage(statusCode, body) {
        return util.format("Unexpected status code: %d - Details: %j", statusCode, body);
    }

    function prepare(callback) {
        var deferred = when.defer();

        if (typeof(callback) === "function") {
            return {
                callback: function(error, res, body) {
                    if (error || res.statusCode >= 400) {
                        var message = errorMessage(res.statusCode, body);

                        callback(error || new Error(message));
                        return;
                    }

                    callback(null, body);
                }
            };
        } else {
            return {
                promise: deferred.promise,
                callback: function(error, res, body) {
                    if (error || res.statusCode >= 400) {
                        var message = errorMessage(res.statusCode, body);

                        deferred.reject(error || new Error(message));
                        return;
                    }

                    deferred.resolve(body);
                }
            };
        }
    }

    return {
        get: function(code, callback) {
            var url = util.format("%s/vouchers/%s", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.get({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        usage: function(code, callback) {
            var url = util.format("%s/vouchers/%s/usage", backendUrl, encodeURIComponent(code));
            var handler = prepare(callback);

            request.get({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        },

        use: function(code, trackingId, callback) {
            // No `tracking_id` passed here,
            // use callback from 2n argument.
            if (typeof(trackingId) === "function") {
                callback = trackingId;
                trackingId = undefined;
            }

            var handler = prepare(callback);
            var url = util.format("%s/vouchers/%s/usage", backendUrl, encodeURIComponent(code));

            // If `tracking_id` passed, use it in query string.
            if (typeof(trackingId) === "string" && trackingId) {
                url += "?tracking_id=" + encodeURIComponent(trackingId);
            }

            request.post({ url: url, headers: headers, json: true }, handler.callback);

            return handler.promise;
        }
    };
};<|endoftext|>


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

/**
 *
 * @param {object} config
 * @return {function}
 */
function safeExternalLinksSetup(config = {}) {
  const pattern = new RegExp(config.pattern || 'https{0,1}://');
  const noopener = config.hasOwnProperty('noopener') ? config.noopener : true;
  const noreferrer = config.hasOwnProperty('noreferrer') ? config.noreferrer : false;
  const files = config.files || ['.html'];

  /**
   * @param {string} content
   * @param {string} outputPath
   * @return {string}
   */
  return function safeExternalLinks(content, outputPath) {
    const ext = path.extname(outputPath);

    console.log(ext);
    console.log(!files.includes(ext));

    if (!files.includes(ext)) return content;

    try {
      const $ = cheerio.load(content);
      const links = $('a').get();

      if (links.length) {
        for (let i = 0; i < links.length; i++) {
          const link = links[i];
          const href = $(link).attr('href');

          if (pattern.test(href)) {
            const rel = [];
            if (noopener) {
              rel.push('noopener');
            }

            if (noreferrer) {
              rel.push('noreferrer');
            }

            if (rel.length) {
              $(link).attr('rel', rel.join(' '));
            }

            $(link).replaceWith($.html(link));
          }
        }

        return $.html();
      }
    } catch (e) {
      // console.error(e);
    }

    return content;
  };
}

module.exports = safeExternalLinksSetup;
<commit_msg>🚑 (eleventy-plugin-safe-external-links) Remove console logging nonsense<commit_after>/**
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
const cheerio = require('cheerio');
const path = require('path');

/**
 *
 * @param {object} config
 * @return {function}
 */
function safeExternalLinksSetup(config = {}) {
  const pattern = new RegExp(config.pattern || 'https{0,1}://');
  const noopener = config.hasOwnProperty('noopener') ? config.noopener : true;
  const noreferrer = config.hasOwnProperty('noreferrer') ? config.noreferrer : false;
  const files = config.files || ['.html'];

  /**
   * @param {string} content
   * @param {string} outputPath
   * @return {string}
   */
  return function safeExternalLinks(content, outputPath) {
    const ext = path.extname(outputPath);

    if (!files.includes(ext)) return content;

    try {
      const $ = cheerio.load(content);
      const links = $('a').get();

      if (links.length) {
        for (let i = 0; i < links.length; i++) {
          const link = links[i];
          const href = $(link).attr('href');

          if (pattern.test(href)) {
            const rel = [];
            if (noopener) {
              rel.push('noopener');
            }

            if (noreferrer) {
              rel.push('noreferrer');
            }

            if (rel.length) {
              $(link).attr('rel', rel.join(' '));
            }

            $(link).replaceWith($.html(link));
          }
        }

        return $.html();
      }
    } catch (e) {
      // console.error(e);
    }

    return content;
  };
}

module.exports = safeExternalLinksSetup;
<|endoftext|>


<commit_before>var bookmarks_page = 0;
var bookmarks_loading = false;

var bookmarks_sorting = 'bookmarks_sorting_recent';

$(document).ready(function() {
	$('#bookmark_add_submit').click(addBookmark);
	$(window).resize(function () {
		fillWindow($('.bookmarks_list'));
	});
	$(window).resize();
	$('.bookmarks_list').scroll(updateOnBottom).empty().width($('#rightcontent').width());
	$('#tag_filter input').tagit({
		allowSpaces: true,
		availableTags: fullTags,
		onTagRemoved: filterTagsChanged
	}).tagit('option', 'onTagAdded', filterTagsChanged);

	getBookmarks();
});

function addFilterTag(event) {
	event.preventDefault();
	$('#tag_filter input').tagit('createTag', $(this).text());
}

function updateTagsList(tag) {
	$('.tag_list').append('
'+tag['tag']+''+
		'
'+
			''+
				''+
			''+
			''+
				''+
			''+
		'
'+
		''+tag['nbr']+''+
	'
');
}

function filterTagsChanged()
{
	$('#bookmarkFilterTag').val($('#tag_filter input:hidden').val());
	bookmarks_page = 0;
	$('.bookmarks_list').empty();
	getBookmarks();
}
function getBookmarks() {
	if(bookmarks_loading) {
		//have patience :)
		return;
	}
	//Update Rel Tags
	$.ajax({
		type: 'POST',
		url: OC.filePath('bookmarks', 'ajax', 'updateList.php') + '&type=rel_tags',
		data: {tag: $('#bookmarkFilterTag').val(), page:bookmarks_page, sort:bookmarks_sorting },
		success: function(tags){
			$('.tag_list').empty();
			for(var i in tags.data) {
				updateTagsList(tags.data[i]);
			}
			$('.tag_list a.tag').click(addFilterTag);
		}
	});

	$.ajax({
		type: 'POST',
		url: OC.filePath('bookmarks', 'ajax', 'updateList.php') + '&type=bookmark',
		data: {tag: $('#bookmarkFilterTag').val(), page:bookmarks_page, sort:bookmarks_sorting },
		success: function(bookmarks){
			if (bookmarks.data.length) {
				bookmarks_page += 1;
			}
			$('.bookmark_link').unbind('click', recordClick);
			$('.bookmark_delete').unbind('click', delBookmark);
			$('.bookmark_edit').unbind('click', editBookmark);

			for(var i in bookmarks.data) {
				updateBookmarksList(bookmarks.data[i]);
				$("#firstrun").hide();
			}
			if($('.bookmarks_list').is(':empty')) {
				$("#firstrun").show();
			}

			$('.bookmark_link').click(recordClick);
			$('.bookmark_delete').click(delBookmark);
			$('.bookmark_edit').click(editBookmark);

			bookmarks_loading = false;
			if (bookmarks.data.length) {
				updateOnBottom()
			}
		}
	});
}

function createEditDialog(record){
	dialog_html = $('#edit_dialog').html();
	var dialog = $(dialog_html).dialog({
		width : 620,
		height: 450,
		title: t('bookmark', 'Edit bookmark'),
		modal: true,
		close : function(event, ui) {
			$(this).dialog('destroy').remove();
		}
	});

	$('.ui-dialog').bookmark_dialog({
		on_success: function(){
			dialog.dialog('destroy').remove();
			filterTagsChanged();
		},
		record: record
	});
}

function addBookmark(event) {
	createEditDialog();
}

function delBookmark(event) {
	var record = $(this).parent().parent();
	$.ajax({
		type: 'POST',
		url: OC.filePath('bookmarks', 'ajax', 'delBookmark.php'),
		data: 'id=' + record.data('id'),
		success: function(data){
			if (data.status == 'success') {
				record.remove();
				if($('.bookmarks_list').is(':empty')) {
					$("#firstrun").show();
				}
			}
		}
	});
}

function editBookmark(event) {
	var record = $(this).parent().parent();
	bookmark =  record.data('record');
	createEditDialog(bookmark);
}

function replaceQueryString(url,param,value) {
    var re = new RegExp("([?|&])" + param + "=.*?(&|$)","i");
    if (url.match(re))
        return url.replace(re,'$1' + param + "=" + value + '$2');
    else
        return url + '&' + param + "=" + value;
}

function updateBookmarksList(bookmark) {
	var tags = bookmark.tags;
	var taglist = '';
	for ( var i=0, len=tags.length; i<len; ++i ){
		if(tags[i] != '')
			taglist = taglist + '' + encodeEntities(tags[i]) + ' ';
	}
	if(!hasProtocol(bookmark.url)) {
		bookmark.url = 'http://' + bookmark.url;
	}
	if(bookmark.title == '') bookmark.title = bookmark.url;
	$('.bookmarks_list').append(
		'
' +
			'
' +
				'' +
					'' +
				'' +
				'' +
					'' +
				' ' +
			'
' +
			'
'+
				'' + encodeEntities(bookmark.title) + '' +
			'
' +
			'
' + encodeEntities(bookmark.url) + '
' +
		'
'
	);
	$('div[data-id="'+ bookmark.id +'"]').data('record', bookmark);
	if(taglist != '') {
		$('div[data-id="'+ bookmark.id +'"]').append('
' + taglist + '
');
	}
}

function updateOnBottom() {
	//check wether user is on bottom of the page
	var top = $('.bookmarks_list>:last-child').position().top;
	var height = $('.bookmarks_list').height();
	// use a bit of margin to begin loading before we are really at the
	// bottom
	if (top < height * 1.2) {
	//	getBookmarks();
	}
}

function recordClick(event) {
	$.ajax({
		type: 'POST',
		url: OC.filePath('bookmarks', 'ajax', 'recordClick.php'),
		data: 'url=' + encodeURIComponent($(this).attr('href')),
	});
}

function encodeEntities(s){
	try {
		return $('
').text(s).html();
	} catch (ex) {
		return "";
	}
}

function hasProtocol(url) {
    var regexp = /(ftp|http|https|sftp)/;
    return regexp.test(url);
}
<commit_msg>Fix in list tag filtering<commit_after>var bookmarks_page = 0;
var bookmarks_loading = false;

var bookmarks_sorting = 'bookmarks_sorting_recent';

$(document).ready(function() {
	$('#bookmark_add_submit').click(addBookmark);
	$(window).resize(function () {
		fillWindow($('.bookmarks_list'));
	});
	$(window).resize();
	$('.bookmarks_list').scroll(updateOnBottom).empty().width($('#rightcontent').width());
	$('#tag_filter input').tagit({
		allowSpaces: true,
		availableTags: fullTags,
		onTagRemoved: filterTagsChanged
	}).tagit('option', 'onTagAdded', filterTagsChanged);

	getBookmarks();
});

function addFilterTag(event) {
	event.preventDefault();
	$('#tag_filter input').tagit('createTag', $(this).text());
}

function updateTagsList(tag) {
	$('.tag_list').append('
'+tag['tag']+''+
		'
'+
			''+
				''+
			''+
			''+
				''+
			''+
		'
'+
		''+tag['nbr']+''+
	'
');
}

function filterTagsChanged()
{
	$('#bookmarkFilterTag').val($('#tag_filter input:hidden').val());
	bookmarks_page = 0;
	$('.bookmarks_list').empty();
	getBookmarks();
}
function getBookmarks() {
	if(bookmarks_loading) {
		//have patience :)
		return;
	}
	//Update Rel Tags
	$.ajax({
		type: 'POST',
		url: OC.filePath('bookmarks', 'ajax', 'updateList.php') + '&type=rel_tags',
		data: {tag: $('#bookmarkFilterTag').val(), page:bookmarks_page, sort:bookmarks_sorting },
		success: function(tags){
			$('.tag_list').empty();
			for(var i in tags.data) {
				updateTagsList(tags.data[i]);
			}
			$('.tag_list a.tag').click(addFilterTag);
		}
	});

	$.ajax({
		type: 'POST',
		url: OC.filePath('bookmarks', 'ajax', 'updateList.php') + '&type=bookmark',
		data: {tag: $('#bookmarkFilterTag').val(), page:bookmarks_page, sort:bookmarks_sorting },
		success: function(bookmarks){
			if (bookmarks.data.length) {
				bookmarks_page += 1;
			}
			$('.bookmark_link').unbind('click', recordClick);
			$('.bookmark_delete').unbind('click', delBookmark);
			$('.bookmark_edit').unbind('click', editBookmark);

			for(var i in bookmarks.data) {
				updateBookmarksList(bookmarks.data[i]);
				$("#firstrun").hide();
			}
			if($('.bookmarks_list').is(':empty')) {
				$("#firstrun").show();
			}

			$('.bookmark_link').click(recordClick);
			$('.bookmark_delete').click(delBookmark);
			$('.bookmark_edit').click(editBookmark);

			bookmarks_loading = false;
			if (bookmarks.data.length) {
				updateOnBottom()
			}
		}
	});
}

function createEditDialog(record){
	dialog_html = $('#edit_dialog').html();
	var dialog = $(dialog_html).dialog({
		width : 620,
		height: 450,
		title: t('bookmark', 'Edit bookmark'),
		modal: true,
		close : function(event, ui) {
			$(this).dialog('destroy').remove();
		}
	});

	$('.ui-dialog').bookmark_dialog({
		on_success: function(){
			dialog.dialog('destroy').remove();
			filterTagsChanged();
		},
		record: record
	});
}

function addBookmark(event) {
	createEditDialog();
}

function delBookmark(event) {
	var record = $(this).parent().parent();
	$.ajax({
		type: 'POST',
		url: OC.filePath('bookmarks', 'ajax', 'delBookmark.php'),
		data: 'id=' + record.data('id'),
		success: function(data){
			if (data.status == 'success') {
				record.remove();
				if($('.bookmarks_list').is(':empty')) {
					$("#firstrun").show();
				}
			}
		}
	});
}

function editBookmark(event) {
	var record = $(this).parent().parent();
	bookmark =  record.data('record');
	createEditDialog(bookmark);
}

function updateBookmarksList(bookmark) {
	var tags = bookmark.tags;
	var taglist = '';
	for ( var i=0, len=tags.length; i<len; ++i ){
		if(tags[i] != '')
			taglist = taglist + '' + encodeEntities(tags[i]) + ' ';
	}
	if(!hasProtocol(bookmark.url)) {
		bookmark.url = 'http://' + bookmark.url;
	}
	if(bookmark.title == '') bookmark.title = bookmark.url;
	$('.bookmarks_list').append(
		'
' +
			'
' +
				'' +
					'' +
				'' +
				'' +
					'' +
				' ' +
			'
' +
			'
'+
				'' + encodeEntities(bookmark.title) + '' +
			'
' +
			'
' + encodeEntities(bookmark.url) + '
' +
		'
'
	);
	$('div[data-id="'+ bookmark.id +'"]').data('record', bookmark);
	if(taglist != '') {
		$('div[data-id="'+ bookmark.id +'"]').append('
' + taglist + '
');
	}
	$('div[data-id="'+ bookmark.id +'"] a.bookmark_tag').bind('click', addFilterTag);

}

function updateOnBottom() {
	//check wether user is on bottom of the page
	var top = $('.bookmarks_list>:last-child').position().top;
	var height = $('.bookmarks_list').height();
	// use a bit of margin to begin loading before we are really at the
	// bottom
	if (top < height * 1.2) {
	//	getBookmarks();
	}
}

function recordClick(event) {
	$.ajax({
		type: 'POST',
		url: OC.filePath('bookmarks', 'ajax', 'recordClick.php'),
		data: 'url=' + encodeURIComponent($(this).attr('href')),
	});
}

function encodeEntities(s){
	try {
		return $('
').text(s).html();
	} catch (ex) {
		return "";
	}
}

function hasProtocol(url) {
    var regexp = /(ftp|http|https|sftp)/;
    return regexp.test(url);
}
<|endoftext|>


<commit_before>// -*- Mode: JavaScript; tab-width: 4 -*- vim:tabstop=4 syntax=javascript:
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*global module: false */

module.version = "1.2.1 (2013-12-24)";
module.prefs = {
	"fnqwebirc": true,
	"help!": true,
	"ciao": true,
	"!list": true,
	"!kick": true,
	"!ban": true,
	"!kb": true
};
module.strings = {
	"fnqwebirc": ":[{0}] Welcome! To allow other users to identify you more easily, please change your nick (/nick newnickname). Thanks!",
	"help!": "Welcome! To get help, please state your problem. Being specific will get you help faster.",
	"ciao": "Welcome. Please note we do not support warez around here, as this is a free, open-source software network.",
	"!list": ":No warez for you!",
	"!kick": ":you asked for it",
	"!kb": ":you asked for it"
};
module.parseln = function parseln(ln, conn) {
	if (!(this.prefs.fnqwebirc && /^:(qwebirc\d+)![0-9a-f]+@gateway\/web\/freenode\/ip\.\d+\.\d+\.\d+\.\d+ JOIN :?(\S+)/.test(ln))) {
		return false;
	}
	conn.send("CNOTICE", RegExp.$1, RegExp.$2, this.strings.fnqwebirc.format(RegExp.$2));
	return true;
};
module.onMsg = function onMsg(e) {
	var dest = e.dest, msg = e.msg, nick = e.nick, conn = e.conn;
	msg = msg.split(" ");
	var arg = msg[1];
	switch (msg[0]) {
	case "help": case "help!":
		if (this.prefs["help!"] && msg.length === 1) {
			e.reply(this.strings["help!"]);
			return true;
		}
		break;
	case "ciao":
		if (this.prefs.ciao && msg.length === 1) {
			e.notice(this.strings.ciao);
			return true;
		}
		break;
	case "!list":
		if (this.prefs["!list"] && msg.length === 1) {
			conn.send("KICK", dest, nick, this.strings["!list"]);
			return true;
		}
		break;
	case "!kick": case "!k":
		if (this.prefs["!kick"] && (!arg || arg === nick)) {
			conn.send("KICK", dest, nick, this.strings["!kick"]);
			return true;
		}
		break;
	case "!ban": case "!b":
		if (this.prefs["!ban"] && (!arg || arg === nick) && e.okToKick()) {
			conn.send("MODE", dest, "+b", "*!*@" + host);
			return true;
		}
		break;
	case "!kick-ban": case "!kickban": case "!kb":
		if (this.prefs["!kb"] && (!arg || arg === nick) && e.okToKick()) {
			conn.send("KICK", dest, nick, this.strings["!kb"]);
			conn.send("MODE", dest, "+b", "*!*@" + host);
			return true;
		}
		break;
	}
};
<commit_msg>deidiotify.jsm: onUnknownMsg, saner prefs<commit_after>// -*- Mode: JavaScript; tab-width: 4 -*- vim:tabstop=4 syntax=javascript:
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*global module: false */

module.version = "1.2.3 (2014-01-21)";
module.prefs = {
	"fnqwebirc": true,
	"help!": true,
	"ciao": false,
	"!list": false,
	"kick": true,
	"ban": true,
	"!kb": true
};
module.strings = {
	"fnqwebirc": ":[{0}] Welcome! To allow other users to identify you more easily, please change your nick (/nick newnickname). Thanks!",
	"help!": "Welcome! To get help, please state your problem. Being specific will get you help faster.",
	"ciao": "Welcome. Please note we do not support warez around here, as this is a free, open-source software network.",
	"!list": ":No warez for you!",
	"kick": ":you asked for it",
	"!kb": ":you asked for it"
};
module.parseln = function parseln(ln, conn) {
	if (!(this.prefs.fnqwebirc && /^:(qwebirc\d+)![0-9a-f]+@gateway\/web\/freenode\/ip\.\d+\.\d+\.\d+\.\d+ JOIN :?(\S+)/.test(ln))) {
		return false;
	}
	conn.send("CNOTICE", RegExp.$1, RegExp.$2, this.strings.fnqwebirc.format(RegExp.$2));
	return true;
};
module.onUnknownMsg = function onUnknownMsg(e) {
	var dest = e.dest, msg = e.msg, nick = e.nick, conn = e.conn;
	msg = msg.split(" ");
	var arg = msg[1];
	switch (msg[0]) {
	case "help": case "help!":
		if (this.prefs["help!"] && msg.length === 1) {
			e.reply(this.strings["help!"]);
			return true;
		}
		break;
	case "ciao":
		if (this.prefs.ciao && msg.length === 1) {
			e.notice(this.strings.ciao);
			return true;
		}
		break;
	case "!list":
		if (this.prefs["!list"] && msg.length === 1) {
			conn.send("KICK", dest, nick, this.strings["!list"]);
			return true;
		}
		break;
	case "!kick": case "!k":
		if (this.prefs.kick && (!arg || arg === nick || arg === "me")) {
			conn.send("KICK", dest, nick, this.strings.kick);
			return true;
		}
		break;
	case "!ban": case "!b":
		if (this.prefs.ban && (!arg || arg === nick || arg === "me") && e.okToKick()) {
			conn.send("MODE", dest, "+b", "*!*@" + host);
			return true;
		}
		break;
	case "!kick-ban": case "!kickban": case "!kb":
		if (this.prefs["!kb"] && (!arg || arg === nick || arg === "me") && e.okToKick()) {
			conn.send("KICK", dest, nick, this.strings["!kb"]);
			conn.send("MODE", dest, "+b", "*!*@" + host);
			return true;
		}
		break;
	}
};
<|endoftext|>


<commit_before>import React from 'react'
import {connect, select} from 'store'
import styles from './navBar.module.css'
import Tooltip from 'widget/tooltip'
import {Link} from 'route'
import {requestedApps, quitApp} from 'apps'
import Icon from 'widget/icon'
import actionBuilder from 'action-builder'
import ToggleSwitch from 'widget/toggleSwitch'
import FlipSwitch from 'widget/flipSwitch'
import PropTypes from 'prop-types'

export function isNavBarLocked() {
    return select('menu.locked') == null ? true : !!select('menu.locked')
}

const mapStateToProps = () => ({
    requestedApps: requestedApps(),
    locked: isNavBarLocked()
})

class NavBar extends React.Component {
    appSection(app) {
        return <AppLink key={app.path} app={app}/>
    }

    setUnlocked(unlocked) {
        actionBuilder('TOGGLE_MENU')
            .set('menu.locked', !unlocked)
            .dispatch()
    }

    render() {
        const {requestedApps} = this.props
        return (

                    <LockSwitch locked={this.props.locked} onChange={this.setUnlocked.bind(this)}/>
                    <SectionLink name='process' icon='globe'/>
                    <SectionLink name='browse' icon='folder-open'/>
                    <SectionLink name='terminal' icon='terminal'/>
                    <SectionLink name='app-launch-pad' icon='wrench'/>
                    {requestedApps.map(this.appSection)}

        )
    }
}

NavBar.propTypes = {
    locked: PropTypes.bool.isRequired,
    requestedApps: PropTypes.arrayOf(PropTypes.object).isRequired
}

const SectionLink = ({name, icon}) =>
    <Link to={'/' + name} onMouseDown={(e) => e.preventDefault()}>
        <Tooltip msg={'home.sections.' + name} right>
            <button className={`${styles[name]}`}>
                <Icon name={icon}/>
            </button>
        </Tooltip>
    </Link>

SectionLink.propTypes = {
    name: PropTypes.string,
    icon: PropTypes.string
}

const AppLink = ({app: {path, label, alt}}) =>

 quitApp(path)}>
            <Icon name='times'/>

        <Link to={'/app' + path} onMouseDown={(e) => e.preventDefault()}>
            <Tooltip rawMsg={label || alt} right>
                <button>
                    <Icon name='cubes'/>
                </button>
            </Tooltip>
        </Link>

AppLink.propTypes = {
    app: PropTypes.object,
    path: PropTypes.string,
    label: PropTypes.string,
    alt: PropTypes.string,
    onRemove: PropTypes.func
}

const LockSwitch = ({locked, onChange}) =>
    <Tooltip msg={locked ? 'home.sections.locked' : 'home.sections.unlocked'} right>

            {/* <FlipSwitch */}
            <ToggleSwitch
                on={!locked}
                offIcon='unlock'
                onIcon='lock'
                onChange={onChange}/>

    </Tooltip>

LockSwitch.propTypes = {
    locked: PropTypes.bool,
    onChange: PropTypes.func
}

export default NavBar = connect(mapStateToProps)(NavBar)
<commit_msg>Trying flipswitch for navbar behavior.<commit_after>import React from 'react'
import {connect, select} from 'store'
import styles from './navBar.module.css'
import Tooltip from 'widget/tooltip'
import {Link} from 'route'
import {requestedApps, quitApp} from 'apps'
import Icon from 'widget/icon'
import actionBuilder from 'action-builder'
import ToggleSwitch from 'widget/toggleSwitch'
import FlipSwitch from 'widget/flipSwitch'
import PropTypes from 'prop-types'

export function isNavBarLocked() {
    return select('menu.locked') == null ? true : !!select('menu.locked')
}

const mapStateToProps = () => ({
    requestedApps: requestedApps(),
    locked: isNavBarLocked()
})

class NavBar extends React.Component {
    appSection(app) {
        return <AppLink key={app.path} app={app}/>
    }

    setUnlocked(unlocked) {
        actionBuilder('TOGGLE_MENU')
            .set('menu.locked', !unlocked)
            .dispatch()
    }

    render() {
        const {requestedApps} = this.props
        return (

                    <LockSwitch locked={this.props.locked} onChange={this.setUnlocked.bind(this)}/>
                    <SectionLink name='process' icon='globe'/>
                    <SectionLink name='browse' icon='folder-open'/>
                    <SectionLink name='terminal' icon='terminal'/>
                    <SectionLink name='app-launch-pad' icon='wrench'/>
                    {requestedApps.map(this.appSection)}

        )
    }
}

NavBar.propTypes = {
    locked: PropTypes.bool.isRequired,
    requestedApps: PropTypes.arrayOf(PropTypes.object).isRequired
}

const SectionLink = ({name, icon}) =>
    <Link to={'/' + name} onMouseDown={(e) => e.preventDefault()}>
        <Tooltip msg={'home.sections.' + name} right>
            <button className={`${styles[name]}`}>
                <Icon name={icon}/>
            </button>
        </Tooltip>
    </Link>

SectionLink.propTypes = {
    name: PropTypes.string,
    icon: PropTypes.string
}

const AppLink = ({app: {path, label, alt}}) =>

 quitApp(path)}>
            <Icon name='times'/>

        <Link to={'/app' + path} onMouseDown={(e) => e.preventDefault()}>
            <Tooltip rawMsg={label || alt} right>
                <button>
                    <Icon name='cubes'/>
                </button>
            </Tooltip>
        </Link>

AppLink.propTypes = {
    app: PropTypes.object,
    path: PropTypes.string,
    label: PropTypes.string,
    alt: PropTypes.string,
    onRemove: PropTypes.func
}

const LockSwitch = ({locked, onChange}) =>
    <Tooltip msg={locked ? 'home.sections.locked' : 'home.sections.unlocked'} right>

            <FlipSwitch
            // <ToggleSwitch
                on={!locked}
                offIcon='unlock'
                onIcon='lock'
                onChange={onChange}/>

    </Tooltip>

LockSwitch.propTypes = {
    locked: PropTypes.bool,
    onChange: PropTypes.func
}

export default NavBar = connect(mapStateToProps)(NavBar)
<|endoftext|>


<commit_before>var boomerang = angular.module('gdgBoomerang', ['ngSanitize', 'ui.bootstrap'])
    .config([
    '$httpProvider',
    '$interpolateProvider',
    '$routeProvider',
    function($httpProvider, $interpolateProvider, $routeProvider) {
        $interpolateProvider.startSymbol('{$');
        $interpolateProvider.endSymbol('$}');
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
        $routeProvider.
          when("/about", {templateUrl: 'views/about.html', controller: "AboutControl"}).
          when("/news", {templateUrl: 'views/news.html', controller: "NewsControl"}).
          when("/events", {templateUrl: 'views/events.html', controller: "EventsControl"}).
          when("/photos", {templateUrl: 'views/photos.html', controller: "PhotosControl"}).
          otherwise({ redirectTo: '/about' });
    }]);

boomerang.controller('MainControl', function ($scope, Config) {
    $scope.chapter_name = Config.name;
    $scope.google_plus_link = 'https://plus.google.com/' + Config.id;
    $scope.isNavCollapsed = true;
});

boomerang.controller('AboutControl', function ($scope, $http, $location, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "about";
    $scope.cover = Config.cover;
    $http.jsonp('https://www.googleapis.com/plus/v1/people/' + Config.id +
            '?callback=JSON_CALLBACK&fields=aboutMe%2Ccover%2Cimage%2CplusOneCount&key=' + Config.google_api).
        success(function (data) {
            console.log(data);
            $scope.desc = data.aboutMe;
            if (data.cover && data.cover.coverPhoto.url) {
                $scope.cover.url = data.cover.coverPhoto.url;
            }
            $scope.loading = false;
        });
});

boomerang.controller("NewsControl", function ($scope, $http, $timeout, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "news";
    $http.
        jsonp('https://www.googleapis.com/plus/v1/people/' + Config.id +
            '/activities/public?callback=JSON_CALLBACK&maxResults=10&key=' + Config.google_api).
        success(function (response) {
            var entries = [], i, j;
            for (i = 0; i < response.items.length; i++) {
                var item = response.items[i];
                var actor = item.actor || {};
                var object = item.object || {};
                // Normalize tweet to a FriendFeed-like entry.
                // var itemTitle = '' + item.title + '';
                var itemTitle = object.content;

                if(item.annotation)
                  itemTitle = item.annotation;

                var html = [itemTitle.replace(new RegExp('\n', 'g'), '
').replace('

', '
')];
                //html.push(' Read More »');

                var thumbnails = [];

                var attachments = object.attachments || [];
                for (j = 0; j < attachments.length; j++) {
                    var attachment = attachments[j];
                    switch (attachment.objectType) {
                        case 'album':
                            break;// TODO needs more work
                            var upper = attachment.thumbnails.length > 7 ? 7 : attachment.thumbnails.length;
                            html.push('
');
                            for (var k = 1; k < upper; k++) {
                                html.push('

');
                            }
                            html.push('
');
                            break;
                        case 'photo':
                            thumbnails.push({
                                url: attachment.image.url,
                                link: attachment.fullImage.url
                            });
                            break;

                        case 'video':
                            thumbnails.push({
                                url: attachment.image.url,
                                link: attachment.url
                            });
                            break;

                        case 'article': case 'event':
                            html.push('
' + attachment.displayName + '');
                            if (attachment.content) {
                                html.push('
' + attachment.content + '');
                            }
                            html.push('
');
                            break;
                        /* case 'event':
                            console.log(attachment);
                            html.push('
' + attachment.displayName + '');
                            html.push('
' + attachment.content.replace(new RegExp('\n', 'g'), '
') + '
');
                            break; */
                        default :
                            console.log(attachment.objectType);
                    }
                }

                html = html.join('');

                var actorImage = actor.image.url;
                actorImage = actorImage.substr(0, actorImage.length - 2) + '16';
                // The replace in the item URL is a dirty quick fix for issue #20 which seems to be a g+ api bug
                var entry = {
                    via: {
                        name: 'Google+',
                        url: item.url.replace('https://plus.google.com/https://plus.google.com', 'https://plus.google.com')
                    },
                    body: html,
                    date: item.updated,
                    reshares: (object.resharers || {}).totalItems,
                    plusones: (object.plusoners || {}).totalItems,
                    comments: (object.replies || {}).totalItems,
                    thumbnails: thumbnails,
                    icon: actorImage
                };

                entries.push(entry);
            }
            $scope.news = entries;
            $timeout(function () {
                gapi.plusone.go();
            });
            $scope.loading = false;
        });

});

boomerang.controller("EventsControl", function ($scope, $http, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "events";

    $scope.events = {past: [], future: []};
    $http.get("http://gdgfresno.com/gdgfeed.php?id=" + Config.id).
        success(function (data) {
            var now = new Date();
            for (var i = data.length - 1; i >= 0; i--) {
                var start = new Date(data[i].start);

                data[i].start = start;
                data[i].end = new Date(data[i].end);

                if (start < now) {
                    $scope.events.past.push(data[i]);
                } else {
                    $scope.events.future.push(data[i]);
                }
            }
            $scope.loading = false;
        });

});

boomerang.controller("PhotosControl", function ($scope, $http, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "photos";
    $scope.photos = [];

    var pwa = 'https://picasaweb.google.com/data/feed/api/user/' + Config.id + '/albumid/' + Config.pwa_id +
        '?access=public&alt=json-in-script&kind=photo&max-results=20&fields=entry(title,link/@href,summary,content/@src)&v=2.0&callback=JSON_CALLBACK';

    $http.jsonp(pwa).
        success(function (d) {
            var p = d.feed.entry;
            for (var x in p) {
                var photo = {
                    link: p[x].link[1].href,
                    src: p[x].content.src,
                    alt: p[x].title.$t,
                    title: p[x].summary.$t
                };
                $scope.photos.push(photo);
            }
            $scope.loading = false;
        });
});

// HTML-ified linky from http://plnkr.co/edit/IEpLfZ8gO2B9mJcTKuWY?p=preview
boomerang.filter('htmlLinky', function($sanitize, linkyFilter) {
    var ELEMENT_NODE = 1;
    var TEXT_NODE = 3;
    var linkifiedDOM = document.createElement('div');
    var inputDOM = document.createElement('div');

    var linkify = function linkify(startNode) {
        var i, currentNode;

        for (i = 0; i < startNode.childNodes.length; i++) {
            currentNode = startNode.childNodes[i];

            switch (currentNode.nodeType) {
                case ELEMENT_NODE:
                    linkify(currentNode);
                    break;
                case TEXT_NODE:
                    linkifiedDOM.innerHTML = linkyFilter(currentNode.textContent);
                    i += linkifiedDOM.childNodes.length - 1;

                    while(linkifiedDOM.childNodes.length)
                        startNode.insertBefore(linkifiedDOM.childNodes[0], currentNode);

                    startNode.removeChild(currentNode);
            }
        }

        return startNode;
    };

    return function(input) {
        inputDOM.innerHTML = input;
        return linkify(inputDOM).innerHTML;
    };
});

boomerang.filter('hashLinky', function($sanitize, linkyFilter) {
    var ELEMENT_NODE = 1;
    var TEXT_NODE = 3;
    var linkifiedDOM = document.createElement('div');
    var inputDOM = document.createElement('div');

    var hashLinky = function hashLinky(startNode) {
        var i, currentNode;

        for (i = 0; i < startNode.childNodes.length; i++) {
            currentNode = startNode.childNodes[i];

            switch (currentNode.nodeType) {
                case ELEMENT_NODE:
                    hashLinky(currentNode);
                    break;
                case TEXT_NODE:
                    var hashtagRegex = /#([A-Za-z0-9-_]+)/g;
                    currentNode.textContent =  currentNode.textContent.replace(hashtagRegex,
                        '#$1');

                    linkifiedDOM.innerHTML = currentNode.textContent;
                    i += linkifiedDOM.childNodes.length - 1;

                    while(linkifiedDOM.childNodes.length) {
                        startNode.insertBefore(linkifiedDOM.childNodes[0], currentNode);
                    }
                    startNode.removeChild(currentNode);
            }
        }

        return startNode;
    };

    return function(input) {
        inputDOM.innerHTML = input;
        return hashLinky(inputDOM).innerHTML;
    };
});
<commit_msg>Update boomerang.js<commit_after>var boomerang = angular.module('gdgBoomerang', ['ngSanitize', 'ui.bootstrap'])
    .config([
    '$httpProvider',
    '$interpolateProvider',
    '$routeProvider',
    function($httpProvider, $interpolateProvider, $routeProvider) {
        $interpolateProvider.startSymbol('{$');
        $interpolateProvider.endSymbol('$}');
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
        $routeProvider.
          when("/about", {templateUrl: 'views/about.html', controller: "AboutControl"}).
          when("/news", {templateUrl: 'views/news.html', controller: "NewsControl"}).
          when("/events", {templateUrl: 'views/events.html', controller: "EventsControl"}).
          when("/photos", {templateUrl: 'views/photos.html', controller: "PhotosControl"}).
          otherwise({ redirectTo: '/about' });
    }]);

boomerang.controller('MainControl', function ($scope, Config) {
    $scope.chapter_name = Config.name;

    $scope.chapter_id = Config.id;
    $scope.site_link = 'http://' + angular.lowercase(Config.name.replace(new RegExp(' ', 'g'), '')) + '.appspot.com';
    $scope.google_plus_link = 'https://plus.google.com/' + Config.id;
    $scope.isNavCollapsed = true;
});

boomerang.controller('AboutControl', function ($scope, $http, $location, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "about";
    $scope.cover = Config.cover;
    $http.jsonp('https://www.googleapis.com/plus/v1/people/' + Config.id +
            '?callback=JSON_CALLBACK&fields=aboutMe%2Ccover%2Cimage%2CplusOneCount&key=' + Config.google_api).
        success(function (data) {
            console.log(data);
            $scope.desc = data.aboutMe;
            if (data.cover && data.cover.coverPhoto.url) {
                $scope.cover.url = data.cover.coverPhoto.url;
            }
            $scope.loading = false;
        });
});

boomerang.controller("NewsControl", function ($scope, $http, $timeout, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "news";
    $http.
        jsonp('https://www.googleapis.com/plus/v1/people/' + Config.id +
            '/activities/public?callback=JSON_CALLBACK&maxResults=10&key=' + Config.google_api).
        success(function (response) {
            var entries = [], i, j;
            for (i = 0; i < response.items.length; i++) {
                var item = response.items[i];
                var actor = item.actor || {};
                var object = item.object || {};
                // Normalize tweet to a FriendFeed-like entry.
                // var itemTitle = '' + item.title + '';
                var itemTitle = object.content;

                if(item.annotation)
                  itemTitle = item.annotation;

                var html = [itemTitle.replace(new RegExp('\n', 'g'), '
').replace('

', '
')];
                //html.push(' Read More »');

                var thumbnails = [];

                var attachments = object.attachments || [];
                for (j = 0; j < attachments.length; j++) {
                    var attachment = attachments[j];
                    switch (attachment.objectType) {
                        case 'album':
                            break;// TODO needs more work
                            var upper = attachment.thumbnails.length > 7 ? 7 : attachment.thumbnails.length;
                            html.push('
');
                            for (var k = 1; k < upper; k++) {
                                html.push('

');
                            }
                            html.push('
');
                            break;
                        case 'photo':
                            thumbnails.push({
                                url: attachment.image.url,
                                link: attachment.fullImage.url
                            });
                            break;

                        case 'video':
                            thumbnails.push({
                                url: attachment.image.url,
                                link: attachment.url
                            });
                            break;

                        case 'article': case 'event':
                            html.push('
' + attachment.displayName + '');
                            if (attachment.content) {
                                html.push('
' + attachment.content + '');
                            }
                            html.push('
');
                            break;
                        /* case 'event':
                            console.log(attachment);
                            html.push('
' + attachment.displayName + '');
                            html.push('
' + attachment.content.replace(new RegExp('\n', 'g'), '
') + '
');
                            break; */
                        default :
                            console.log(attachment.objectType);
                    }
                }

                html = html.join('');

                var actorImage = actor.image.url;
                actorImage = actorImage.substr(0, actorImage.length - 2) + '16';
                // The replace in the item URL is a dirty quick fix for issue #20 which seems to be a g+ api bug
                var entry = {
                    via: {
                        name: 'Google+',
                        url: item.url.replace('https://plus.google.com/https://plus.google.com', 'https://plus.google.com')
                    },
                    body: html,
                    date: item.updated,
                    reshares: (object.resharers || {}).totalItems,
                    plusones: (object.plusoners || {}).totalItems,
                    comments: (object.replies || {}).totalItems,
                    thumbnails: thumbnails,
                    icon: actorImage
                };

                entries.push(entry);
            }
            $scope.news = entries;
            $timeout(function () {
                gapi.plusone.go();
            });
            $scope.loading = false;
        });

});

boomerang.controller("EventsControl", function ($scope, $http, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "events";

    $scope.events = {past: [], future: []};
    $http.get("http://gdgfresno.com/gdgfeed.php?id=" + Config.id).
        success(function (data) {
            var now = new Date();
            for (var i = data.length - 1; i >= 0; i--) {
                var start = new Date(data[i].start);

                data[i].start = start;
                data[i].end = new Date(data[i].end);

                if (start < now) {
                    $scope.events.past.push(data[i]);
                } else {
                    $scope.events.future.push(data[i]);
                }
            }
            $scope.loading = false;
        });

});

boomerang.controller("PhotosControl", function ($scope, $http, Config) {
    $scope.loading = true;
    $scope.$parent.activeTab = "photos";
    $scope.photos = [];

    var pwa = 'https://picasaweb.google.com/data/feed/api/user/' + Config.id + '/albumid/' + Config.pwa_id +
        '?access=public&alt=json-in-script&kind=photo&max-results=20&fields=entry(title,link/@href,summary,content/@src)&v=2.0&callback=JSON_CALLBACK';

    $http.jsonp(pwa).
        success(function (d) {
            var p = d.feed.entry;
            for (var x in p) {
                var photo = {
                    link: p[x].link[1].href,
                    src: p[x].content.src,
                    alt: p[x].title.$t,
                    title: p[x].summary.$t
                };
                $scope.photos.push(photo);
            }
            $scope.loading = false;
        });
});

// HTML-ified linky from http://plnkr.co/edit/IEpLfZ8gO2B9mJcTKuWY?p=preview
boomerang.filter('htmlLinky', function($sanitize, linkyFilter) {
    var ELEMENT_NODE = 1;
    var TEXT_NODE = 3;
    var linkifiedDOM = document.createElement('div');
    var inputDOM = document.createElement('div');

    var linkify = function linkify(startNode) {
        var i, currentNode;

        for (i = 0; i < startNode.childNodes.length; i++) {
            currentNode = startNode.childNodes[i];

            switch (currentNode.nodeType) {
                case ELEMENT_NODE:
                    linkify(currentNode);
                    break;
                case TEXT_NODE:
                    linkifiedDOM.innerHTML = linkyFilter(currentNode.textContent);
                    i += linkifiedDOM.childNodes.length - 1;

                    while(linkifiedDOM.childNodes.length)
                        startNode.insertBefore(linkifiedDOM.childNodes[0], currentNode);

                    startNode.removeChild(currentNode);
            }
        }

        return startNode;
    };

    return function(input) {
        inputDOM.innerHTML = input;
        return linkify(inputDOM).innerHTML;
    };
});

boomerang.filter('hashLinky', function($sanitize, linkyFilter) {
    var ELEMENT_NODE = 1;
    var TEXT_NODE = 3;
    var linkifiedDOM = document.createElement('div');
    var inputDOM = document.createElement('div');

    var hashLinky = function hashLinky(startNode) {
        var i, currentNode;

        for (i = 0; i < startNode.childNodes.length; i++) {
            currentNode = startNode.childNodes[i];

            switch (currentNode.nodeType) {
                case ELEMENT_NODE:
                    hashLinky(currentNode);
                    break;
                case TEXT_NODE:
                    var hashtagRegex = /#([A-Za-z0-9-_]+)/g;
                    currentNode.textContent =  currentNode.textContent.replace(hashtagRegex,
                        '#$1');

                    linkifiedDOM.innerHTML = currentNode.textContent;
                    i += linkifiedDOM.childNodes.length - 1;

                    while(linkifiedDOM.childNodes.length) {
                        startNode.insertBefore(linkifiedDOM.childNodes[0], currentNode);
                    }
                    startNode.removeChild(currentNode);
            }
        }

        return startNode;
    };

    return function(input) {
        inputDOM.innerHTML = input;
        return hashLinky(inputDOM).innerHTML;
    };
});
<|endoftext|>


<commit_before>var Backbone = require('backbone');
var TorqueHeaderView = require('../../../src/widgets/time-series/torque-header-view');

describe('widgets/time-series/torque-header-view', function () {
  var filterIsEmpty = true;
  var timeSeriesModel = new Backbone.Model({
    title: 'Morty'
  });

  beforeEach(function () {
    this.dataviewModel = new Backbone.Model({
      data: [{}]
    });
    this.dataviewModel.layer = new Backbone.Model();
    this.dataviewModel.filter = new Backbone.Model();
    this.dataviewModel.filter.isEmpty = function () {
      return filterIsEmpty;
    };
    this.torqueLayerModel = new Backbone.Model();
    this.view = new TorqueHeaderView({
      dataviewModel: this.dataviewModel,
      torqueLayerModel: this.torqueLayerModel,
      timeSeriesModel: timeSeriesModel,
      selectedAmount: 0
    });
  });

  afterEach(function () {
    filterIsEmpty = true;
  });

  describe('.render', function () {
    it('should render the proper template', function () {
      this.view.render();

      expect(this.view.$('.js-torque-controls').length).toBe(1);
      expect(this.view.$('.js-time-series-header').length).toBe(1);
    });

    it('should render and update the title', function () {
      this.view.render();

      expect(this.view.$('.js-widget-title').text()).toBe('Morty');

      timeSeriesModel.set('title', 'Rick');

      expect(this.view.$('.js-widget-title').text()).toBe('Rick');
    });

    it('should render torque controls and hide clear button if filter is empty', function () {
      this.view.render();

      // Torque controls rendered
      expect(this.view.$('.CDB-Widget-controlButtonContent').length).toBe(1);
      // Torque time info rendered
      expect(this.view.$('.CDB-Widget-timeSeriesTimeInfo').length).toBe(1);
      // Header clear button not present
      expect(this.view.$('.js-clear').length).toBe(0);
    });

    it('should not render torque controls and show clear button if filter has value', function () {
      filterIsEmpty = false;
      this.dataviewModel.filter.set({ min: 1, max: 2 });

      this.view.render();

      // Torque controls not rendered
      expect(this.view.$('.CDB-Widget-controlButtonContent').length).toBe(0);
      // Torque time info not rendered
      expect(this.view.$('.CDB-Widget-timeSeriesTimeInfo').length).toBe(0);
      // Header clear button present
      expect(this.view.$('.js-clear').length).toBe(1);
    });
  });
});
<commit_msg>fix tests to account for widget title<commit_after>var Backbone = require('backbone');
var TorqueHeaderView = require('../../../src/widgets/time-series/torque-header-view');

describe('widgets/time-series/torque-header-view', function () {
  var filterIsEmpty = true;
  var timeSeriesModel = new Backbone.Model({
    title: 'Morty'
  });

  beforeEach(function () {
    this.dataviewModel = new Backbone.Model({
      data: [{}]
    });
    this.dataviewModel.layer = new Backbone.Model();
    this.dataviewModel.filter = new Backbone.Model();
    this.dataviewModel.filter.isEmpty = function () {
      return filterIsEmpty;
    };
    this.torqueLayerModel = new Backbone.Model();
    this.view = new TorqueHeaderView({
      dataviewModel: this.dataviewModel,
      torqueLayerModel: this.torqueLayerModel,
      timeSeriesModel: timeSeriesModel,
      selectedAmount: 0
    });
  });

  afterEach(function () {
    filterIsEmpty = true;
  });

  describe('.render', function () {
    it('should render the proper template', function () {
      this.view.render();

      expect(this.view.$('.js-torque-controls').length).toBe(1);
      expect(this.view.$('.js-time-series-header').length).toBe(1);
    });

    it('should render and update the title', function () {
      this.view.render();

      expect(this.view.$('.js-widget-title').text()).toBe('Morty');

      timeSeriesModel.set('title', 'Rick');

      expect(this.view.$('.js-widget-title').text()).toBe('Rick');
    });

    it('should render torque controls and hide clear button if filter is empty', function () {
      this.view.render();

      // Torque controls rendered
      expect(this.view.$('.CDB-Widget-controlButtonContent').length).toBe(1);
      // Torque time info rendered
      expect(this.view.$('.CDB-Widget-timeSeriesTimeInfo').length).toBe(2);
      // Header clear button not present
      expect(this.view.$('.js-clear').length).toBe(0);
    });

    it('should not render torque controls and show clear button if filter has value', function () {
      filterIsEmpty = false;
      this.dataviewModel.filter.set({ min: 1, max: 2 });

      this.view.render();

      // Torque controls not rendered
      expect(this.view.$('.CDB-Widget-controlButtonContent').length).toBe(0);
      // Torque time info not rendered
      expect(this.view.$('.CDB-Widget-timeSeriesTimeInfo').length).toBe(1);
      // Header clear button present
      expect(this.view.$('.js-clear').length).toBe(1);
    });
  });
});
<|endoftext|>