<commit_before>/**
 * @file:   Resolver class capable of identifying nodes in a given tree by
 *          pattern matching.
 *
 * @see:    * Sebastian Rönnau, Christian Pauli, and Uwe M. Borghoff. Merging
 *            changes in XML documents using reliable context fingerprints:
 *            http://dx.doi.org/10.1145/1410140.1410151
 *          * Original Sourcecode:
 *            https://launchpad.net/xcc
 *
 * @module  delta
 */

/** @ignore */
var tree = require('./tree.js');

/**
 * @constant
 */
var UPDATE_NODE_TYPE = 1;

/**
 * @constant
 */
var UPDATE_FOREST_TYPE = 2;

/**
 * Create new patch instance.
 *
 * @constructor
 */
function Delta() {
    this.operations = [];
    this.handlers = [];
}

/**
 * Apply the delta to a tree using the specified resolver to identify the
 * locations and the handler factory to instantiate operation handlers.
 *
 * @param resolver  A resolver capable of mapping paths to tree nodes.
 * @param handlerfactory Factory class for operations.
 */
Delta.prototype.attach = function(resolver, handlerfactory) {
    var fails = 0, i, start, op, nodes, depth, handler;

    for (i = 0; i < this.operations.length; i++) {
        op = this.operations[i];

        // Resolve anchor node
        nodes = resolver.find(op.path, op.oldvalue, op.head, op.tail);

        // Check if we can accept the resolved location depending on the
        // operation type
        depth = op.path.length;

        if (!nodes) {
            // Resolving failed completely
            fails++;
        }
        else if (op.oldvalue.length && !nodes[depth]) {
            // If an old value is supplied (node-update, subtree-remove), the
            // path must be complete.
            fails++;
        }
        else if (op.type === UPDATE_FOREST_TYPE && !nodes[depth - 1]) {
            // Operations on forests require the parent node
            fails++;
        }
        else {
            handler = undefined;
            switch (op.type) {
                case UPDATE_FOREST_TYPE:
                    // Operation should start at the node index of the resolved
                    // node or after the last node.
                    start = nodes[depth] ? nodes[depth].childidx :
                        nodes[depth - 1].children.length;
                    // If we have nothing to remove, start should point after
                    // the resolved node.
                    if (!op.oldvalue.length) {
                        start++;
                    }

                    handler = handlerfactory.createForestUpdateOperationHandler(
                            nodes[depth - 1], start, op.oldvalue.length,
                            op.newvalue);
                    break;

                case UPDATE_NODE_TYPE:
                    handler = handlerfactory.createNodeUpdateOperationHandler(
                            nodes[depth], op.newvalue[0]);
                    break;
            }

            this.handlers[i] = handler;
        }
    }

    return fails;
};

/**
 * Private utility class: Creates a new ParameterBuffer instance.
 *
 * @constructor
 */
function ParameterBuffer(callback, T) {
    this.callback = callback;
    this.T = T;
    this.removes = [];
    this.inserts = [];
}

/**
 * Append an item to the end of the buffer
 */
ParameterBuffer.prototype.pushRemove = function(item) {
    this.removes.push(item);
};

/**
 * Append an item to the end of the buffer
 */
ParameterBuffer.prototype.pushInsert = function(item) {
    this.inserts.push(item);
};

/**
 * Invoke callback with the contents of the buffer array and empty the
 * buffer afterwards.
 */
ParameterBuffer.prototype.flush = function() {
    if (this.removes.length > 0 || this.inserts.length > 0) {
        this.callback.call(this.T, this.removes, this.inserts);
        this.removes = [];
        this.inserts = [];
    }
};

/**
 * Collect changeset on given node and all its descendants. Construct and
 * add operations for each.
 *
 * @param node      The node where to start. Typically the root of tree a
 * @param matching  The node matching built up using matchTrees
 * @param contextgen The context generator
 * @param updater   A function(node, callback, T) calling callback if an
 *                  update operation should be performed on node.
 * @param path      (internal use) current path relative to base node. Used
 *                  from recursive calls.
 */
Delta.prototype.collect = function(node, matching, contextgen, updater, path) {
    var parambuf, i, k, l, a_nodes, b_nodes, a, b, anchor;

    // Initialize path if not provided
    path = path || [];

    if (!matching.get(node)) {
        throw new Error('Delta.collect may not be invoked for unmatched nodes');
    }

    // Generate update command if values of node and its partner do not
    // match
    if (updater) {
        updater(node, function(a, b) {
            var head = contextgen.head(a);
            var tail = contextgen.tail(a, true);
            var op = new exports.Operation(UPDATE_NODE_TYPE, path.slice(),
                head, tail, [a], [b]);
            this.add(op);
        }, this);
    }

    // Operation aggregator for inserts
    parambuf = new ParameterBuffer(function(removes, inserts) {
        var head = contextgen.head(anchor);
        var tail = contextgen.tail(removes.length ? removes[removes.length-1] : anchor);
        var op = new exports.Operation(UPDATE_FOREST_TYPE, path.slice(), head, tail,
            removes, inserts);
        this.add(op);
    }, this);

    // Descend one level
    path.push(0);
    anchor = node;
    a_nodes = node.children;
    b_nodes = matching.get(node).children;
    i = 0; k = 0; l = 0;
    while (a_nodes[i] || b_nodes[k]) {
        a = a_nodes[i];
        b = b_nodes[k];

        if (a && !matching.get(a)) {
            parambuf.pushRemove(a);
            i++;
            l++;
        }
        else if (b && !matching.get(b)) {
            parambuf.pushInsert(b);
            k++;
        }
        else if (a && b && a === matching.get(b)) {
            path[path.length-1] = i - l;

            // Flush item aggregators
            parambuf.flush();

            // Recurse
            anchor = this.collect(a, matching, contextgen, updater, path);

            l=0;
            i++;
            k++;
        }
        else {
            throw new Error('Matching is not consistent.');
        }
    }

    path[path.length-1] = i - l;
    parambuf.flush();

    // Go back up
    path.pop();

    return anchor;
};

/**
 * Add an operation to the delta. Optionally also provide a handler.
 *
 * @param operation An operation
 * @param handler   (optional) The corresponding operation handler.
 */
Delta.prototype.add = function(operation, handler) {
    this.operations.push(operation);
    this.handlers.push(handler);
};

/**
 * Execute the callbac for each operation and its corresponding handler in
 * the delta.
 */
Delta.prototype.forEach = function(callback, T) {
    var i;

    for (i = 0; i < this.operations.length; i++) {
        callback.call(T, this.operations[i], this.handlers[i]);
    }
};

/**
 * Construct a new operation instance.
 *
 * @constructor
 */
function Operation(type, path, head, tail, oldvalue, newvalue) {
    /**
     * The operation type, one of UPDATE_NODE_TYPE, UPDATE_FOREST_TYPE
     */
    this.type = type;

    /**
     * An array of integers representing the top-down path from the root
     * node to the anchor of this operation. The anchor point always is
     * the first position after the leading context values. For insert
     * operations it will must point to the first element of the tail
     * context.
     */
    this.path = path;

    /**
     * Fingerprint values for the content. For insert operations, this
     * array should be empty. For remove-operations, the array should
     * contain the fingerprint values of the nodes which should be removed,
     * for update operations, the only element should be the fingerprint
     * value of the original node.
     */
    this.head = head;
    this.tail = tail;

    /**
     * Null (insert), one tree.Node (update) or sequence of nodes (delete)
     */
    this.oldvalue = oldvalue;

    /**
     * Null (remove), one tree.Node (update) or sequence of nodes (insert)
     */
    this.newvalue = newvalue;
}

/**
 * Constructor for a simple context generator with the given radius. Node
 * locations are resolved using nodeindex (typically an instance of
 * tree.DocumentOrderIndex) and values are mapped using the valindex.
 * @constructor
 */
function ContextGenerator(radius, nodeindex, valindex) {
    /**
     * Return the values for the head context, that is n nodes preceeding the
     * given node.
     */
    this.head = function(before) {
        var i, result = [];
        for (i = -radius; i < 0; i++) {
            result.push(valindex.get(nodeindex.get(before, i)));
        }
        return result;
    };

    /**
     * Return the values for the tail context starting with the given node.
     */
    this.tail = function(after, flatbody) {
        var i, result = [];
        if (flatbody) {
            after = after && nodeindex.get(after, 1);
        }
        else {
            after = after && nodeindex.skip(after);
        }
        for (i = 0; i < radius; i++) {
            result.push(valindex.get(after && nodeindex.get(after, i)));
        }
        return result;
    };
}

/**
 * Returns a new updater function suitable for Delta.collect based on the
 * given matching and equality callback.
 */
function defaultMatchingUpdater(matching, equals, Teq) {
    equals = equals || function(a, b) {
        return a.value === b.value;
    };

    return function(node, update, Tup) {
        var partner = matching.get(node);
        if (!equals.call(Teq, node, partner)) {
            update.call(Tup, node, partner);
        }
    };
}

exports.Delta = Delta;
exports.Operation = Operation;
exports.ContextGenerator = ContextGenerator;
exports.defaultMatchingUpdater = defaultMatchingUpdater;

exports.UPDATE_NODE_TYPE = UPDATE_NODE_TYPE;
exports.UPDATE_FOREST_TYPE = UPDATE_FOREST_TYPE;
<commit_msg>Add parameter to resolver.find in order to pass in operation type, call content/context callbacks with this flag as a parameter<commit_after>/**
 * @file:   Resolver class capable of identifying nodes in a given tree by
 *          pattern matching.
 *
 * @see:    * Sebastian Rönnau, Christian Pauli, and Uwe M. Borghoff. Merging
 *            changes in XML documents using reliable context fingerprints:
 *            http://dx.doi.org/10.1145/1410140.1410151
 *          * Original Sourcecode:
 *            https://launchpad.net/xcc
 *
 * @module  delta
 */

/** @ignore */
var tree = require('./tree.js');

/**
 * @constant
 */
var UPDATE_NODE_TYPE = 1;

/**
 * @constant
 */
var UPDATE_FOREST_TYPE = 2;

/**
 * Create new patch instance.
 *
 * @constructor
 */
function Delta() {
    this.operations = [];
    this.handlers = [];
}

/**
 * Apply the delta to a tree using the specified resolver to identify the
 * locations and the handler factory to instantiate operation handlers.
 *
 * @param resolver  A resolver capable of mapping paths to tree nodes.
 * @param handlerfactory Factory class for operations.
 */
Delta.prototype.attach = function(resolver, handlerfactory) {
    var fails = 0, i, start, op, nodes, depth, handler;

    for (i = 0; i < this.operations.length; i++) {
        op = this.operations[i];

        // Resolve anchor node
        nodes = resolver.find(op.path, op.oldvalue, op.head, op.tail, op.type);

        // Check if we can accept the resolved location depending on the
        // operation type
        depth = op.path.length;

        if (!nodes) {
            // Resolving failed completely
            fails++;
        }
        else if (op.oldvalue.length && !nodes[depth]) {
            // If an old value is supplied (node-update, subtree-remove), the
            // path must be complete.
            fails++;
        }
        else if (op.type === UPDATE_FOREST_TYPE && !nodes[depth - 1]) {
            // Operations on forests require the parent node
            fails++;
        }
        else {
            handler = undefined;
            switch (op.type) {
                case UPDATE_FOREST_TYPE:
                    // Operation should start at the node index of the resolved
                    // node or after the last node.
                    start = nodes[depth] ? nodes[depth].childidx :
                        nodes[depth - 1].children.length;
                    // If we have nothing to remove, start should point after
                    // the resolved node.
                    if (!op.oldvalue.length) {
                        start++;
                    }

                    handler = handlerfactory.createForestUpdateOperationHandler(
                            nodes[depth - 1], start, op.oldvalue.length,
                            op.newvalue);
                    break;

                case UPDATE_NODE_TYPE:
                    handler = handlerfactory.createNodeUpdateOperationHandler(
                            nodes[depth], op.newvalue[0]);
                    break;
            }

            this.handlers[i] = handler;
        }
    }

    return fails;
};

/**
 * Private utility class: Creates a new ParameterBuffer instance.
 *
 * @constructor
 */
function ParameterBuffer(callback, T) {
    this.callback = callback;
    this.T = T;
    this.removes = [];
    this.inserts = [];
}

/**
 * Append an item to the end of the buffer
 */
ParameterBuffer.prototype.pushRemove = function(item) {
    this.removes.push(item);
};

/**
 * Append an item to the end of the buffer
 */
ParameterBuffer.prototype.pushInsert = function(item) {
    this.inserts.push(item);
};

/**
 * Invoke callback with the contents of the buffer array and empty the
 * buffer afterwards.
 */
ParameterBuffer.prototype.flush = function() {
    if (this.removes.length > 0 || this.inserts.length > 0) {
        this.callback.call(this.T, this.removes, this.inserts);
        this.removes = [];
        this.inserts = [];
    }
};

/**
 * Collect changeset on given node and all its descendants. Construct and
 * add operations for each.
 *
 * @param node      The node where to start. Typically the root of tree a
 * @param matching  The node matching built up using matchTrees
 * @param contextgen The context generator
 * @param updater   A function(node, callback, T) calling callback if an
 *                  update operation should be performed on node.
 * @param path      (internal use) current path relative to base node. Used
 *                  from recursive calls.
 */
Delta.prototype.collect = function(node, matching, contextgen, updater, path) {
    var parambuf, i, k, l, a_nodes, b_nodes, a, b, anchor;

    // Initialize path if not provided
    path = path || [];

    if (!matching.get(node)) {
        throw new Error('Delta.collect may not be invoked for unmatched nodes');
    }

    // Generate update command if values of node and its partner do not
    // match
    if (updater) {
        updater(node, function(a, b) {
            var head = contextgen.head(a);
            var tail = contextgen.tail(a, true);
            var op = new exports.Operation(UPDATE_NODE_TYPE, path.slice(),
                head, tail, [a], [b]);
            this.add(op);
        }, this);
    }

    // Operation aggregator for inserts
    parambuf = new ParameterBuffer(function(removes, inserts) {
        var head = contextgen.head(anchor);
        var tail = contextgen.tail(removes.length ? removes[removes.length-1] : anchor);
        var op = new exports.Operation(UPDATE_FOREST_TYPE, path.slice(), head, tail,
            removes, inserts);
        this.add(op);
    }, this);

    // Descend one level
    path.push(0);
    anchor = node;
    a_nodes = node.children;
    b_nodes = matching.get(node).children;
    i = 0; k = 0; l = 0;
    while (a_nodes[i] || b_nodes[k]) {
        a = a_nodes[i];
        b = b_nodes[k];

        if (a && !matching.get(a)) {
            parambuf.pushRemove(a);
            i++;
            l++;
        }
        else if (b && !matching.get(b)) {
            parambuf.pushInsert(b);
            k++;
        }
        else if (a && b && a === matching.get(b)) {
            path[path.length-1] = i - l;

            // Flush item aggregators
            parambuf.flush();

            // Recurse
            anchor = this.collect(a, matching, contextgen, updater, path);

            l=0;
            i++;
            k++;
        }
        else {
            throw new Error('Matching is not consistent.');
        }
    }

    path[path.length-1] = i - l;
    parambuf.flush();

    // Go back up
    path.pop();

    return anchor;
};

/**
 * Add an operation to the delta. Optionally also provide a handler.
 *
 * @param operation An operation
 * @param handler   (optional) The corresponding operation handler.
 */
Delta.prototype.add = function(operation, handler) {
    this.operations.push(operation);
    this.handlers.push(handler);
};

/**
 * Execute the callbac for each operation and its corresponding handler in
 * the delta.
 */
Delta.prototype.forEach = function(callback, T) {
    var i;

    for (i = 0; i < this.operations.length; i++) {
        callback.call(T, this.operations[i], this.handlers[i]);
    }
};

/**
 * Construct a new operation instance.
 *
 * @constructor
 */
function Operation(type, path, head, tail, oldvalue, newvalue) {
    /**
     * The operation type, one of UPDATE_NODE_TYPE, UPDATE_FOREST_TYPE
     */
    this.type = type;

    /**
     * An array of integers representing the top-down path from the root
     * node to the anchor of this operation. The anchor point always is
     * the first position after the leading context values. For insert
     * operations it will must point to the first element of the tail
     * context.
     */
    this.path = path;

    /**
     * Fingerprint values for the content. For insert operations, this
     * array should be empty. For remove-operations, the array should
     * contain the fingerprint values of the nodes which should be removed,
     * for update operations, the only element should be the fingerprint
     * value of the original node.
     */
    this.head = head;
    this.tail = tail;

    /**
     * Null (insert), one tree.Node (update) or sequence of nodes (delete)
     */
    this.oldvalue = oldvalue;

    /**
     * Null (remove), one tree.Node (update) or sequence of nodes (insert)
     */
    this.newvalue = newvalue;
}

/**
 * Constructor for a simple context generator with the given radius. Node
 * locations are resolved using nodeindex (typically an instance of
 * tree.DocumentOrderIndex) and values are mapped using the valindex.
 * @constructor
 */
function ContextGenerator(radius, nodeindex, valindex) {
    /**
     * Return the values for the head context, that is n nodes preceeding the
     * given node.
     */
    this.head = function(before) {
        var i, result = [];
        for (i = -radius; i < 0; i++) {
            result.push(valindex.get(nodeindex.get(before, i)));
        }
        return result;
    };

    /**
     * Return the values for the tail context starting with the given node.
     */
    this.tail = function(after, flatbody) {
        var i, result = [];
        if (flatbody) {
            after = after && nodeindex.get(after, 1);
        }
        else {
            after = after && nodeindex.skip(after);
        }
        for (i = 0; i < radius; i++) {
            result.push(valindex.get(after && nodeindex.get(after, i)));
        }
        return result;
    };
}

/**
 * Returns a new updater function suitable for Delta.collect based on the
 * given matching and equality callback.
 */
function defaultMatchingUpdater(matching, equals, Teq) {
    equals = equals || function(a, b) {
        return a.value === b.value;
    };

    return function(node, update, Tup) {
        var partner = matching.get(node);
        if (!equals.call(Teq, node, partner)) {
            update.call(Tup, node, partner);
        }
    };
}

exports.Delta = Delta;
exports.Operation = Operation;
exports.ContextGenerator = ContextGenerator;
exports.defaultMatchingUpdater = defaultMatchingUpdater;

exports.UPDATE_NODE_TYPE = UPDATE_NODE_TYPE;
exports.UPDATE_FOREST_TYPE = UPDATE_FOREST_TYPE;
<|endoftext|>


<commit_before>const MongoClient = require('mongodb').MongoClient;
const roomMap = {
  'C0D2Z96AG': 'hubot-testing',
  'C03AFTJHG': 'general',
  'C4YTEUTJ6': 'generaltsos',
  'CCE6AE5GE': 'investing',
  'CEFH3HW1M': 'whatsplaying'
};

module.exports = function (robot) {

  MongoClient.connect(process.env.MONGODB_URL, {
      useNewUrlParser: true
    },
    function (err, client) {
      if (err) {
        robot.logger.error('MongoStats was unable to connect to slack_messages connection!');
        robot.logger.error(err);
      }

      robot.logger.debug('MongoStats - Successfully authenticated with mongo');

      let db = client.db(process.env.MONGODB_DBNAME);
      let collection = db.collection('slack_messages');

      robot.respond(/give us the stats/, function (msg) {
        var content = {};

        let endTime = new Date();
        endTime.setUTCHours(0, 0, 0);
        let startTime = new Date(endTime - (7 * 24 * 60 * 60 * 1000));
        content.start = startTime.toDateString();
        content.end = endTime.toDateString();
        let timestampQuery = {
          $gte: startTime.getTime(),
          $lte: endTime.getTime()
        };

        getMessageCount(collection, timestampQuery, function (error, result) {
          content.messageCount = result || -1;
          respondWithContent(msg, content);
        });

        getRoomsAggregate(collection, timestampQuery, function (error, result) {
          content.roomCounts = result || [];
          respondWithContent(msg, content);
        });

        getUsersAggregate(collection, timestampQuery, function (error, result) {
          content.userCounts = result || [];
          respondWithContent(msg, content);
        });

      });
    });
};

function getUsersAggregate(collection, timestampQuery, callback) {
  let userPipeline = [{ $match: { timestamp: timestampQuery } },
    { $group: { _id: "$user", count: { $sum: 1 } } }];
  collection.aggregate(userPipeline).toArray(callback);
}

function getRoomsAggregate(collection, timestampQuery, callback) {
  let roomPipeline = [{ $match: { timestamp: timestampQuery } },
    { $group: { _id: "$room", count: { $sum: 1 } } }];
  collection.aggregate(roomPipeline).toArray(callback);
}

function getMessageCount(collection, timestampQuery, callback) {
  let query = {
    timestamp: timestampQuery
  };
  collection.countDocuments(query, {}, callback);
}

function respondWithContent(robot, content) {
  if (robot && content && content.start &&
    content.end && content.messageCount &&
    content.roomCounts && content.userCounts) {
    robot.send('*Last Week Messages Statistics*');
    robot.send(`*Timeframe:* _${content.start} - ${content.end}_`);
    robot.send(`*Total Message Count:* _${content.messageCount}_`);
    robot.send(`*Stats by User:*`);
    content.userCounts.sort(compareAggregateResults).forEach(function(user, index) {
      robot.send(`_${index+1}. ${user._id}: ${user.count} ${optionalMedal(index)}_`);
    });
    robot.send(`*Stats by Room:*`);
    content.roomCounts.sort(compareAggregateResults).forEach(function(room, index) {
      robot.send(`_${index+1}. ${room._id}: ${room.count} ${optionalMedal(index)}_`);
    });
  }
}

function compareAggregateResults(a, b) {
  return b.count - a.count;
}

function optionalMedal(index) {
  if (index === 0) {
    return ':gold:';
  } else if (index === 1) {
    return ':silver:';
  } else if (index === 2) {
    return ':bronze:';
  } else {
    return '';
  }
}<commit_msg>Add case insensitivity, single response array.<commit_after>const MongoClient = require('mongodb').MongoClient;
const roomMap = {
  'C0D2Z96AG': 'hubot-testing',
  'C03AFTJHG': 'general',
  'C4YTEUTJ6': 'generaltsos',
  'CCE6AE5GE': 'investing',
  'CEFH3HW1M': 'whatsplaying'
};

module.exports = function (robot) {

  MongoClient.connect(process.env.MONGODB_URL, {
      useNewUrlParser: true
    },
    function (err, client) {
      if (err) {
        robot.logger.error('MongoStats was unable to connect to slack_messages connection!');
        robot.logger.error(err);
      }

      robot.logger.debug('MongoStats - Successfully authenticated with mongo');

      let db = client.db(process.env.MONGODB_DBNAME);
      let collection = db.collection('slack_messages');

      robot.respond(/give us the stats/i, function (msg) {
        var content = {};

        let endTime = new Date();
        endTime.setUTCHours(0, 0, 0);
        let startTime = new Date(endTime - (7 * 24 * 60 * 60 * 1000));
        content.start = startTime.toDateString();
        content.end = endTime.toDateString();
        let timestampQuery = {
          $gte: startTime.getTime(),
          $lte: endTime.getTime()
        };

        getMessageCount(collection, timestampQuery, function (error, result) {
          content.messageCount = result || -1;
          respondWithContent(msg, content);
        });

        getRoomsAggregate(collection, timestampQuery, function (error, result) {
          content.roomCounts = result || [];
          respondWithContent(msg, content);
        });

        getUsersAggregate(collection, timestampQuery, function (error, result) {
          content.userCounts = result || [];
          respondWithContent(msg, content);
        });

      });
    });
};

function getUsersAggregate(collection, timestampQuery, callback) {
  let userPipeline = [{ $match: { timestamp: timestampQuery } },
    { $group: { _id: "$user", count: { $sum: 1 } } }];
  collection.aggregate(userPipeline).toArray(callback);
}

function getRoomsAggregate(collection, timestampQuery, callback) {
  let roomPipeline = [{ $match: { timestamp: timestampQuery } },
    { $group: { _id: "$room", count: { $sum: 1 } } }];
  collection.aggregate(roomPipeline).toArray(callback);
}

function getMessageCount(collection, timestampQuery, callback) {
  let query = {
    timestamp: timestampQuery
  };
  collection.countDocuments(query, {}, callback);
}

function respondWithContent(robot, content) {
  if (robot && content && content.start &&
    content.end && content.messageCount &&
    content.roomCounts && content.userCounts) {
    var response = [];
    response.push('*Last Week Messages Statistics*');
    response.push(`*Timeframe:* _${content.start} - ${content.end}_`);
    response.push(`*Total Message Count:* _${content.messageCount}_`);
    response.push(`*Stats by User:*`);
    content.userCounts.sort(compareAggregateResults).forEach(function(user, index) {
      response.push(`_${index+1}. ${user._id}: ${user.count} ${optionalMedal(index)}_`);
    });
    response.push(`*Stats by Room:*`);
    content.roomCounts.sort(compareAggregateResults).forEach(function(room, index) {
      response.push(`_${index+1}. ${room._id}: ${room.count} ${optionalMedal(index)}_`);
    });
    robot.send(response.join('\n'));
  }
}

function compareAggregateResults(a, b) {
  return b.count - a.count;
}

function optionalMedal(index) {
  if (index === 0) {
    return ':gold:';
  } else if (index === 1) {
    return ':silver:';
  } else if (index === 2) {
    return ':bronze:';
  } else {
    return '';
  }
}<|endoftext|>


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

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

/**
 * PreferencesManager
 *
 */
define(function (require, exports, module) {
    "use strict";

    var PreferenceStorage = require("preferences/PreferenceStorage").PreferenceStorage,
        FileUtils         = require("file/FileUtils"),
        ExtensionLoader   = require("utils/ExtensionLoader"),
        CollectionUtils   = require("utils/CollectionUtils");

    /**
     * The local storage ID
     * @const
     * @type {string}
     */
    var PREFERENCES_CLIENT_ID = "com.adobe.brackets.preferences";

    /**
     * The prefix used in the generated client ID
     * @const
     * @type {string}
     */
    var CLIENT_ID_PREFIX = "com.adobe.brackets.";

    // Private Properties
    var preferencesKey,
        prefStorage,
        persistentStorage,
        doLoadPreferences   = false;

    /**
     * This method returns a standardized ClientID for a given requireJS module object
     * @param {!{id: string, uri: string}} module - A requireJS module object
     * @return {string} The ClientID
     */
    function getClientID(module) {
        var paths = [
            FileUtils.getNativeBracketsDirectoryPath() + "/extensions/default",
            FileUtils.getNativeBracketsDirectoryPath() + "/extensions/dev",
            ExtensionLoader.getUserExtensionPath()
        ],
            pathExp, pathUrl, clientID;

        paths.some(function (path) {
            pathExp = new RegExp("^" + path);
            if (module.uri.match(pathExp)) {
                pathUrl = path;
                return true;
            }
        });

        if (pathUrl) {
            clientID = CLIENT_ID_PREFIX + module.uri.replace(pathUrl + "/", "");
        } else {
            clientID = CLIENT_ID_PREFIX + module.id;
        }
        return clientID;
    }

    /**
     * Retreive the preferences data for the given clientID.
     * @param {string|{id: string, uri: string}} clientID - A unique identifier or a requireJS module object
     * @param {string} defaults - Default preferences stored as JSON
     * @return {PreferenceStorage}
     */
    function getPreferenceStorage(clientID, defaults) {
        if (clientID === undefined || clientID === null ||
                (typeof clientID === "string" && clientID === "") ||
                (typeof clientID === "object" && (!clientID.id || !clientID.uri))) {
            console.error("Invalid clientID");
            return;
        }
        if (typeof (clientID) === "object") {
            clientID = getClientID(clientID);
        }

        var prefs = prefStorage[clientID];

        if (prefs === undefined) {
            // create a new empty preferences object
            prefs = (defaults && JSON.stringify(defaults)) ? defaults : {};
            prefStorage[clientID] = prefs;
        } else if (defaults) {
            // add new defaults
            CollectionUtils.forEach(defaults, function (value, key) {
                if (prefs[key] === undefined) {
                    prefs[key] = value;
                }
            });
        }

        return new PreferenceStorage(clientID, prefs);
    }

    /**
     * Save all preference clients.
     */
    function savePreferences() {
        // save all preferences
        persistentStorage.setItem(preferencesKey, JSON.stringify(prefStorage));
    }

    /**
     * @private
     * Reset preferences and callbacks
     */
    function _reset() {
        prefStorage = {};

        // Note that storage.clear() is not used. Production and unit test code
        // both rely on the same backing storage but unique item keys.
        persistentStorage.setItem(preferencesKey, JSON.stringify(prefStorage));
    }

    /**
     * @private
     * Initialize persistent storage implementation
     */
    function _initStorage(storage) {
        persistentStorage = storage;

        if (doLoadPreferences) {
            prefStorage = JSON.parse(persistentStorage.getItem(preferencesKey));
        }

        // initialize empty preferences if none were found in storage
        if (!prefStorage) {
            _reset();
        }
    }

    /**
     * This method handles the copy of all old prefs to the new prefs
     * TODO: remove All calls to this function and the function itself
     *
     * @param {!PreferenceStorage} newPrefs The new PreferenceStorage
     * @param {!string} oldID The id of the old PreferenceStorage
     * @param {?obj} defaults The defaults to add
     */
    function handleClientIdChange(newPrefs, oldID, defaults) {
        var oldPrefs = getPreferenceStorage(oldID);

        defaults = defaults || {};

        if (!newPrefs.getValue("newClientID")) {
            var data = oldPrefs.getAllValues();

            if ($.isEmptyObject(data)) {
                data = defaults;
            }

            newPrefs.setAllValues(data, false);
            newPrefs.setValue("newClientID", true);
        }
        delete prefStorage[oldID];
    }

    // Check localStorage for a preferencesKey. Production and unit test keys
    // are used to keep preferences separate within the same storage implementation.
    preferencesKey = localStorage.getItem("preferencesKey");

    if (!preferencesKey) {
        // use default key if none is found
        preferencesKey = PREFERENCES_CLIENT_ID;
        doLoadPreferences = true;
    } else {
        // using a non-default key, check for additional settings
        doLoadPreferences = !!(localStorage.getItem("doLoadPreferences"));
    }

    // Use localStorage by default
    _initStorage(localStorage);

    // Public API
    exports.getPreferenceStorage    = getPreferenceStorage;
    exports.savePreferences         = savePreferences;
    exports.handleClientIdChange    = handleClientIdChange;
    exports.getClientID             = getClientID;

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

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

/**
 * PreferencesManager
 *
 */
define(function (require, exports, module) {
    "use strict";

    var PreferenceStorage = require("preferences/PreferenceStorage").PreferenceStorage,
        FileUtils         = require("file/FileUtils"),
        ExtensionLoader   = require("utils/ExtensionLoader"),
        CollectionUtils   = require("utils/CollectionUtils");

    /**
     * The local storage ID
     * @const
     * @type {string}
     */
    var PREFERENCES_CLIENT_ID = "com.adobe.brackets.preferences";

    /**
     * The prefix used in the generated client ID
     * @const
     * @type {string}
     */
    var CLIENT_ID_PREFIX = "com.adobe.brackets.";

    // Private Properties
    var preferencesKey,
        prefStorage,
        persistentStorage,
        doLoadPreferences   = false;

    /**
     * This method returns a standardized ClientID for a given requireJS module object
     * @param {!{id: string, uri: string}} module - A requireJS module object
     * @return {string} The ClientID
     */
    function getClientID(module) {
        var pathExp, pathUrl, clientID,
            dirPath = FileUtils.getNativeBracketsDirectoryPath(),
            paths   = [
                dirPath + "/extensions/default/",
                dirPath + "/extensions/dev/",
                ExtensionLoader.getUserExtensionPath() + "/"
            ];

        paths.some(function (path) {
            pathExp = new RegExp("^" + path);
            if (module.uri.match(pathExp)) {
                pathUrl = path;
                return true;
            }
        });

        if (pathUrl) {
            clientID = CLIENT_ID_PREFIX + module.uri.replace(pathUrl, "");
        } else {
            clientID = CLIENT_ID_PREFIX + module.id;
        }
        return clientID;
    }

    /**
     * Retreive the preferences data for the given clientID.
     * @param {string|{id: string, uri: string}} clientID - A unique identifier or a requireJS module object
     * @param {string} defaults - Default preferences stored as JSON
     * @return {PreferenceStorage}
     */
    function getPreferenceStorage(clientID, defaults) {
        if (!clientID || (typeof clientID === "object" && (!clientID.id || !clientID.uri))) {
            console.error("Invalid clientID");
            return;
        }
        if (typeof (clientID) === "object") {
            clientID = getClientID(clientID);
        }

        var prefs = prefStorage[clientID];

        if (prefs === undefined) {
            // create a new empty preferences object
            prefs = (defaults && JSON.stringify(defaults)) ? defaults : {};
            prefStorage[clientID] = prefs;
        } else if (defaults) {
            // add new defaults
            CollectionUtils.forEach(defaults, function (value, key) {
                if (prefs[key] === undefined) {
                    prefs[key] = value;
                }
            });
        }

        return new PreferenceStorage(clientID, prefs);
    }

    /**
     * Save all preference clients.
     */
    function savePreferences() {
        // save all preferences
        persistentStorage.setItem(preferencesKey, JSON.stringify(prefStorage));
    }

    /**
     * @private
     * Reset preferences and callbacks
     */
    function _reset() {
        prefStorage = {};

        // Note that storage.clear() is not used. Production and unit test code
        // both rely on the same backing storage but unique item keys.
        persistentStorage.setItem(preferencesKey, JSON.stringify(prefStorage));
    }

    /**
     * @private
     * Initialize persistent storage implementation
     */
    function _initStorage(storage) {
        persistentStorage = storage;

        if (doLoadPreferences) {
            prefStorage = JSON.parse(persistentStorage.getItem(preferencesKey));
        }

        // initialize empty preferences if none were found in storage
        if (!prefStorage) {
            _reset();
        }
    }

    /**
     * This method handles the copy of all old prefs to the new prefs
     * TODO: remove All calls to this function and the function itself
     *
     * @param {!PreferenceStorage} newPrefs The new PreferenceStorage
     * @param {!string} oldID The id of the old PreferenceStorage
     * @param {?obj} defaults The defaults to add
     */
    function handleClientIdChange(newPrefs, oldID, defaults) {
        var oldPrefs = getPreferenceStorage(oldID);

        defaults = defaults || {};

        if (!newPrefs.getValue("newClientID")) {
            var data = oldPrefs.getAllValues();

            if ($.isEmptyObject(data)) {
                data = defaults;
            }

            newPrefs.setAllValues(data, false);
            newPrefs.setValue("newClientID", true);
        }
        delete prefStorage[oldID];
    }

    // Check localStorage for a preferencesKey. Production and unit test keys
    // are used to keep preferences separate within the same storage implementation.
    preferencesKey = localStorage.getItem("preferencesKey");

    if (!preferencesKey) {
        // use default key if none is found
        preferencesKey = PREFERENCES_CLIENT_ID;
        doLoadPreferences = true;
    } else {
        // using a non-default key, check for additional settings
        doLoadPreferences = !!(localStorage.getItem("doLoadPreferences"));
    }

    // Use localStorage by default
    _initStorage(localStorage);

    // Public API
    exports.getPreferenceStorage    = getPreferenceStorage;
    exports.savePreferences         = savePreferences;
    exports.handleClientIdChange    = handleClientIdChange;
    exports.getClientID             = getClientID;

    // Unit test use only
    exports._reset                  = _reset;
});<|endoftext|>


<commit_before><commit_msg>added doc<commit_after>/* write your component code here */<|endoftext|>


<commit_before>var fs = require('fs');
var ncp = require('ncp').ncp;
var prependFile = require('prepend-file');
var pkg = require('../package.json');

var headerContent = ['/**',
  ' * This file is generated. Please don\'t update it',
  ' * ' + pkg.name + ' - ' + pkg.description,
  ' * @version v' + pkg.version,
  ' * @link ' + pkg.homepage,
  ' * @license ' + pkg.license,
  ' */',
  '',
  ''].join('\n');

//Where "src" folder is and have to be place
var copyyFileList =
    [
        {
            input: 'postinstall/gulpfile.js',
            output: '../../gulpfile.js',
            force: true,
            prepend: headerContent
        },
        {
            input: 'postinstall/gulp-config.js',
            output: '../../gulp-config.js'
        },
        {
            input: 'postinstall/.editorconfig',
            output: '../../.editorconfig'
        },
        {
            input: 'postinstall/.eslintrc.json',
            output: '../../.eslintrc.json'
        },
        {
            input: 'postinstall/.sass-lint.yml',
            output: '../../.sass-lint.yml'
        },
        {
            input: 'postinstall/.lesshintrc',
            output: '../../.lesshintrc'
        }
    ];

// Where "src" folder is and have to be place
var assetsInput = 'postinstall/src';
var assetsOutput = '../../src';

function fsExistsSync(myDir) {
    try {
        fs.accessSync(myDir);
        return true;
    } catch (e) {
        return false;
    }
}

// Copy some unitary files
for(var file of copyyFileList) {
    if (file.force || !fsExistsSync(file.output)) {
        fs.createReadStream(file.input).pipe(fs.createWriteStream(file.output));
        if(file.prepend) {
            prependFile(file.output, file.prepend);
        }
    }
}

// Copy source folder in project if not exists yet
if (!fsExistsSync(assetsOutput)) {
    ncp.limit = 16;
    ncp(assetsInput, assetsOutput, {
        filter: /^(?:(?!\.gitkeep).)*$/
    }, function (err) {
        if (err) {
            return console.error(err);
        }
    });
}<commit_msg>[fix] BOILERPLATE-59: fixed script linting<commit_after>var fs = require('fs');
var ncp = require('ncp').ncp;
var prependFile = require('prepend-file');
var pkg = require('../package.json');

var headerContent = ['/**',
    ' * This file is generated. Please don\'t update it',
    ' * ' + pkg.name + ' - ' + pkg.description,
    ' * @version v' + pkg.version,
    ' * @link ' + pkg.homepage,
    ' * @license ' + pkg.license,
    ' */',
    '',
    ''].join('\n');

//Where "src" folder is and have to be place
var copyyFileList =
    [
        {
            input: 'postinstall/gulpfile.js',
            output: '../../gulpfile.js',
            force: true,
            prepend: headerContent
        },
        {
            input: 'postinstall/gulp-config.js',
            output: '../../gulp-config.js'
        },
        {
            input: 'postinstall/.editorconfig',
            output: '../../.editorconfig'
        },
        {
            input: 'postinstall/.eslintrc.json',
            output: '../../.eslintrc.json'
        },
        {
            input: 'postinstall/.sass-lint.yml',
            output: '../../.sass-lint.yml'
        },
        {
            input: 'postinstall/.lesshintrc',
            output: '../../.lesshintrc'
        }
    ];

// Where "src" folder is and have to be place
var assetsInput = 'postinstall/src';
var assetsOutput = '../../src';

function fsExistsSync(myDir) {
    try {
        fs.accessSync(myDir);
        return true;
    } catch (e) {
        return false;
    }
}

// Copy some unitary files
for(var file of copyyFileList) {
    if (file.force || !fsExistsSync(file.output)) {
        fs.createReadStream(file.input).pipe(fs.createWriteStream(file.output));
        if(file.prepend) {
            prependFile(file.output, file.prepend);
        }
    }
}

// Copy source folder in project if not exists yet
if (!fsExistsSync(assetsOutput)) {
    ncp.limit = 16;
    ncp(assetsInput, assetsOutput, {
        filter: /^(?:(?!\.gitkeep).)*$/
    }, function (err) {
        if (err) {
            return console.error(err);
        }
    });
}<|endoftext|>


<commit_before>define(["helper/Basic", "Tone/source/Player", "helper/Offline", "helper/SourceTests", "Tone/core/Buffer", "helper/Meter"],
	function (BasicTests, Player, Offline, SourceTests, Buffer, Meter) {

	describe("Player", function(){

		var buffer = new Buffer();

		beforeEach(function(done){
			buffer.load("./audio/sine.wav", function(){
				done();
			});
		});

		//run the common tests
		BasicTests(Player, buffer);
		SourceTests(Player, buffer);

		context("Loading", function(){

			it("loads a url which was passed in", function(done){
				var player = new Player("./audio/sine.wav", function(){
					player.dispose();
					done();
				});
			});

			it("loads a url using the load method", function(done){
				var player = new Player();
				player.load("./audio/sine.wav", function(){
					expect(player._buffer).to.be.instanceof(Buffer);
					done();
				});
			});

			it("can be created with an options object", function(){
				var player = new Player({
					"url" : "./audio/sine.wav",
					"loop" : true
				});
				player.dispose();
			});

			it("can autostart after loading", function(done){
				var player = new Player({
					"url" : "./audio/sine.wav",
					"autostart" : true,
					"onload" : function(){
						setTimeout(function(){
							expect(player.state).to.be.equal("started");
							done();
						}, 10);
					}
				});
			});

		});

		context("Reverse", function(){

			it("can be played in reverse", function(done){
				var player;
				var offline = new Offline();
				var audioBuffer = buffer.get().getChannelData(0);
				var lastSample = audioBuffer[audioBuffer.length - 1];
				offline.before(function(dest){
					player = new Player(buffer.get()).connect(dest);
					player.reverse = true;
					player.start(0);
				});
				offline.test(function(sample, time){
					if (time === 0){
						expect(sample).to.equal(lastSample);
					}
				});
				offline.after(function(){
					player.dispose();
					buffer.reverse = false;
					done();
				});
				offline.run();
			});

		});

		context("Looping", function(){

			it("can be set to loop", function(){
				var player = new Player();
				player.loop = true;
				expect(player.loop).to.be.true;
				player.dispose();
			});

			it("can set the loop points", function(){
				var player = new Player();
				player.loopStart = 0.4;
				expect(player.loopStart).to.equal(0.4);
				player.loopEnd = 0.5;
				expect(player.loopEnd).to.equal(0.5);
				player.setLoopPoints(0, 0.2);
				expect(player.loopStart).to.equal(0);
				expect(player.loopEnd).to.equal(0.2);
				player.dispose();
			});

			it("loops the audio", function(done){
				var player;
				var meter = new Meter(buffer.duration * 2);
				meter.before(function(dest){
					player = new Player(buffer);
					player.loop = true;
					player.connect(dest);
					player.start(0);
				});
				meter.test(function(sample, time){
					if (time > 0.01){
						expect(sample).to.be.above(0);
					}
				});
				meter.after(function(){
					player.dispose();
					done();
				});
				meter.run();
			});

		});

		context("Get/Set", function(){

			it("can be set with an options object", function(){
				var player = new Player();
				expect(player.loop).to.be.false;
				player.set({
					"loop" : true,
					"loopStart" : 0.4
				});
				expect(player.loop).to.be.true;
				expect(player.loopStart).to.equal(0.4);
				player.dispose();
			});

			it("can get an options object", function(){
				var player = new Player({
					"url" : "./audio/sine.wav",
					"loopStart" : 0.2,
					"loopEnd" : 0.3,
					"loop" : true,
					"reverse" : true
				});
				expect(player.get().loopStart).to.equal(0.2);
				expect(player.get().loopEnd).to.equal(0.3);
				expect(player.get().loop).to.be.true;
				expect(player.get().reverse).to.be.true;
				player.dispose();
			});

			it("can get/set the playbackRate", function(){
				var player = new Player();
				player.playbackRate = 0.5;
				expect(player.playbackRate).to.equal(0.5);
				player.dispose();
			});

		});

		context("Start Scheduling", function(){

			it("can be start with an offset", function(done){
				var player;
				var offline = new Offline(0.4, 1);
				var audioBuffer = buffer.get().getChannelData(0);
				var testSample = audioBuffer[buffer.secondsToSamples(0.1)];
				offline.before(function(dest){
					player = new Player(buffer.get());
					player.connect(dest);
					player.start(0, 0.1);
				});
				offline.test(function(sample, time){
					if (time === 0){
						expect(sample).to.equal(testSample);
					}
				});
				offline.after(function(){
					player.dispose();
					done();
				});
				offline.run();
			});

			it("can be play for a specific duration", function(done){
				var player;
				var meter = new Meter(0.4);
				meter.before(function(dest){
					player = new Player(buffer);
					player.connect(dest);
					player.start(0).stop(0.1);
				});
				meter.test(function(sample, time){
					if (sample < 0.001){
						expect(time).to.at.least(0.1);
						expect(player.state).to.equal("stopped");
					}
				});
				meter.after(function(){
					player.dispose();
					done();
				});
				meter.run();
			});

			it("can be play for a specific duration passed in the 'start' method", function(done){
				var player;
				var meter = new Meter(0.4);
				meter.before(function(dest){
					player = new Player(buffer);
					player.connect(dest);
					player.start(0, 0.1);
				});
				meter.test(function(sample, time){
					if (sample < 0.001){
						expect(time).to.at.least(0.1);
						expect(player.state).to.equal("stopped");
					}
				});
				meter.after(function(){
					player.dispose();
					done();
				});
				meter.run();
			});

			it("reports itself as stopped after a single iterations of the buffer", function(done){
				var player = new Player("./audio/kick.mp3", function(){
					var duration = player.buffer.duration;
					player.start();
					setTimeout(function(){
						expect(player.state).to.equal("started");
					}, 100);
					setTimeout(function(){
						expect(player.state).to.equal("stopped");
						done();
					}, duration * 1000 + 200);
				});
			});

		});

	});
});<commit_msg>Testing loading with a Tone.Buffer and AudioBuffer<commit_after>define(["helper/Basic", "Tone/source/Player", "helper/Offline", "helper/SourceTests", "Tone/core/Buffer", "helper/Meter"],
	function (BasicTests, Player, Offline, SourceTests, Buffer, Meter) {

	describe("Player", function(){

		var buffer = new Buffer();

		beforeEach(function(done){
			buffer.load("./audio/sine.wav", function(){
				done();
			});
		});

		//run the common tests
		BasicTests(Player, buffer);
		SourceTests(Player, buffer);

		context("Constructor", function(){

			it ("can be constructed with a Tone.Buffer", function(done){
				var player = new Player(buffer);
				expect(player.buffer.get()).to.equal(buffer.get());
				player.dispose();
				done();
			});

			it ("can be constructed with an AudioBuffer", function(done){
				var player = new Player(buffer.get());
				expect(player.buffer.get()).to.equal(buffer.get());
				player.dispose();
				done();
			});
		});

		context("Loading", function(){

			it("loads a url which was passed in", function(done){
				var player = new Player("./audio/sine.wav", function(){
					player.dispose();
					done();
				});
			});

			it("loads a url using the load method", function(done){
				var player = new Player();
				player.load("./audio/sine.wav", function(){
					expect(player._buffer).to.be.instanceof(Buffer);
					done();
				});
			});

			it("can be created with an options object", function(){
				var player = new Player({
					"url" : "./audio/sine.wav",
					"loop" : true
				});
				player.dispose();
			});

			it("can autostart after loading", function(done){
				var player = new Player({
					"url" : "./audio/sine.wav",
					"autostart" : true,
					"onload" : function(){
						setTimeout(function(){
							expect(player.state).to.be.equal("started");
							done();
						}, 10);
					}
				});
			});

		});

		context("Reverse", function(){

			it("can be played in reverse", function(done){
				var player;
				var offline = new Offline();
				var audioBuffer = buffer.get().getChannelData(0);
				var lastSample = audioBuffer[audioBuffer.length - 1];
				offline.before(function(dest){
					player = new Player(buffer.get()).connect(dest);
					player.reverse = true;
					player.start(0);
				});
				offline.test(function(sample, time){
					if (time === 0){
						expect(sample).to.equal(lastSample);
					}
				});
				offline.after(function(){
					player.dispose();
					buffer.reverse = false;
					done();
				});
				offline.run();
			});

		});

		context("Looping", function(){

			it("can be set to loop", function(){
				var player = new Player();
				player.loop = true;
				expect(player.loop).to.be.true;
				player.dispose();
			});

			it("can set the loop points", function(){
				var player = new Player();
				player.loopStart = 0.4;
				expect(player.loopStart).to.equal(0.4);
				player.loopEnd = 0.5;
				expect(player.loopEnd).to.equal(0.5);
				player.setLoopPoints(0, 0.2);
				expect(player.loopStart).to.equal(0);
				expect(player.loopEnd).to.equal(0.2);
				player.dispose();
			});

			it("loops the audio", function(done){
				var player;
				var meter = new Meter(buffer.duration * 2);
				meter.before(function(dest){
					player = new Player(buffer);
					player.loop = true;
					player.connect(dest);
					player.start(0);
				});
				meter.test(function(sample, time){
					if (time > 0.01){
						expect(sample).to.be.above(0);
					}
				});
				meter.after(function(){
					player.dispose();
					done();
				});
				meter.run();
			});

		});

		context("Get/Set", function(){

			it("can be set with an options object", function(){
				var player = new Player();
				expect(player.loop).to.be.false;
				player.set({
					"loop" : true,
					"loopStart" : 0.4
				});
				expect(player.loop).to.be.true;
				expect(player.loopStart).to.equal(0.4);
				player.dispose();
			});

			it("can get an options object", function(){
				var player = new Player({
					"url" : "./audio/sine.wav",
					"loopStart" : 0.2,
					"loopEnd" : 0.3,
					"loop" : true,
					"reverse" : true
				});
				expect(player.get().loopStart).to.equal(0.2);
				expect(player.get().loopEnd).to.equal(0.3);
				expect(player.get().loop).to.be.true;
				expect(player.get().reverse).to.be.true;
				player.dispose();
			});

			it("can get/set the playbackRate", function(){
				var player = new Player();
				player.playbackRate = 0.5;
				expect(player.playbackRate).to.equal(0.5);
				player.dispose();
			});

		});

		context("Start Scheduling", function(){

			it("can be start with an offset", function(done){
				var player;
				var offline = new Offline(0.4, 1);
				var audioBuffer = buffer.get().getChannelData(0);
				var testSample = audioBuffer[buffer.secondsToSamples(0.1)];
				offline.before(function(dest){
					player = new Player(buffer.get());
					player.connect(dest);
					player.start(0, 0.1);
				});
				offline.test(function(sample, time){
					if (time === 0){
						expect(sample).to.equal(testSample);
					}
				});
				offline.after(function(){
					player.dispose();
					done();
				});
				offline.run();
			});

			it("can be play for a specific duration", function(done){
				var player;
				var meter = new Meter(0.4);
				meter.before(function(dest){
					player = new Player(buffer);
					player.connect(dest);
					player.start(0).stop(0.1);
				});
				meter.test(function(sample, time){
					if (sample < 0.001){
						expect(time).to.at.least(0.1);
						expect(player.state).to.equal("stopped");
					}
				});
				meter.after(function(){
					player.dispose();
					done();
				});
				meter.run();
			});

			it("can be play for a specific duration passed in the 'start' method", function(done){
				var player;
				var meter = new Meter(0.4);
				meter.before(function(dest){
					player = new Player(buffer);
					player.connect(dest);
					player.start(0, 0.1);
				});
				meter.test(function(sample, time){
					if (sample < 0.001){
						expect(time).to.at.least(0.1);
						expect(player.state).to.equal("stopped");
					}
				});
				meter.after(function(){
					player.dispose();
					done();
				});
				meter.run();
			});

			it("reports itself as stopped after a single iterations of the buffer", function(done){
				var player = new Player("./audio/kick.mp3", function(){
					var duration = player.buffer.duration;
					player.start();
					setTimeout(function(){
						expect(player.state).to.equal("started");
					}, 100);
					setTimeout(function(){
						expect(player.state).to.equal("stopped");
						done();
					}, duration * 1000 + 200);
				});
			});

		});

	});
});<|endoftext|>


<commit_before>/**
 * Quick Create: RelateCreateWindow; simple form in a popup window to create a new record
 */
Ext.ns('Garp');

Garp.RelateCreateWindow = Ext.extend(Ext.Window,{

	model: '',
	iconCls: '',
	title: '',
	cls: 'relate-create-window',
	modal: true,
	width: 640,
	border: true,
	preventBodyReset: false,
	autoScroll: true,

	rec: null,

	quickCreatableInit: Ext.emptyFn,

	initComponent: function(){

		if (!this.iconCls) {
			this.setIconClass(Garp.dataTypes[this.model].iconCls);
		}
		if (!this.title) {
			this.setTitle(Garp.dataTypes[this.model].text);
		}
		this.addEvents('aftersave', 'afterinit');

		this.writer = new Ext.data.JsonWriter({
			paramsAsHash: false,
			encode: false
		});
		var fields = [];
		var cm = Garp.dataTypes[this.model].columnModel;
		Ext.each(cm, function(c){
			fields.push(c.dataIndex);
		});

		this.store = new Ext.data.DirectStore({
			fields: fields,
			autoLoad: false,
			autoSave: false,
			pruneModifiedRecords: true,
			remoteSort: true,
			restful: true,
			autoDestroy: true,
			root: 'rows',
			idProperty: 'id',
			sortInfo: Garp.dataTypes[this.model].sortInfo || null,
			baseParams: {
				start: 0,
				limit: Garp.pageSize
			},
			api: {
				create: Garp[this.model].create || Ext.emptyFn,
				read: Garp[this.model].fetch || Ext.emptyFn,
				update: Garp[this.model].update || Ext.emptyFn,
				destroy: Garp[this.model].destroy || Ext.emptyFn
			},
			writer: this.writer
		});

		var items = Ext.apply({}, Garp.dataTypes[this.model].formConfig[0].items[0]);
		var listeners = Ext.apply({}, Garp.dataTypes[this.model].formConfig[0].listeners);
		items = {
			ref: '../formcontent',
			items: [items],
			listeners: listeners,
			bodyCssClass: 'garp-formpanel',
			border: false
		};

		// Now hide disabled items, they have no function when adding a new item. It may otherwise confuse users:
		// Also: if the field is not in the columnModel, it has no place here in this window
		this.items = [{
			border: false,
			xtype: 'form',
			layout: 'form',
			ref: 'form',
			defaults: {
				autoWidth: true,
				border: false,
				bodyCssClass: 'garp-formpanel' // visual styling
			},
			items: items
		}];

		if (!this.buttons) {
			this.buttons = [];
		}
		this.buttons.push([{
			text: __('Cancel'),
			ref: '../cancelBtn',
			handler: function(){
				this.close();
			},
			scope: this
		}, {
			text: __('Ok'),
			ref: '../okBtn',
			handler: function(){
				this.saveAll(true);
			},
			scope: this
		}]);

		Garp.RelateCreateWindow.superclass.initComponent.call(this);
	},

	saveAll: function(doClose){
		if (!this.form.getForm().isValid()) {
			this.form.getForm().items.each(function(){
				this.isValid(); // marks the field also visually invalid if needed
			});
			return;
		}
		this.form.getForm().updateRecord(this.rec);
		this.store.on({
			'save': {
				fn: function(){
					this.rec = this.store.getAt(0);
					if (this.formcontent) {
						this.formcontent.fireEvent('loaddata', this.rec, this);
					}
					this.fireEvent('aftersave', this, this.rec);
					this.loadMask.hide();
					if (doClose) {
						this.close();
					}
				},
				single: true,
				scope: this
			}
		});
		if(this.store.save() !== -1){
			this.loadMask = new Ext.LoadMask(this.getEl());
			this.loadMask.show();
		}
	},

	afterRender: function(){
		Garp.RelateCreateWindow.superclass.afterRender.call(this);
		this.form.getForm().setValues(Garp.dataTypes[this.model].defaultData);
		if (this.onShow) {
			this.onShow.call(this);
		}
		var rec = new this.store.recordType(Ext.apply({}, Garp.dataTypes[this.model].defaultData));
		this.rec = rec;
		this.store.insert(0, rec);

		this.getForm = function(){
			return this.form.getForm();
		};

		this.on('save-all', this.saveAll, this);

		this.on('show', function(){
			this.formcontent.fireEvent('loaddata', rec, this);
			this.quickCreatableInit();
			this.getForm().clearInvalid();
			if (this.quickCreateReference) {
				var id = this.parentId || Garp.gridPanel.getSelectionModel().getSelected().get('id');
				this.getForm().findField(this.quickCreateReference).store.on('load', function(){
					this.getForm().findField(this.quickCreateReference).setValue(id);
				}, this, {
					single: true
				});
				this.getForm().findField(this.quickCreateReference).store.load();
				this.getForm().findField(this.quickCreateReference).hide();

				// this is dumb... have to reset the height after hiding the field
				this.setHeight(this.getHeight());
				this.center();
			}
			window.weenerdog = this;
			this.keymap = new Ext.KeyMap(this.formcontent.getEl(), [{
				key: Ext.EventObject.ENTER,
				ctrl: true,
				scope: this,
				handler: function(e){
					this.form.getForm().items.each(function(){
						this.fireEvent('blur', this);
					});
					this.okBtn.handler.call(this);
					return false;
				}
			}]);
			this.keymap.stopEvent = true; // prevents browser key handling.
			this.fireEvent('afterinit', this);
		}, this);
	}
});
<commit_msg>Collapse fieldsets in relatecreatewindows<commit_after>/**
 * Quick Create: RelateCreateWindow; simple form in a popup window to create a new record
 */
Ext.ns('Garp');

Garp.RelateCreateWindow = Ext.extend(Ext.Window,{

	model: '',
	iconCls: '',
	title: '',
	cls: 'relate-create-window',
	modal: true,
	width: 640,
	border: true,
	preventBodyReset: false,
	autoScroll: true,

	rec: null,

	quickCreatableInit: Ext.emptyFn,

	initComponent: function(){

		if (!this.iconCls) {
			this.setIconClass(Garp.dataTypes[this.model].iconCls);
		}
		if (!this.title) {
			this.setTitle(Garp.dataTypes[this.model].text);
		}
		this.addEvents('aftersave', 'afterinit');

		this.writer = new Ext.data.JsonWriter({
			paramsAsHash: false,
			encode: false
		});
		var fields = [];
		var cm = Garp.dataTypes[this.model].columnModel;
		Ext.each(cm, function(c){
			fields.push(c.dataIndex);
		});

		this.store = new Ext.data.DirectStore({
			fields: fields,
			autoLoad: false,
			autoSave: false,
			pruneModifiedRecords: true,
			remoteSort: true,
			restful: true,
			autoDestroy: true,
			root: 'rows',
			idProperty: 'id',
			sortInfo: Garp.dataTypes[this.model].sortInfo || null,
			baseParams: {
				start: 0,
				limit: Garp.pageSize
			},
			api: {
				create: Garp[this.model].create || Ext.emptyFn,
				read: Garp[this.model].fetch || Ext.emptyFn,
				update: Garp[this.model].update || Ext.emptyFn,
				destroy: Garp[this.model].destroy || Ext.emptyFn
			},
			writer: this.writer
		});

		var items = Ext.apply({}, Garp.dataTypes[this.model].formConfig[0].items[0]);
		var listeners = Ext.apply({}, Garp.dataTypes[this.model].formConfig[0].listeners);
		items = {
			ref: '../formcontent',
			items: [items],
			listeners: listeners,
			bodyCssClass: 'garp-formpanel',
			border: false
		};

		// Collapse fieldsets, to save some room (window is tiny as it is)
		for (var j = 0; j < items.items[0].items.length; ++j) {
			if ('collapsed' in items.items[0].items[j]) {
				items.items[0].items[j].collapsed = true;
			}
		}

		// Now hide disabled items, they have no function when adding a new item. It may otherwise confuse users:
		// Also: if the field is not in the columnModel, it has no place here in this window
		this.items = [{
			border: false,
			xtype: 'form',
			layout: 'form',
			ref: 'form',
			defaults: {
				autoWidth: true,
				border: false,
				bodyCssClass: 'garp-formpanel' // visual styling
			},
			items: items
		}];

		if (!this.buttons) {
			this.buttons = [];
		}
		this.buttons.push([{
			text: __('Cancel'),
			ref: '../cancelBtn',
			handler: function(){
				this.close();
			},
			scope: this
		}, {
			text: __('Ok'),
			ref: '../okBtn',
			handler: function(){
				this.saveAll(true);
			},
			scope: this
		}]);

		Garp.RelateCreateWindow.superclass.initComponent.call(this);
	},

	saveAll: function(doClose){
		if (!this.form.getForm().isValid()) {
			this.form.getForm().items.each(function(){
				this.isValid(); // marks the field also visually invalid if needed
			});
			return;
		}
		this.form.getForm().updateRecord(this.rec);
		this.store.on({
			'save': {
				fn: function(){
					this.rec = this.store.getAt(0);
					if (this.formcontent) {
						this.formcontent.fireEvent('loaddata', this.rec, this);
					}
					this.fireEvent('aftersave', this, this.rec);
					this.loadMask.hide();
					if (doClose) {
						this.close();
					}
				},
				single: true,
				scope: this
			}
		});
		if(this.store.save() !== -1){
			this.loadMask = new Ext.LoadMask(this.getEl());
			this.loadMask.show();
		}
	},

	afterRender: function(){
		Garp.RelateCreateWindow.superclass.afterRender.call(this);
		this.form.getForm().setValues(Garp.dataTypes[this.model].defaultData);
		if (this.onShow) {
			this.onShow.call(this);
		}
		var rec = new this.store.recordType(Ext.apply({}, Garp.dataTypes[this.model].defaultData));
		this.rec = rec;
		this.store.insert(0, rec);

		this.getForm = function(){
			return this.form.getForm();
		};

		this.on('save-all', this.saveAll, this);

		this.on('show', function(){
			this.formcontent.fireEvent('loaddata', rec, this);
			this.quickCreatableInit();
			this.getForm().clearInvalid();
			if (this.quickCreateReference) {
				var id = this.parentId || Garp.gridPanel.getSelectionModel().getSelected().get('id');
				this.getForm().findField(this.quickCreateReference).store.on('load', function(){
					this.getForm().findField(this.quickCreateReference).setValue(id);
				}, this, {
					single: true
				});
				this.getForm().findField(this.quickCreateReference).store.load();
				this.getForm().findField(this.quickCreateReference).hide();

				// this is dumb... have to reset the height after hiding the field
				this.setHeight(this.getHeight());
				this.center();
			}
			window.weenerdog = this;
			this.keymap = new Ext.KeyMap(this.formcontent.getEl(), [{
				key: Ext.EventObject.ENTER,
				ctrl: true,
				scope: this,
				handler: function(e){
					this.form.getForm().items.each(function(){
						this.fireEvent('blur', this);
					});
					this.okBtn.handler.call(this);
					return false;
				}
			}]);
			this.keymap.stopEvent = true; // prevents browser key handling.
			this.fireEvent('afterinit', this);
		}, this);
	}
});
<|endoftext|>


<commit_before>const { join } = require('path')
const { writeFile } = require('fs').promises
const { default: players } = require('../lib/players')

const generateSinglePlayers = async () => {
  for (const { key, name } of players) {
    const file = `
      const createReactPlayer = require('./lib/ReactPlayer').createReactPlayer
      const Player = require('./lib/players/${name}').default
      module.exports = createReactPlayer([Player])
    `
    await writeFile(join('.', `${key}.js`), file)
  }
}

generateSinglePlayers()
<commit_msg>Fix single player import logic<commit_after>const { join } = require('path')
const { writeFile } = require('fs').promises
const { default: players } = require('../lib/players')

const generateSinglePlayers = async () => {
  for (const { key, name } of players) {
    const file = `
      const createReactPlayer = require('./lib/ReactPlayer').createReactPlayer
      const Player = require('./lib/players/${name}').default
      module.exports = createReactPlayer([{
        key: '${key}',
        canPlay: Player.canPlay,
        lazyPlayer: Player
      }])
    `
    await writeFile(join('.', `${key}.js`), file)
  }
}

generateSinglePlayers()
<|endoftext|>


<commit_before>/*global:describe,beforeEach,it,expect,spyOn*/
define(["./jasmine-matchers", "units-required/model/UnitList"], function(customJasmineMatchers, UnitList) {

    describe("UnitList.equals", function() {

        it("*.equals(null) is false", function() {
            expect(new UnitList().equals(null)).toBe(false);
        });

        it("*.equals() is false", function() {
            expect(new UnitList().equals()).toBe(false);
        });

        it("x.equals(x) is true", function() {
            var u = new UnitList();
            expect(u.equals(u)).toBe(true);
        });

        it("[].equals([]) is true", function() {
            var u1 = new UnitList();
            var u2 = new UnitList();
            expect(u1.equals(u2)).toBe(true);
        });

        it("[R99].equals([R99]) is true", function() {
            var u1 = UnitList.fromUnits("R", 99);
            var u2 = UnitList.fromUnits("R", 99);
            expect(u1.equals(u2)).toBe(true);
        });

        it("[R99].equals([]) is false", function() {
            var u1 = UnitList.fromUnits("R", 99);
            var u2 = new UnitList();
            expect(u1.equals(u2)).toBe(false);
        });

        it("[].equals([R99]) is false", function() {
            var u1 = new UnitList();
            var u2 = UnitList.fromUnits("R", 99);
            expect(u1.equals(u2)).toBe(false);
        });

    });

    describe("UnitList.missing", function() {

        it("[] missing [] == []", function() {
            var u1 = new UnitList();
            var u2 = new UnitList();
            var u3 = u2.missing(u1);
            expect(u3.totalUnits()).toBe(0);
        });

        it("[R10] missing [] == []", function() {
            var u1 = UnitList.fromUnits("R", 10);
            var u2 = new UnitList();
            var u3 = u1.missing(u2);
            expect(u3.count("R")).toBe(0);
        });

        it("[R99, C11] missing [R99, C11] == []", function() {
            var u1 = UnitList.fromUnits("R", 99, "C", 11);
            var u2 = u1.copy();
            var u3 = u1.missing(u2);
            expect(u3.count("R")).toBe(0);
            expect(u3.count("C")).toBe(0);
            expect(u3.totalUnits()).toBe(0);
        });

        it("[] missing [R99, C11] == [R99, C11]", function() {
            var u1 = new UnitList();
            var u2 = UnitList.fromUnits("R", 99, "C", 11);
            var u3 = u1.missing(u2);
            console.log(u1, u2, u2);
            expect(u3.count("R")).toBe(99);
            expect(u3.count("C")).toBe(11);
            expect(u3.totalUnits()).toBe(110);
        });

        it("[R99, C11] missing [] == []", function() {
            var u1 = UnitList.fromUnits("R", 99, "C", 11);
            var u2 = new UnitList();
            var u3 = u1.missing(u2);
            expect(u3.count("R")).toBe(0);
            expect(u3.count("C")).toBe(0);
            expect(u3.totalUnits()).toBe(0);
        });

    });

    describe("UnitList.addUnits", function() {

        beforeEach(function() {
            // adds toEqualUnitList()
            this.addMatchers(customJasmineMatchers);
        });

        it("[R, 99, C, 11]", function() {
            var u1 = new UnitList().addUnits("R", 99, "C", 11);
            var u2 = UnitList.fromUnits("R", 99, "C", 11);
            expect(u1).toEqualUnitList(u2);
            expect(u1.count("R")).toBe(99);
            expect(u1.count("C")).toBe(11);
        });

    });

});
<commit_msg>Remove console.log that was causing error on IE9.<commit_after>/*global:describe,beforeEach,it,expect,spyOn*/
define(["./jasmine-matchers", "units-required/model/UnitList"], function(customJasmineMatchers, UnitList) {

    describe("UnitList.equals", function() {

        it("*.equals(null) is false", function() {
            expect(new UnitList().equals(null)).toBe(false);
        });

        it("*.equals() is false", function() {
            expect(new UnitList().equals()).toBe(false);
        });

        it("x.equals(x) is true", function() {
            var u = new UnitList();
            expect(u.equals(u)).toBe(true);
        });

        it("[].equals([]) is true", function() {
            var u1 = new UnitList();
            var u2 = new UnitList();
            expect(u1.equals(u2)).toBe(true);
        });

        it("[R99].equals([R99]) is true", function() {
            var u1 = UnitList.fromUnits("R", 99);
            var u2 = UnitList.fromUnits("R", 99);
            expect(u1.equals(u2)).toBe(true);
        });

        it("[R99].equals([]) is false", function() {
            var u1 = UnitList.fromUnits("R", 99);
            var u2 = new UnitList();
            expect(u1.equals(u2)).toBe(false);
        });

        it("[].equals([R99]) is false", function() {
            var u1 = new UnitList();
            var u2 = UnitList.fromUnits("R", 99);
            expect(u1.equals(u2)).toBe(false);
        });

    });

    describe("UnitList.missing", function() {

        it("[] missing [] == []", function() {
            var u1 = new UnitList();
            var u2 = new UnitList();
            var u3 = u2.missing(u1);
            expect(u3.totalUnits()).toBe(0);
        });

        it("[R10] missing [] == []", function() {
            var u1 = UnitList.fromUnits("R", 10);
            var u2 = new UnitList();
            var u3 = u1.missing(u2);
            expect(u3.count("R")).toBe(0);
        });

        it("[R99, C11] missing [R99, C11] == []", function() {
            var u1 = UnitList.fromUnits("R", 99, "C", 11);
            var u2 = u1.copy();
            var u3 = u1.missing(u2);
            expect(u3.count("R")).toBe(0);
            expect(u3.count("C")).toBe(0);
            expect(u3.totalUnits()).toBe(0);
        });

        it("[] missing [R99, C11] == [R99, C11]", function() {
            var u1 = new UnitList();
            var u2 = UnitList.fromUnits("R", 99, "C", 11);
            var u3 = u1.missing(u2);
            expect(u3.count("R")).toBe(99);
            expect(u3.count("C")).toBe(11);
            expect(u3.totalUnits()).toBe(110);
        });

        it("[R99, C11] missing [] == []", function() {
            var u1 = UnitList.fromUnits("R", 99, "C", 11);
            var u2 = new UnitList();
            var u3 = u1.missing(u2);
            expect(u3.count("R")).toBe(0);
            expect(u3.count("C")).toBe(0);
            expect(u3.totalUnits()).toBe(0);
        });

    });

    describe("UnitList.addUnits", function() {

        beforeEach(function() {
            // adds toEqualUnitList()
            this.addMatchers(customJasmineMatchers);
        });

        it("[R, 99, C, 11]", function() {
            var u1 = new UnitList().addUnits("R", 99, "C", 11);
            var u2 = UnitList.fromUnits("R", 99, "C", 11);
            expect(u1).toEqualUnitList(u2);
            expect(u1.count("R")).toBe(99);
            expect(u1.count("C")).toBe(11);
        });

    });

});
<|endoftext|>


<commit_before>//abstract base class
function InboxStateObject() {
    this.baseUrl = $("input[name='baseUrl']").val();
}

InboxStateObject.prototype.undo = function() {

    var me = this;
    $(document).delegate("a.undo", "click", function(e) {
        var feedid    = $(this).attr('href');
        var href      = $(this).attr('hrefaction');
        var undo_type = $(this).attr('undo-type');
        var undo_mode = $('.inbox-state').val();

        var current_catid = me.elem.attr('catid');
        var sec       = 350;

        $("#" + me.feeds.feedid).fadeIn(sec);
        $(this).parents("."+undo_type).fadeOut(sec, function() { $(this).remove(); });
        $.ajax({  type: "POST"
                , url: href
                , data: {"mode": undo_mode, "feed_ids": [me.feeds], "cat_id": current_catid, "catstate": true}
                , success: function () {
                    var myStatus = new Status();
                    myStatus.notify("Processing...", 1000);
                  }
               });
        e.preventDefault();
    });
}

InboxStateObject.prototype.process = function() {

    var me = this;
    var is_single = $(me).attr('feedid');
    console.log(is_single);
    console.log(me.mode);
    console.log(me.baseUrl);
    //TODO: if publish or feature do not animate if in Published Folder animate in Inbox Folder only.
    /*
    if(is_single) {
        $(me.elem).parents('.feedback').fadeOut(350, function() {
            var undo       = "  Undo";
            var close_checky = "  Close";
            var notify_msg = me.message + undo + close_checky;
            var notify     = $('
').addClass(me.identifier).html(notify_msg);
            var checky = $('.checky-bar');

            if(me.state == 0) {
                console.log(me.href);
                console.log(me.state);

                $.ajax({ type: "POST", url: me.href, data: {"mode": me.mode ,"feed_ids": [me.feeds], "cat_id": me.catid, "catstate": me.catstate }
                       , success: function() {
                             checky.html(notify).show();
                             var myStatus = new Status();
                             myStatus.notify("Processing...", 1000);
                         }
                });

            } else {
                //if state is 1 then we're going back to the inbox
                console.log(me.href);
                console.log(me.state);

                $.ajax({ type: "POST", url: me.href, data: {"mode": "inbox" ,"feed_ids": [me.feeds], "cat_id": me.catid }
                      , success: function() {
                            checky.html("
Feedback has been sent to the " + "Inbox " + undo + close_checky + "
")
                            .show();

                            var myStatus = new Status();
                            myStatus.notify("Processing...", 1000);
                        }
                });

            }

        });
    }
    */

    $(document).delegate('a.close-checky', 'click', function(e) {
        $(this).parents('.check').remove();
        e.preventDefault();
    })

}

//child implementation classes
function PublishStateObject(elem) {
    InboxStateObject.apply(this, arguments);
    this.elem = elem;
    this.message = "Feedback has been published and moved to " + "Published Folder";
    this.mode    = "publish";
    this.feedid = $(elem).attr('feedid');
    this.href   = $(elem).attr('hrefaction');
    this.catid  = $(elem).attr('catid');
    this.catstate = $(elem).attr('cat-state');
    this.state  = $(elem).attr('state');
    this.feeds = {feedid: this.feedid};
    this.identifier = $(elem).attr('class');
}
PublishStateObject.prototype = new InboxStateObject();

function FeatureStateObject(elem) {
    InboxStateObject.apply(this, arguments);
    this.elem = elem;
    this.message = "Feedback has been published and moved to " + "Featured Folder";
    this.mode    = "feature";
    this.feedid = $(elem).attr('feedid');
    this.href   = $(elem).attr('hrefaction');
    this.catid  = $(elem).attr('catid');
    this.catstate = $(elem).attr('cat-state');
    this.state  = $(elem).attr('state');
    this.feeds = {feedid: this.feedid};
    this.identifier = $(elem).attr('class');
}
FeatureStateObject.prototype = new InboxStateObject();

function RemoveStateObject(elem) {
    InboxStateObject.apply(this, arguments);
    this.elem = elem;
    this.message = "Feedback has been " + "deleted";
    this.mode    = "delete";
    this.feedid = $(elem).attr('feedid');
    this.href   = $(elem).attr('hrefaction');
    this.catid  = $(elem).attr('catid');
    this.catstate = $(elem).attr('cat-state');
    this.state  = $(elem).attr('state');
    this.feeds = {feedid: this.feedid};
    this.identifier = $(elem).attr('class');
}
RemoveStateObject.prototype = new InboxStateObject();

function CatPickObject(elem) {
    InboxStateObject.apply(this, arguments);
    this.elem = elem;
    this.catstate = $(elem).attr('cat-state');
    if(this.catstate == 'default') {
        this.message = "Feedback has been sent to " + "Inbox";
    } else {
        this.message = "Feedback has been sent to " + "Filed Feedback";
    }
    this.mode    = "fileas";
    $(elem).parents('div.category-picker-holder').hide();
    this.feedid = $(elem).attr('feedid');
    this.href   = $(elem).attr('hrefaction');
    this.catid  = $(elem).attr('catid');
    this.catstate = $(elem).attr('cat-state');
    this.state  = $(elem).attr('state');
    this.feeds = {feedid: this.feedid};
    this.identifier = $(elem).attr('class');
}

CatPickObject.prototype = new InboxStateObject();
CatPickObject.prototype.process = function() {
    var me = this;
    if(location.pathname.match(/filed|modifyfeedback/)) {
        $.ajax({ type: "POST", url: me.href, data: {"mode": me.mode ,"feed_ids": [me.feeds], "cat_id": me.catid, "catstate": me.catstate }, success: function() {
            if(me.catstate == "default") {
                $(me.elem).parents('.feedback').fadeOut(350);
            }
            var myStatus = new Status();
            myStatus.notify("Processing...", 1000);
        }});
    } else {
        $(this.elem).parents('.feedback').fadeOut(350, function() {
            var undo       = " Undo";
            var close_checky = "  Close";
            var notify_msg = me.message + undo + close_checky;
            var notify     = $('
').addClass(me.identifier).html(notify_msg);
            var checky = $('.checky-bar');

            if(me.state == 0) {
                $.ajax({ type: "POST", url: me.href, data: {"mode": me.mode ,"feed_ids": [me.feeds], "cat_id": me.catid, "catstate": me.catstate }, success: function()
                    {

                        var myStatus = new Status();
                        myStatus.notify("Processing...", 1000);
                        checky.html(notify).show();
                    }
                });
            } else {
                //if state is 1 then we're going back to the inbox
                $.ajax({ type: "POST", url: me.href, data: {"mode": "inbox" ,"feed_ids": [me.feeds], "cat_id": me.catid }, success: function()
                    {

                        var myStatus = new Status();
                        myStatus.notify("Processing...", 1000);
                        checky.html("
Feedback has been sent to the " + "Inbox " + undo + close_checky +"
")
                        .show();
                    }
                });
            }
        });

    }

    $(document).delegate('a.close-checky', 'click', function(e) {
        $(this).parents('.check').remove();
        e.preventDefault();
    })
}

//Factory
function InboxStatusChange(opts)  {
    this.inbox_controls = opts;
}

InboxStatusChange.prototype.initialize = function() {
    var me = this;
    $(document).delegate(me.inbox_controls, 'click', function(e) {
        var identifier = $(this).attr('class');
        var us = $(this);

        $.ajax({url: "/feedback/bust_hostfeed_data"});

        if(identifier == 'check') {
            var check = new PublishStateObject(us);
            check.process();
            check.undo();
        }

        if(identifier == 'feature') {
            var feature = new FeatureStateObject(us);
            feature.process();
            feature.undo();
        }

        if(identifier == 'remove' || identifier == 'popup-delete') {
            var remove = new RemoveStateObject(us);
            remove.process();
            remove.undo();
        }

    })
}
<commit_msg>I'm serious<commit_after>//abstract base class
function InboxStateObject() {
    this.baseUrl = $("input[name='baseUrl']").val();
    this.currentUrl = window.location.pathname;
}

InboxStateObject.prototype.undo = function() {

    var me = this;
    $(document).delegate("a.undo", "click", function(e) {
        var feedid    = $(this).attr('href');
        var href      = $(this).attr('hrefaction');
        var undo_type = $(this).attr('undo-type');
        var undo_mode = $('.inbox-state').val();

        var current_catid = me.elem.attr('catid');
        var sec       = 350;

        $("#" + me.feeds.feedid).fadeIn(sec);
        $(this).parents("."+undo_type).fadeOut(sec, function() { $(this).remove(); });
        $.ajax({  type: "POST"
                , url: href
                , data: {"mode": undo_mode, "feed_ids": [me.feeds], "cat_id": current_catid, "catstate": true}
                , success: function () {
                    var myStatus = new Status();
                    myStatus.notify("Processing...", 1000);
                  }
               });
        e.preventDefault();
    });
}

InboxStateObject.prototype.process = function() {

    var me = this;
    var is_single = $(me).attr('feedid');
    console.log(is_single);
    console.log(me.mode);
    console.log(me.currentUrl);
    //TODO: if publish or feature do not animate if in Published Folder animate in Inbox Folder only.
    /*
    if(is_single) {
        $(me.elem).parents('.feedback').fadeOut(350, function() {
            var undo       = "  Undo";
            var close_checky = "  Close";
            var notify_msg = me.message + undo + close_checky;
            var notify     = $('
').addClass(me.identifier).html(notify_msg);
            var checky = $('.checky-bar');

            if(me.state == 0) {
                console.log(me.href);
                console.log(me.state);

                $.ajax({ type: "POST", url: me.href, data: {"mode": me.mode ,"feed_ids": [me.feeds], "cat_id": me.catid, "catstate": me.catstate }
                       , success: function() {
                             checky.html(notify).show();
                             var myStatus = new Status();
                             myStatus.notify("Processing...", 1000);
                         }
                });

            } else {
                //if state is 1 then we're going back to the inbox
                console.log(me.href);
                console.log(me.state);

                $.ajax({ type: "POST", url: me.href, data: {"mode": "inbox" ,"feed_ids": [me.feeds], "cat_id": me.catid }
                      , success: function() {
                            checky.html("
Feedback has been sent to the " + "Inbox " + undo + close_checky + "
")
                            .show();

                            var myStatus = new Status();
                            myStatus.notify("Processing...", 1000);
                        }
                });

            }

        });
    }
    */

    $(document).delegate('a.close-checky', 'click', function(e) {
        $(this).parents('.check').remove();
        e.preventDefault();
    })

}

//child implementation classes
function PublishStateObject(elem) {
    InboxStateObject.apply(this, arguments);
    this.elem = elem;
    this.message = "Feedback has been published and moved to " + "Published Folder";
    this.mode    = "publish";
    this.feedid = $(elem).attr('feedid');
    this.href   = $(elem).attr('hrefaction');
    this.catid  = $(elem).attr('catid');
    this.catstate = $(elem).attr('cat-state');
    this.state  = $(elem).attr('state');
    this.feeds = {feedid: this.feedid};
    this.identifier = $(elem).attr('class');
}
PublishStateObject.prototype = new InboxStateObject();

function FeatureStateObject(elem) {
    InboxStateObject.apply(this, arguments);
    this.elem = elem;
    this.message = "Feedback has been published and moved to " + "Featured Folder";
    this.mode    = "feature";
    this.feedid = $(elem).attr('feedid');
    this.href   = $(elem).attr('hrefaction');
    this.catid  = $(elem).attr('catid');
    this.catstate = $(elem).attr('cat-state');
    this.state  = $(elem).attr('state');
    this.feeds = {feedid: this.feedid};
    this.identifier = $(elem).attr('class');
}
FeatureStateObject.prototype = new InboxStateObject();

function RemoveStateObject(elem) {
    InboxStateObject.apply(this, arguments);
    this.elem = elem;
    this.message = "Feedback has been " + "deleted";
    this.mode    = "delete";
    this.feedid = $(elem).attr('feedid');
    this.href   = $(elem).attr('hrefaction');
    this.catid  = $(elem).attr('catid');
    this.catstate = $(elem).attr('cat-state');
    this.state  = $(elem).attr('state');
    this.feeds = {feedid: this.feedid};
    this.identifier = $(elem).attr('class');
}
RemoveStateObject.prototype = new InboxStateObject();

function CatPickObject(elem) {
    InboxStateObject.apply(this, arguments);
    this.elem = elem;
    this.catstate = $(elem).attr('cat-state');
    if(this.catstate == 'default') {
        this.message = "Feedback has been sent to " + "Inbox";
    } else {
        this.message = "Feedback has been sent to " + "Filed Feedback";
    }
    this.mode    = "fileas";
    $(elem).parents('div.category-picker-holder').hide();
    this.feedid = $(elem).attr('feedid');
    this.href   = $(elem).attr('hrefaction');
    this.catid  = $(elem).attr('catid');
    this.catstate = $(elem).attr('cat-state');
    this.state  = $(elem).attr('state');
    this.feeds = {feedid: this.feedid};
    this.identifier = $(elem).attr('class');
}

CatPickObject.prototype = new InboxStateObject();
CatPickObject.prototype.process = function() {
    var me = this;
    if(location.pathname.match(/filed|modifyfeedback/)) {
        $.ajax({ type: "POST", url: me.href, data: {"mode": me.mode ,"feed_ids": [me.feeds], "cat_id": me.catid, "catstate": me.catstate }, success: function() {
            if(me.catstate == "default") {
                $(me.elem).parents('.feedback').fadeOut(350);
            }
            var myStatus = new Status();
            myStatus.notify("Processing...", 1000);
        }});
    } else {
        $(this.elem).parents('.feedback').fadeOut(350, function() {
            var undo       = " Undo";
            var close_checky = "  Close";
            var notify_msg = me.message + undo + close_checky;
            var notify     = $('
').addClass(me.identifier).html(notify_msg);
            var checky = $('.checky-bar');

            if(me.state == 0) {
                $.ajax({ type: "POST", url: me.href, data: {"mode": me.mode ,"feed_ids": [me.feeds], "cat_id": me.catid, "catstate": me.catstate }, success: function()
                    {

                        var myStatus = new Status();
                        myStatus.notify("Processing...", 1000);
                        checky.html(notify).show();
                    }
                });
            } else {
                //if state is 1 then we're going back to the inbox
                $.ajax({ type: "POST", url: me.href, data: {"mode": "inbox" ,"feed_ids": [me.feeds], "cat_id": me.catid }, success: function()
                    {

                        var myStatus = new Status();
                        myStatus.notify("Processing...", 1000);
                        checky.html("
Feedback has been sent to the " + "Inbox " + undo + close_checky +"
")
                        .show();
                    }
                });
            }
        });

    }

    $(document).delegate('a.close-checky', 'click', function(e) {
        $(this).parents('.check').remove();
        e.preventDefault();
    })
}

//Factory
function InboxStatusChange(opts)  {
    this.inbox_controls = opts;
}

InboxStatusChange.prototype.initialize = function() {
    var me = this;
    $(document).delegate(me.inbox_controls, 'click', function(e) {
        var identifier = $(this).attr('class');
        var us = $(this);

        $.ajax({url: "/feedback/bust_hostfeed_data"});

        if(identifier == 'check') {
            var check = new PublishStateObject(us);
            check.process();
            check.undo();
        }

        if(identifier == 'feature') {
            var feature = new FeatureStateObject(us);
            feature.process();
            feature.undo();
        }

        if(identifier == 'remove' || identifier == 'popup-delete') {
            var remove = new RemoveStateObject(us);
            remove.process();
            remove.undo();
        }

    })
}
<|endoftext|>