<commit_before>#!/usr/bin/env node

var stdout = process.stdout,
    fs = require('fs'),
    spawn = require('child_process').spawn,
    package = require('./package.json');

// Start Configuration

var opts = require('nomnom')
      .option('profile', {
        position: 0,
        required: true,
        help: "Chrome CPU profile (JSON file)"
      }).option('output', {
        abbr: 'o',
        default: 'out.gif',
        help: "Output image file"
      }).option('format', {
        abbr: 'f',
        default: 'gif',
        help: "Output image format (passed to dot)\n" +
          "\tsee www.graphviz.org/doc/info/output.html)"
      }).option('pruneDepth', {
        abbr: 'p',
        default: 0,
        help: "Depth at which to prune functions whose callees hit count is less or equal to sampleLimit"
      }).option('sampleLimit', {
        abbr: 's',
        default: '10',
        help: "Number of samples required for inclusion in the call tree"
      }).option('maxLabelLength', {
        abbr: 'l',
        default: 30,
        help: "Maximum length of a vertex label (derived from function name)"
      }).option('treeDirection', {
        abbr: 't',
        default: 'TD',
        help: "Digraph direction, TD (Top-Down) or LR (Left-Right)"
      }).option('vertexStyle', {
        abbr: 'v',
        default: 'ellipse',
        help: "Vertex style, e.g. ellipse or box, see http://www.graphviz.org/content/node-shapes"
      }).option('debug', {
        flag: true,
        help: "Output the generated dot file to stdout"
      }).option('version', {
        abbr: 'v',
        flag: true,
        callback: function() {
          return "Version " + package.version;
        }
      }).parse();

var pruneDepth = opts.pruneDepth,
    sampleLimit = opts.sampleLimit,
    nameLimit = opts.maxLabelLength;
// End Configuration

// Start Stats collection
var profile = JSON.parse(fs.readFileSync(opts.profile));
var totalHitcount = profile.samples.length;

console.log("Found " + totalHitcount + " samples");

// Calculate the cumulative hitcount for all nodes
// Do any pruning while we're at it
console.log("Calculating callee hit counts:");
var pruned = calculateCumulativeHitcount(profile.head, 0);
console.log("\tPruned " + pruned + " small nodes");
console.log("\tComplete");
// End stats collection

// Start Dot Generation
console.log("Generating dot file:");

// Generate the dot header with required options
var dotFile = "digraph cpuprofile {\n";
dotFile += "  node [shape=" + opts.style + "];";
dotFile += "  rankdir=" + opts.treeDirection + ";";
writeGraph(profile.head);
dotFile += "}";

console.log("\tComplete");
// End Dot Generation

if(opts.debug) {
  console.log(dotFile);
}

// Generate output file with dot
console.log("Generating output file:");
var dot = spawn('dot', ['-T' + opts.format, "-o", opts.output]);
dot.stdin.write(dotFile);
dot.stdin.end();

dot.on('close', function(code) {
  if(code === 0) {
    console.log("\tComplete");
  } else {
    console.log("\tFailed (" + code + ")");
  }
});

// Helper to write a DOT vertex with label
function writeVertex(id, label) {
  var color = "Blue";
  if(label === '(anonymous function)') {
    color = "Black";
  }

  if(label.length > nameLimit) {
    label = label.substring(0, nameLimit);
  }

  dotFile += "  " + id + " [label=\"" + label + "\" color=" + color + "]\n";
}

// Helper to write a DOT edge with label
function writeEdge(vertexA, vertexB, label) {
    dotFile += "  " + vertexA + " -> " + vertexB + "[label=\"" + label + "\"]\n";
}

function calculateCumulativeHitcount(node, level) {
  var pruned = 0;

  node.childHitcount = node.hitCount;

  // Use a reverse for loop so we can splice
  for(var i=node.children.length-1; i>=0; --i) {
    var child = node.children[i];

    pruned += calculateCumulativeHitcount(child, level + 1);

    node.childHitcount += child.childHitcount;

    if(child.childHitcount < sampleLimit && level >= pruneDepth) {
      node.children.splice(i, 1);
      pruned++;
    } else if (child.functionName === '(idle)' || child.functionName === '(program)') {
      node.children.splice(i, 1);
      totalHitcount -= child.hitCount;
      console.log("\tPruning " + child.hitCount + " samples for " + child.functionName + "");
    }
  };

  return pruned;
}

function writeGraph(node) {
  writeVertex(node.id, node.functionName);

  node.children.forEach(function(child) {
    writeGraph(child);
    writeEdge(node.id, child.id, Math.floor(((child.childHitcount / totalHitcount) * 1000))/10 + "% (" + child.childHitcount + ")");
  });
}
<commit_msg>Fixed conflicting options. Added some more whitespace to output dotfile.<commit_after>#!/usr/bin/env node

var stdout = process.stdout,
    fs = require('fs'),
    spawn = require('child_process').spawn,
    package = require('./package.json');

// Start Configuration

var opts = require('nomnom')
      .option('profile', {
        position: 0,
        required: true,
        help: "Chrome CPU profile (JSON file)"
      }).option('output', {
        abbr: 'o',
        default: 'out.gif',
        help: "Output image file"
      }).option('format', {
        abbr: 'f',
        default: 'gif',
        help: "Output image format (passed to dot)\n" +
          "\tsee www.graphviz.org/doc/info/output.html)"
      }).option('pruneDepth', {
        abbr: 'p',
        default: 0,
        help: "Depth at which to prune functions whose callees hit count is less or equal to sampleLimit"
      }).option('sampleLimit', {
        abbr: 's',
        default: '10',
        help: "Number of samples required for inclusion in the call tree"
      }).option('maxLabelLength', {
        abbr: 'l',
        default: 30,
        help: "Maximum length of a vertex label (derived from function name)"
      }).option('treeDirection', {
        abbr: 't',
        default: 'TD',
        help: "Digraph direction, TD (Top-Down) or LR (Left-Right)"
      }).option('vertexStyle', {
        abbr: 'v',
        default: 'ellipse',
        help: "Vertex style, e.g. ellipse or box, see http://www.graphviz.org/content/node-shapes"
      }).option('debug', {
        flag: true,
        help: "Output the generated dot file to stdout"
      }).option('version', {
        flag: true,
        callback: function() {
          return "Version " + package.version;
        }
      }).parse();

var pruneDepth = opts.pruneDepth,
    sampleLimit = opts.sampleLimit,
    nameLimit = opts.maxLabelLength;
// End Configuration

// Start Stats collection
var profile = JSON.parse(fs.readFileSync(opts.profile));
var totalHitcount = profile.samples.length;

console.log("Found " + totalHitcount + " samples");

// Calculate the cumulative hitcount for all nodes
// Do any pruning while we're at it
console.log("Calculating callee hit counts:");
var pruned = calculateCumulativeHitcount(profile.head, 0);
console.log("\tPruned " + pruned + " small nodes");
console.log("\tComplete");
// End stats collection

// Start Dot Generation
console.log("Generating dot file:");

// Generate the dot header with required options
var dotFile = "digraph cpuprofile {\n";
dotFile += "  node [shape=" + opts.vertexStyle + "];\n";
dotFile += "  rankdir=" + opts.treeDirection + ";\n";
writeGraph(profile.head);
dotFile += "}";

console.log("\tComplete");
// End Dot Generation

if(opts.debug) {
  console.log(dotFile);
}

// Generate output file with dot
console.log("Generating output file:");
var dot = spawn('dot', ['-T' + opts.format, "-o", opts.output]);
dot.stdin.write(dotFile);
dot.stdin.end();

dot.on('close', function(code) {
  if(code === 0) {
    console.log("\tComplete");
  } else {
    console.log("\tFailed (" + code + ")");
  }
});

// Helper to write a DOT vertex with label
function writeVertex(id, label) {
  var color = "Blue";
  if(label === '(anonymous function)') {
    color = "Black";
  }

  if(label.length > nameLimit) {
    label = label.substring(0, nameLimit);
  }

  dotFile += "  " + id + " [label=\"" + label + "\" color=" + color + "]\n";
}

// Helper to write a DOT edge with label
function writeEdge(vertexA, vertexB, label) {
    dotFile += "  " + vertexA + " -> " + vertexB + "[label=\"" + label + "\"]\n";
}

function calculateCumulativeHitcount(node, level) {
  var pruned = 0;

  node.childHitcount = node.hitCount;

  // Use a reverse for loop so we can splice
  for(var i=node.children.length-1; i>=0; --i) {
    var child = node.children[i];

    pruned += calculateCumulativeHitcount(child, level + 1);

    node.childHitcount += child.childHitcount;

    if(child.childHitcount < sampleLimit && level >= pruneDepth) {
      node.children.splice(i, 1);
      pruned++;
    } else if (child.functionName === '(idle)' || child.functionName === '(program)') {
      node.children.splice(i, 1);
      totalHitcount -= child.hitCount;
      console.log("\tPruning " + child.hitCount + " samples for " + child.functionName + "");
    }
  };

  return pruned;
}

function writeGraph(node) {
  writeVertex(node.id, node.functionName);

  node.children.forEach(function(child) {
    writeGraph(child);
    writeEdge(node.id, child.id, Math.floor(((child.childHitcount / totalHitcount) * 1000))/10 + "% (" + child.childHitcount + ")");
  });
}
<|endoftext|>


<commit_before>"use strict";

treeherder.controller('PinboardCtrl', [
    '$scope', '$rootScope', '$document', '$timeout','thEvents', 'thPinboard', 'thNotify', 'ThLog',
    function PinboardCtrl(
        $scope, $rootScope, $document, $timeout, thEvents, thPinboard, thNotify, ThLog) {

        var $log = new ThLog(this.constructor.name);

        $rootScope.$on(thEvents.toggleJobPin, function(event, job) {
            $scope.toggleJobPin(job);
            if (!$scope.$$phase){
                $scope.$digest();
            }
        });

        $rootScope.$on(thEvents.jobPin, function(event, job) {
            $scope.pinJob(job);
            if (!$scope.$$phase){
                $scope.$digest();
            }
        });

        $rootScope.$on(thEvents.addRelatedBug, function(event, job) {
            $scope.pinJob(job);
            $scope.toggleEnterBugNumber(true);
        });

        $rootScope.$on(thEvents.saveClassification, function() {
            if ($scope.isPinboardVisible) {
                $scope.save();
            }
        });

        $rootScope.$on(thEvents.clearPinboard, function() {
            if ($scope.isPinboardVisible) {
                $scope.unPinAll();
            }
        });

        $scope.toggleJobPin = function(job) {
            thPinboard.toggleJobPin(job);
            if (!$scope.selectedJob) {
                $scope.viewJob(job);
            }
        };

        $scope.pulsePinCount = function() {
            $( ".pin-count-group" ).addClass( "pin-count-pulse" );
            $timeout(function() {
                $( ".pin-count-group" ).removeClass( "pin-count-pulse" );
            }, 700);
        };

        // Triggered on pin api events eg. from the job details navbar
        $rootScope.$on(thEvents.pulsePinCount, function() {
            $scope.pulsePinCount();
        });

        $scope.pinJob = function(job) {
            thPinboard.pinJob(job);
            if (!$scope.selectedJob) {
                $scope.viewJob(job);
            }
            $scope.pulsePinCount();
        };

        $scope.unPinJob = function(id) {
            thPinboard.unPinJob(id);
        };

        $scope.addBug = function(bug) {
            thPinboard.addBug(bug);
        };

        $scope.removeBug = function(id) {
            thPinboard.removeBug(id);
        };

        $scope.unPinAll = function() {
            thPinboard.unPinAll();
            $scope.classification = thPinboard.createNewClassification();
        };

        $scope.save = function() {
            var errorFree = true;
            if ($scope.enteringBugNumber) {
                // we should save this for the user, as they likely
                // just forgot to hit enter. Returns false if invalid
                errorFree = $scope.saveEnteredBugNumber();
                if (!errorFree) {
                    thNotify.send("Please enter a valid bug number", "danger");
                }
            }
            if (!$scope.canSaveClassifications()) {
                thNotify.send("Please classify this failure before saving", "danger");
                errorFree = false;
            }
            if (!$scope.user.loggedin) {
                thNotify.send("Must be logged in to save job classifications", "danger");
                errorFree = false;
            }
            if (errorFree) {
                $scope.classification.who = $scope.user.email;
                var classification = $scope.classification;
                thPinboard.save(classification);
                $scope.completeClassification();
                $scope.classification = thPinboard.createNewClassification();

                // HACK: it looks like Firefox on Linux and Windows doesn't
                // want to accept keyboard input after this change for some
                // reason which I don't understand. Chrome (any platform)
                // or Firefox on Mac works fine though.
                document.activeElement.blur();
            }
        };

        $scope.saveClassificationOnly = function() {
            if ($scope.user.loggedin) {
                $scope.classification.who = $scope.user.email;
                thPinboard.saveClassificationOnly($scope.classification);
            } else {
                thNotify.send("Must be logged in to save job classifications", "danger");
            }
        };

        $scope.saveBugsOnly = function() {
            if ($scope.user.loggedin) {
                thPinboard.saveBugsOnly();
            } else {
                thNotify.send("Must be logged in to save job classifications", "danger");
            }
        };

        $scope.retriggerAllPinnedJobs = function() {
            // pushing pinned jobs to a list.
            $scope.retriggerJob(_.values($scope.pinnedJobs));
        };

        $scope.cancelAllPinnedJobsTitle = function() {
            if (!$scope.user.loggedin) {
                return "Not logged in";
            } else if (!$scope.canCancelAllPinnedJobs()) {
                return "No pending / running jobs in pinboard";
            }

            return "Cancel all the pinned jobs";
        };

        $scope.canCancelAllPinnedJobs = function() {
            var cancellableJobs = _.values($scope.pinnedJobs).filter(
                job => (job.state === 'pending' || job.state === 'running'));
            return $scope.user.loggedin && cancellableJobs.length > 0;
        };

        $scope.cancelAllPinnedJobs = function() {
            if (window.confirm('This will cancel all the selected jobs. Are you sure?')) {
                $scope.cancelJobs(_.values($scope.pinnedJobs));
            }
        };

        $scope.canSaveClassifications = function() {
            var thisClass = $scope.classification;
            return $scope.hasPinnedJobs() && $scope.user.loggedin &&
                   (thPinboard.hasRelatedBugs() ||
                   (thisClass.failure_classification_id !== 4 && thisClass.failure_classification_id !== 2) ||
                   $rootScope.currentRepo.repository_group.name === "try" ||
                   $rootScope.currentRepo.repository_group.name === "project repositories" ||
                   (thisClass.failure_classification_id === 4 && thisClass.text.length > 0) ||
                   (thisClass.failure_classification_id === 2 && thisClass.text.length > 7));
        };

        // Dynamic btn/anchor title for classification save
        $scope.saveUITitle = function(category) {
            var title = "";

            if (!$scope.user.loggedin) {
                title = title.concat("not logged in / ");
            }

            if (category === "classification") {
                if (!$scope.canSaveClassifications()) {
                    title = title.concat("ineligible classification data / ");
                }
                if (!$scope.hasPinnedJobs()) {
                    title = title.concat("no pinned jobs");
                }
            // We don't check pinned jobs because the menu dropdown handles it
            } else if (category === "bug") {
                if (!$scope.hasRelatedBugs()) {
                    title = title.concat("no related bugs");
                }
            }

            if (title === "") {
                title = "Save " + category + " data";
            } else {
                // Cut off trailing "/ " if one exists, capitalize first letter
                title = title.replace(/\/ $/,"");
                title = title.replace(/^./, function(l) { return l.toUpperCase(); });
            }

            return title;
        };

        $scope.hasPinnedJobs = function() {
            return thPinboard.hasPinnedJobs();
        };

        $scope.hasRelatedBugs = function() {
            return thPinboard.hasRelatedBugs();
        };

        function handleRelatedBugDocumentClick(event) {
            if (!$(event.target).hasClass("add-related-bugs-input")) {
                $scope.$apply(function() {
                    $scope.toggleEnterBugNumber(false);
                });
            }
        }

        $scope.toggleEnterBugNumber = function(tf) {
            $scope.enteringBugNumber = tf;
            $scope.focusInput = tf;

            $document.off('click', handleRelatedBugDocumentClick);
            if (tf) {
                // Rebind escape to canceling the bug entry, pressing escape
                // again will close the pinboard as usual.
                Mousetrap.bind('escape', function() {
                    var cancel = _.bind($scope.toggleEnterBugNumber, $scope, false);
                    $scope.$evalAsync(cancel);
                });

                // Install a click handler on the document so that clicking
                // outside of the input field will close it. A blur handler
                // can't be used because it would have timing issues with the
                // click handler on the + icon.
                $timeout(function() {
                    $document.on('click', handleRelatedBugDocumentClick);
                }, 0);
            } else {
                $scope.newEnteredBugNumber = '';
            }
        };

        $scope.completeClassification = function() {
            $rootScope.$broadcast('blur-this', "classification-comment");
        };

        $scope.saveEnteredBugNumber = function() {
            if ($scope.enteringBugNumber) {
                if (!$scope.newEnteredBugNumber) {
                    $scope.toggleEnterBugNumber(false);
                } else if (/^[0-9]*$/.test($scope.newEnteredBugNumber)) {
                    $log.debug("new bug number to be saved: ",
                               $scope.newEnteredBugNumber);
                    thPinboard.addBug({id:$scope.newEnteredBugNumber});
                    $scope.toggleEnterBugNumber(false);
                    return true;
                }
            }
        };

        $scope.viewJob = function(job) {
            $rootScope.selectedJob = job;
            $rootScope.$emit(thEvents.jobClick, job);
            $rootScope.$emit(thEvents.selectJob, job);
        };

        $scope.classification = thPinboard.createNewClassification();
        $scope.pinnedJobs = thPinboard.pinnedJobs;
        $scope.relatedBugs = thPinboard.relatedBugs;
    }
]);
<commit_msg>Bug 1196142 - Auto-save pinboard's bug entry on blur (#2329) r=camd<commit_after>"use strict";

treeherder.controller('PinboardCtrl', [
    '$scope', '$rootScope', '$document', '$timeout','thEvents', 'thPinboard', 'thNotify', 'ThLog',
    function PinboardCtrl(
        $scope, $rootScope, $document, $timeout, thEvents, thPinboard, thNotify, ThLog) {

        var $log = new ThLog(this.constructor.name);

        $rootScope.$on(thEvents.toggleJobPin, function(event, job) {
            $scope.toggleJobPin(job);
            if (!$scope.$$phase){
                $scope.$digest();
            }
        });

        $rootScope.$on(thEvents.jobPin, function(event, job) {
            $scope.pinJob(job);
            if (!$scope.$$phase){
                $scope.$digest();
            }
        });

        $rootScope.$on(thEvents.addRelatedBug, function(event, job) {
            $scope.pinJob(job);
            $scope.toggleEnterBugNumber(true);
        });

        $rootScope.$on(thEvents.saveClassification, function() {
            if ($scope.isPinboardVisible) {
                $scope.save();
            }
        });

        $rootScope.$on(thEvents.clearPinboard, function() {
            if ($scope.isPinboardVisible) {
                $scope.unPinAll();
            }
        });

        $scope.toggleJobPin = function(job) {
            thPinboard.toggleJobPin(job);
            if (!$scope.selectedJob) {
                $scope.viewJob(job);
            }
        };

        $scope.pulsePinCount = function() {
            $( ".pin-count-group" ).addClass( "pin-count-pulse" );
            $timeout(function() {
                $( ".pin-count-group" ).removeClass( "pin-count-pulse" );
            }, 700);
        };

        // Triggered on pin api events eg. from the job details navbar
        $rootScope.$on(thEvents.pulsePinCount, function() {
            $scope.pulsePinCount();
        });

        $scope.pinJob = function(job) {
            thPinboard.pinJob(job);
            if (!$scope.selectedJob) {
                $scope.viewJob(job);
            }
            $scope.pulsePinCount();
        };

        $scope.unPinJob = function(id) {
            thPinboard.unPinJob(id);
        };

        $scope.addBug = function(bug) {
            thPinboard.addBug(bug);
        };

        $scope.removeBug = function(id) {
            thPinboard.removeBug(id);
        };

        $scope.unPinAll = function() {
            thPinboard.unPinAll();
            $scope.classification = thPinboard.createNewClassification();
        };

        $scope.save = function() {
            var errorFree = true;
            if ($scope.enteringBugNumber) {
                // we should save this for the user, as they likely
                // just forgot to hit enter. Returns false if invalid
                errorFree = $scope.saveEnteredBugNumber();
                if (!errorFree) {
                    thNotify.send("Please enter a valid bug number", "danger");
                }
            }
            if (!$scope.canSaveClassifications()) {
                thNotify.send("Please classify this failure before saving", "danger");
                errorFree = false;
            }
            if (!$scope.user.loggedin) {
                thNotify.send("Must be logged in to save job classifications", "danger");
                errorFree = false;
            }
            if (errorFree) {
                $scope.classification.who = $scope.user.email;
                var classification = $scope.classification;
                thPinboard.save(classification);
                $scope.completeClassification();
                $scope.classification = thPinboard.createNewClassification();

                // HACK: it looks like Firefox on Linux and Windows doesn't
                // want to accept keyboard input after this change for some
                // reason which I don't understand. Chrome (any platform)
                // or Firefox on Mac works fine though.
                document.activeElement.blur();
            }
        };

        $scope.saveClassificationOnly = function() {
            if ($scope.user.loggedin) {
                $scope.classification.who = $scope.user.email;
                thPinboard.saveClassificationOnly($scope.classification);
            } else {
                thNotify.send("Must be logged in to save job classifications", "danger");
            }
        };

        $scope.saveBugsOnly = function() {
            if ($scope.user.loggedin) {
                thPinboard.saveBugsOnly();
            } else {
                thNotify.send("Must be logged in to save job classifications", "danger");
            }
        };

        $scope.retriggerAllPinnedJobs = function() {
            // pushing pinned jobs to a list.
            $scope.retriggerJob(_.values($scope.pinnedJobs));
        };

        $scope.cancelAllPinnedJobsTitle = function() {
            if (!$scope.user.loggedin) {
                return "Not logged in";
            } else if (!$scope.canCancelAllPinnedJobs()) {
                return "No pending / running jobs in pinboard";
            }

            return "Cancel all the pinned jobs";
        };

        $scope.canCancelAllPinnedJobs = function() {
            var cancellableJobs = _.values($scope.pinnedJobs).filter(
                job => (job.state === 'pending' || job.state === 'running'));
            return $scope.user.loggedin && cancellableJobs.length > 0;
        };

        $scope.cancelAllPinnedJobs = function() {
            if (window.confirm('This will cancel all the selected jobs. Are you sure?')) {
                $scope.cancelJobs(_.values($scope.pinnedJobs));
            }
        };

        $scope.canSaveClassifications = function() {
            var thisClass = $scope.classification;
            return $scope.hasPinnedJobs() && $scope.user.loggedin &&
                   (thPinboard.hasRelatedBugs() ||
                   (thisClass.failure_classification_id !== 4 && thisClass.failure_classification_id !== 2) ||
                   $rootScope.currentRepo.repository_group.name === "try" ||
                   $rootScope.currentRepo.repository_group.name === "project repositories" ||
                   (thisClass.failure_classification_id === 4 && thisClass.text.length > 0) ||
                   (thisClass.failure_classification_id === 2 && thisClass.text.length > 7));
        };

        // Dynamic btn/anchor title for classification save
        $scope.saveUITitle = function(category) {
            var title = "";

            if (!$scope.user.loggedin) {
                title = title.concat("not logged in / ");
            }

            if (category === "classification") {
                if (!$scope.canSaveClassifications()) {
                    title = title.concat("ineligible classification data / ");
                }
                if (!$scope.hasPinnedJobs()) {
                    title = title.concat("no pinned jobs");
                }
            // We don't check pinned jobs because the menu dropdown handles it
            } else if (category === "bug") {
                if (!$scope.hasRelatedBugs()) {
                    title = title.concat("no related bugs");
                }
            }

            if (title === "") {
                title = "Save " + category + " data";
            } else {
                // Cut off trailing "/ " if one exists, capitalize first letter
                title = title.replace(/\/ $/,"");
                title = title.replace(/^./, function(l) { return l.toUpperCase(); });
            }

            return title;
        };

        $scope.hasPinnedJobs = function() {
            return thPinboard.hasPinnedJobs();
        };

        $scope.hasRelatedBugs = function() {
            return thPinboard.hasRelatedBugs();
        };

        function handleRelatedBugDocumentClick(event) {
            if (!$(event.target).hasClass("add-related-bugs-input")) {
                $scope.$apply(function() {
                    if ($scope.newEnteredBugNumber) {
                        $scope.saveEnteredBugNumber();
                    } else {
                        $scope.toggleEnterBugNumber(false);
                    }
                });
            }
        }

        $scope.toggleEnterBugNumber = function(tf) {
            $scope.enteringBugNumber = tf;
            $scope.focusInput = tf;

            $document.off('click', handleRelatedBugDocumentClick);
            if (tf) {
                // Rebind escape to canceling the bug entry, pressing escape
                // again will close the pinboard as usual.
                Mousetrap.bind('escape', function() {
                    var cancel = _.bind($scope.toggleEnterBugNumber, $scope, false);
                    $scope.$evalAsync(cancel);
                });

                // Install a click handler on the document so that clicking
                // outside of the input field will close it. A blur handler
                // can't be used because it would have timing issues with the
                // click handler on the + icon.
                $timeout(function() {
                    $document.on('click', handleRelatedBugDocumentClick);
                }, 0);
            } else {
                $scope.newEnteredBugNumber = '';
            }
        };

        $scope.completeClassification = function() {
            $rootScope.$broadcast('blur-this', "classification-comment");
        };

        $scope.saveEnteredBugNumber = function() {
            if ($scope.enteringBugNumber) {
                if (!$scope.newEnteredBugNumber) {
                    $scope.toggleEnterBugNumber(false);
                } else if (/^[0-9]*$/.test($scope.newEnteredBugNumber)) {
                    $log.debug("new bug number to be saved: ",
                               $scope.newEnteredBugNumber);
                    thPinboard.addBug({id:$scope.newEnteredBugNumber});
                    $scope.toggleEnterBugNumber(false);
                    return true;
                }
            }
        };

        $scope.viewJob = function(job) {
            $rootScope.selectedJob = job;
            $rootScope.$emit(thEvents.jobClick, job);
            $rootScope.$emit(thEvents.selectJob, job);
        };

        $scope.classification = thPinboard.createNewClassification();
        $scope.pinnedJobs = thPinboard.pinnedJobs;
        $scope.relatedBugs = thPinboard.relatedBugs;
    }
]);
<|endoftext|>


<commit_before>/**
 * Created by yangm11 on 8/9/2018.
 */
'use strict';

class DataTable {
  constructor(arr, targetId) {
    if (!Array.isArray(arr)) {
      throw new Error('an array of objects expected');
    }
    if (Object.prototype.toString.call(arr[0]) !== '[object Object]') {
      throw new Error('an array of objects expected');
    }
    if (typeof window === 'undefined') {
      throw new Error('Data Table only works in browser');
    }
    this._originalData = arr;
    this._data = arr.slice();
    this._targetId = targetId;
    this._rowsPerPage = 10;
    this._pageNumber = 1;
    this._changePageByUser = true;
  }
  setColumnNames(names) {
    if (typeof names === 'undefined') {
      let res = new Set();
      for (let d of this._data) {
        let keys = Object.keys(d);
        for (let key of keys) {
          res.add(key);
        }
      }
      this._colNames = [...res];
    } else if (Array.isArray(names)) {
      this._colNames = names;
    } else {
      throw new Error('an array of name strings expected');
    }
  }

  // page number starts from 1
  setPageNumber(n) {
    if (typeof n !== 'number' || n < 0) {
      throw new Error('a natural number expected');
    }
    this._pageNumber = n;
  }
  setRowsPerPage(n) {
    if (typeof n !== 'number' || n < 0) {
      throw new Error('a natural number expected');
    }
    this._rowsPerPage = n;
  }

  static convertToString(d) {
    switch (typeof d) {
      case 'number':
        return d + '';
      case 'string':
        return d;
      case 'object':
        if (Array.isArray(d)) {
          return d.join(', ');
        } else if (d === null) {
          return 'null';
        } else {
          return JSON.stringify(d);
        }
      case 'bool':
        return d + '';
      default:
        return 'null';
    }
  }

  // if descending is omitted,
  sort(col, descending) {
    this._data.sort((x, y) => {
      if (descending) {
        return x[col] < y[col] ? 1 : -1;
      } else {
        return x[col] < y[col] ? -1 : 1;
      }
    });
  }

  updateDataToShow() {
    let res = [];
    let start = (this._pageNumber - 1) * this._rowsPerPage;
    for (let i = 0; i < this._rowsPerPage && start + i < this._data.length; i++) {
      res.push(this._data[start+i]);
    }
    this._dataToShow = res;
  }

  updateTableView() {
    this.updateDataToShow();
    if (typeof this._targetId !== 'string' || !this._targetId) {
      throw new Error('an element id expected');
    }
    let table = document.getElementById(this._targetId + '-table-section');
    if (!table) {
      throw new Error('failed to locate the table');
    }
    while (table.lastChild) {
      table.removeChild(table.lastChild);
    }

    if (!this._colNames) {
      this.setColumnNames();
    }
    let df = document.createDocumentFragment();
    let head = df.appendChild(document.createElement('thead'))
    .appendChild(document.createElement('tr'));
    for (let name of this._colNames) {
      let th = head.appendChild(document.createElement('th'));
      th.appendChild(document.createTextNode(name));
      let control = th.appendChild(document.createElement('div'));
      control.classList.add(this._targetId + '-control');
      control._colName = name;
      let up = control.appendChild(document.createElement('i'));
      up.classList.add('data-table-up-control');
      up._colName = name;
      let down = control.appendChild(document.createElement('i'));
      down.classList.add('data-table-down-control');
      down._colName = name;
    }
    let tbody = df.appendChild(document.createElement('tbody'));
    for (let row of this._dataToShow) {
      let th = tbody.appendChild(document.createElement('tr'));
      for (let name of this._colNames) {
        th.appendChild(document.createElement('td')).innerText = DataTable.convertToString(row[name]);
      }
    }
    table.appendChild(df);
  }
  generate() {
    // replace the table with a div element
    let target = document.getElementById(this._targetId);
    let div = document.createElement('div');
    target.parentNode.insertBefore(div, target);
    target.parentNode.removeChild(target);
    div.id = this._targetId;

    // create the contents of the new object
    let container = document.createDocumentFragment();
    let filterSection = container.appendChild(document.createElement('div'));
    filterSection.id = this._targetId + '-filter-section';

    let vizSection = container.appendChild(document.createElement('div'));
    vizSection.id = this._targetId + '-visualization-section';

    let table = container.appendChild(document.createElement('table'));
    table.id = this._targetId + '-table-section';

    let pager = container.appendChild(document.createElement('div'));
    pager.id = this._targetId + '-pager-section';
    let a = pager.appendChild(document.createElement('div'));
    a.appendChild(document.createElement('span'))
    .appendChild(document.createTextNode('Items per Page'));
    let num = a.appendChild(document.createElement('select'));
    num.classList.add('data-table-row-number-selector');
    for (let i of [5, 10, 20, 50, 100]) {
      num.appendChild(document.createElement('option'))
      .appendChild(document.createTextNode(i));
    }
    num.value = 10;

    let b = pager.appendChild(document.createElement('div'));
    b.appendChild(document.createElement('span'))
    .appendChild(document.createTextNode('Select Page'));
    let pages = b.appendChild(document.createElement('select'));
    pages.classList.add('data-table-pages-selector');

    let totalPages = Math.ceil(this._data.length / this._rowsPerPage);
    for (let i = 1; i <= totalPages; i++) {
      pages.appendChild(document.createElement('option'))
          .appendChild(document.createTextNode(i));
    }

    // add the df to div
    div.appendChild(container);
    this.attachListeners();
  }
  attachListeners() {
    let that = this;
    let table = document.getElementById(this._targetId + '-table-section');
    if (!table) {
      throw new Error('failed to locate the table');
    }
    table.addEventListener('click', function (evt) {
      if (evt.target.classList.contains('data-table-up-control')) {
        let col = evt.target._colName;
        that.sort(col, false);
      } else if (evt.target.classList.contains('data-table-down-control')) {
        let col = evt.target._colName;
        that.sort(col, true);
      }
      that.updateTableView();
    });
    let pager = document.getElementById(this._targetId + '-pager-section');
    let selects = pager.getElementsByTagName('select');
    selects[0].addEventListener('change', function () {
      // update table view
      that.setRowsPerPage(+this.value);
      that.setPageNumber(1);
      that.updateTableView();

      // update pager
      let totalPages = Math.ceil(that._data.length / that._rowsPerPage);
      while (selects[1].lastChild) {
        selects[1].removeChild(selects[1].lastChild);
      }
      for (let i = 1; i <= totalPages; i++) {
        selects[1].appendChild(document.createElement('option'))
        .appendChild(document.createTextNode(i));
      }
      selects[1].value = 1;
      that._changePageByUser = false;
      setTimeout(function () {
        that._changePageByUser = true;
      }, 1000);
    });
    selects[1].addEventListener('change', function () {
      if (that._changePageByUser) {
        that.setPageNumber(+this.value);
        that.updateTableView();
      }
    });
  }
}

if (typeof module !== 'undefined' && module.parent) {

} else {
  // test code go here
}
<commit_msg>updates<commit_after>/**
 * Created by yangm11 on 8/9/2018.
 */
'use strict';

class DataTable {
  constructor(arr, targetId) {
    if (!Array.isArray(arr)) {
      throw new Error('an array of objects expected');
    }
    if (Object.prototype.toString.call(arr[0]) !== '[object Object]') {
      throw new Error('an array of objects expected');
    }
    if (typeof window === 'undefined') {
      throw new Error('Data Table only works in browser');
    }
    this._originalData = arr;
    this._data = arr.slice();
    this._targetId = targetId;
    this._rowsPerPage = 10;
    this._pageNumber = 1;
    this._changePageByUser = true;
  }
  setColumnNames(names) {
    if (typeof names === 'undefined') {
      let res = new Set();
      for (let d of this._data) {
        let keys = Object.keys(d);
        for (let key of keys) {
          res.add(key);
        }
      }
      this._colNames = [...res];
    } else if (Array.isArray(names)) {
      this._colNames = names;
    } else {
      throw new Error('an array of name strings expected');
    }
  }

  // page number starts from 1
  setPageNumber(n) {
    if (typeof n !== 'number' || n < 0) {
      throw new Error('a natural number expected');
    }
    this._pageNumber = n;
  }
  setRowsPerPage(n) {
    if (typeof n !== 'number' || n < 0) {
      throw new Error('a natural number expected');
    }
    this._rowsPerPage = n;
  }

  static convertToString(d) {
    switch (typeof d) {
      case 'number':
        return d + '';
      case 'string':
        return d;
      case 'object':
        if (Array.isArray(d)) {
          return d.join(', ');
        } else if (d === null) {
          return 'null';
        } else {
          return JSON.stringify(d);
        }
      case 'bool':
        return d + '';
      default:
        return 'null';
    }
  }

  // if descending is omitted,
  sort(col, descending) {
    this._data.sort((x, y) => {
      if (descending) {
        return x[col] < y[col] ? 1 : -1;
      } else {
        return x[col] < y[col] ? -1 : 1;
      }
    });
  }

  updateDataToShow() {
    let res = [];
    let start = (this._pageNumber - 1) * this._rowsPerPage;
    for (let i = 0; i < this._rowsPerPage && start + i < this._data.length; i++) {
      res.push(this._data[start+i]);
    }
    this._dataToShow = res;
  }

  updateTableView() {
    this.updateDataToShow();
    if (typeof this._targetId !== 'string' || !this._targetId) {
      throw new Error('an element id expected');
    }
    let table = document.getElementById(this._targetId + '-table-section');
    if (!table) {
      throw new Error('failed to locate the table');
    }
    while (table.lastChild) {
      table.removeChild(table.lastChild);
    }

    if (!this._colNames) {
      this.setColumnNames();
    }
    let df = document.createDocumentFragment();
    let head = df.appendChild(document.createElement('thead'))
    .appendChild(document.createElement('tr'));
    for (let name of this._colNames) {
      let th = head.appendChild(document.createElement('th'));
      th.appendChild(document.createTextNode(name));
      let control = th.appendChild(document.createElement('div'));
      control.classList.add(this._targetId + '-control');
      control._colName = name;
      let up = control.appendChild(document.createElement('i'));
      up.classList.add('data-table-up-control');
      up._colName = name;
      let down = control.appendChild(document.createElement('i'));
      down.classList.add('data-table-down-control');
      down._colName = name;
    }
    let tbody = df.appendChild(document.createElement('tbody'));
    for (let row of this._dataToShow) {
      let th = tbody.appendChild(document.createElement('tr'));
      for (let name of this._colNames) {
        th.appendChild(document.createElement('td')).innerText = DataTable.convertToString(row[name]);
      }
    }
    table.appendChild(df);
  }
  generate() {
    // replace the table with a div element
    let target = document.getElementById(this._targetId);
    let div = document.createElement('div');
    target.parentNode.insertBefore(div, target);
    target.parentNode.removeChild(target);
    div.id = this._targetId;

    // create the contents of the new object
    let container = document.createDocumentFragment();
    let filterSection = container.appendChild(document.createElement('div'));
    filterSection.id = this._targetId + '-filter-section';

    let vizSection = container.appendChild(document.createElement('div'));
    vizSection.id = this._targetId + '-visualization-section';

    let table = container.appendChild(document.createElement('table'));
    table.id = this._targetId + '-table-section';

    let pager = container.appendChild(document.createElement('div'));
    pager.id = this._targetId + '-pager-section';
    let a = pager.appendChild(document.createElement('div'));
    a.appendChild(document.createElement('span'))
    .appendChild(document.createTextNode('Items per Page'));
    let num = a.appendChild(document.createElement('select'));
    num.classList.add('data-table-row-number-selector');
    for (let i of [5, 10, 20, 50, 100]) {
      num.appendChild(document.createElement('option'))
      .appendChild(document.createTextNode(i));
    }
    num.value = 10;

    let b = pager.appendChild(document.createElement('div'));
    b.appendChild(document.createElement('span'))
    .appendChild(document.createTextNode('Select Page'));
    let pages = b.appendChild(document.createElement('select'));
    pages.classList.add('data-table-pages-selector');

    let totalPages = Math.ceil(this._data.length / this._rowsPerPage);
    for (let i = 1; i <= totalPages; i++) {
      pages.appendChild(document.createElement('option'))
          .appendChild(document.createTextNode(i));
    }

    // add the df to div
    div.appendChild(container);
    this.updateTableView();
    this.attachListeners();
  }
  attachListeners() {
    let that = this;
    let table = document.getElementById(this._targetId + '-table-section');
    if (!table) {
      throw new Error('failed to locate the table');
    }
    table.addEventListener('click', function (evt) {
      if (evt.target.classList.contains('data-table-up-control')) {
        let col = evt.target._colName;
        that.sort(col, false);
      } else if (evt.target.classList.contains('data-table-down-control')) {
        let col = evt.target._colName;
        that.sort(col, true);
      }
      that.updateTableView();
    });
    let pager = document.getElementById(this._targetId + '-pager-section');
    let selects = pager.getElementsByTagName('select');
    selects[0].addEventListener('change', function () {
      // update table view
      that.setRowsPerPage(+this.value);
      that.setPageNumber(1);
      that.updateTableView();

      // update pager
      let totalPages = Math.ceil(that._data.length / that._rowsPerPage);
      while (selects[1].lastChild) {
        selects[1].removeChild(selects[1].lastChild);
      }
      for (let i = 1; i <= totalPages; i++) {
        selects[1].appendChild(document.createElement('option'))
        .appendChild(document.createTextNode(i));
      }
      selects[1].value = 1;
      that._changePageByUser = false;
      setTimeout(function () {
        that._changePageByUser = true;
      }, 1000);
    });
    selects[1].addEventListener('change', function () {
      if (that._changePageByUser) {
        that.setPageNumber(+this.value);
        that.updateTableView();
      }
    });
  }
}

if (typeof module !== 'undefined' && module.parent) {

} else {
  // test code go here
}
<|endoftext|>


<commit_before>var assert = require('assert');
var divert = require('../');

describe('divert can be nested', function() {
   it('divert accepts node-style callback as a second parameter', function(done) {
      divert(function*(sync) {
         var result = yield divert(function*() {
               return true;
            }, function(err, result) {
               assert.ifError(err);
               assert.ok(result, 'result of nested divert can be obtained through callback');
               done();
            });
      });
   });

   it('divert accepts sync as a second parameter', function(done) {
      divert(function*(sync) {
         var result = yield divert(function*() {
               return true;
            }, sync);
         assert.ok(result, 'result of nested divert can be obtained through callback');
         done();
      });
   });

   it('exception can be thrown through several levels of divert', function(done) {
      divert(function*(sync) {
         try {
            yield divert(function*(sync) {
               yield divert(function*(sync) {
                  throw Error('error message');
               }, sync);
            }, sync);
            assert.fail('exception must be thrown by yield construction');
         }
         catch(e) {
            assert.equal('error message', e.message, 'exception is thrown through several levels of divert');
            done();
         }
      });
   });
});
<commit_msg>last result test<commit_after>var assert = require('assert');
var divert = require('../');

describe('divert can be nested', function() {
   it('divert accepts node-style callback as a second parameter', function(done) {
      divert(function*(sync) {
         var result = yield divert(function*() {
               return true;
            }, function(err, result) {
               assert.ifError(err);
               assert.ok(result, 'result of nested divert can be obtained through callback');
               done();
            });
      });
   });

   it('divert accepts sync as a second parameter', function(done) {
      divert(function*(sync) {
         var result = yield divert(function*() {
               return true;
            }, sync);
         assert.ok(result, 'result of nested divert can be obtained through callback');
         done();
      });
   });

   it('divert invokes a callback only for the last time', function(done) {
      var doAsync = function(x) {
         setImmediate(function() {
            x(null, false);
         });
      }

      divert(function*(sync) {
         var result = yield divert(function*(sync) {
               yield doAsync(sync);
               return true;
            }, sync);
         assert.ok(result, 'only the last returned result is obtained through callback');
         done();
      });
   });

   it('exception can be thrown through several levels of divert', function(done) {
      divert(function*(sync) {
         try {
            yield divert(function*(sync) {
               yield divert(function*(sync) {
                  throw Error('error message');
               }, sync);
            }, sync);
            assert.fail('exception must be thrown by yield construction');
         }
         catch(e) {
            assert.equal('error message', e.message, 'exception is thrown through several levels of divert');
            done();
         }
      });
   });
});
<|endoftext|>


<commit_before>/*
 * go-sonos
 * ========
 *
 * Copyright (c) 2012, Ian T. Richards <ianr@panix.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

var queueSize = 0;
var updateCount = 0;
var currentTrack = 0;

function onError(msg) {
	$("#result").empty().append(msg);
}

function clearError() {
	$("#result").empty();
}

function onVolume(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else {
		$("#volume-slider").slider("value", data.Value);
	}
}

function formatDuration(d) {
	seconds = d % 60;
	d /= 60;
	minutes = d % 60;
	d /= 60;
	hours = d;
	return Math.floor(hours) + "h" + Math.floor(minutes) + "m" + seconds + "s";
}

function setCurrentTrack(track) {
	if (track != currentTrack) {
		//.remvoveClass()
	}
	currentTrack = track - 1;
}

function onPositionInfo(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if ("Value" in data) {
		obj = data.Value;
		$("#track").text(obj.Track + "/" + queueSize);
		$("#track-duration").text(formatDuration(obj.TrackDuration));
		$("#rel-time").text(formatDuration(obj.RelTime));
		$("#title").text(obj.Title);
		$("#album").text(obj.Album);
		$("#progress-bar").progressbar("value", 100 * (obj.RelTime / obj.TrackDuration));
		$(".progress-label").text(formatDuration(obj.TrackDuration - obj.RelTime));
		setCurrentTrack(obj.Track);
	}
}

function onRemoveTrack(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else {
		clearError();
	}
}

function removeTrack(num) {
	$.post("/control", {method: "remove-track-from-queue", track: num}, onRemoveTrack, "json");
}

function onPlayTrack(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else {
		clearError();
	}
}

function playTrack(num) {
	$.post("/control", {method: "seek", unit: "TRACK_NR", target: num}, onPlayTrack, "json");
}

function xmlUnescape(s) {
	s = s.replace(/%3a/g, ":");
	s = s.replace(/%2f/g, "/");
	s = s.replace(/%2520/g, " ");
	return s;
}

function writeTrackRow(track, num) {
	$("#current-queue>tbody").append(
		  "
"
		+ "" + num + "	"
		+ "Jump	"
		+ "Dele	"
		+ "" + track.Creator + "	"
		+ "" + track.Album + "	"
		+ "" + track.Title + "	"
		//+ "	"
		+ "
");
}

function writeTrackRow_2(track) {
	$("#track-table>tbody").append(
		  "
"
		+ "" + track.Title + "	"
		+ "
");
}

function onQueue(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if ("Value" in data) {
		queueSize = data.Value.length;
		$("#current-queue>tbody").empty();
		for (i = currentTrack; i < data.Value.length; i++) {
			writeTrackRow(data.Value[i], i + 1);
		}
		for (i = 0; i < currentTrack; i++) {
			writeTrackRow(data.Value[i], i + 1);
		}
	}
}

function playButtonPlay() {
	options = {
		label: "Play",
		icons: {
			primary: "ui-icon-play"
		}
	}
	$("#control-panel>#play").button("option", options);
}

function playButtonPause() {
	options = {
		label: "Pause",
		icons: {
			primary: "ui-icon-pause"
		}
	}
	$("#control-panel>#play").button("option", options);
}

function onTransportInfo(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		state = data.Value.CurrentTransportState
		if ("STOPPED" == state || "PAUSED_PLAYBACK" == state) {
			playButtonPlay();
		} else if ("PLAYING" == state) {
			playButtonPause();
		}
	}
}

function onGetGenreArtists(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		clearError();
		$("#artist-table>tbody").empty();
		$("#album-table>tbody").empty();
		$("#track-table>tbody").empty();
		for (i in data.Value) {
			artist = data.Value[i];
			writeArtistRow(artist);
		}
	}
}

function getGenre(genre) {
	$.post("/browse", {method: "get-genre-artists", genre: genre}, onGetGenreArtists, "json");
}

function onGetArtist(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		clearError();
		$("#album-table>tbody").empty();
		for (i in data.Value) {
			album = data.Value[i];
			writeAlbumRow(album);
		}
	}
}

function onGetAlbum(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		clearError();
		$("#track-table>tbody").empty();
		for (i in data.Value) {
			track = data.Value[i];
			writeTrackRow_2(track);
		}
	}
}

function getAlbum(album) {
	$.post("/browse", {method: "get-album-tracks", album: album}, onGetAlbum, "json");
}

function getArtist(artist) {
	$.post("/browse", {method: "get-artist-albums", artist: artist}, onGetArtist, "json");
}

function writeGenreRow(genre) {
	$("#genre-table>tbody").append(
		  "
"
		+ "" + genre.Title + "	"
		+ "
");
}

function writeArtistRow(artist) {
	$("#artist-table>tbody").append(
		  "
"
		+ "" + artist.Title + "	"
		+ "
");
}

function writeAlbumRow(album) {
	$("#album-table>tbody").append(
		  "
"
		+ "" + album.TrackURI + "	"
		+ "
");
}

function onGenreList(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		clearError();
		$("#genre-table>tbody").empty();
		for (i in data.Value) {
			genre = data.Value[i];
			writeGenreRow(genre);
		}
	}
}

function eventLoop() {
	$.post("/control", {method: "get-volume"}, onVolume, "json");
	$.post("/control", {method: "get-position-info"}, onPositionInfo, "json");
	$.post("/control", {method: "get-transport-info"}, onTransportInfo, "json");
	if (++updateCount % 5 == 0) {
		$.post("/browse", {method: "get-queue-contents"}, onQueue, "json");
	}
}

function initUi() {
	$.post("/control", {method: "get-volume"}, onVolume, "json");
	$.post("/control", {method: "get-position-info"}, onPositionInfo, "json");
	$.post("/control", {method: "get-transport-info"}, onTransportInfo, "json");
	$.post("/browse", {method: "get-queue-contents"}, onQueue, "json");
	$.post("/browse", {method: "get-all-genres"}, onGenreList, "json");
}

<commit_msg>Escaping single quotes in genre names<commit_after>/*
 * go-sonos
 * ========
 *
 * Copyright (c) 2012, Ian T. Richards <ianr@panix.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

var queueSize = 0;
var updateCount = 0;
var currentTrack = 0;

function onError(msg) {
	$("#result").empty().append(msg);
}

function clearError() {
	$("#result").empty();
}

function onVolume(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else {
		$("#volume-slider").slider("value", data.Value);
	}
}

function formatDuration(d) {
	seconds = d % 60;
	d /= 60;
	minutes = d % 60;
	d /= 60;
	hours = d;
	return Math.floor(hours) + "h" + Math.floor(minutes) + "m" + seconds + "s";
}

function setCurrentTrack(track) {
	if (track != currentTrack) {
		//.remvoveClass()
	}
	currentTrack = track - 1;
}

function onPositionInfo(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if ("Value" in data) {
		obj = data.Value;
		$("#track").text(obj.Track + "/" + queueSize);
		$("#track-duration").text(formatDuration(obj.TrackDuration));
		$("#rel-time").text(formatDuration(obj.RelTime));
		$("#title").text(obj.Title);
		$("#album").text(obj.Album);
		$("#progress-bar").progressbar("value", 100 * (obj.RelTime / obj.TrackDuration));
		$(".progress-label").text(formatDuration(obj.TrackDuration - obj.RelTime));
		setCurrentTrack(obj.Track);
	}
}

function onRemoveTrack(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else {
		clearError();
	}
}

function removeTrack(num) {
	$.post("/control", {method: "remove-track-from-queue", track: num}, onRemoveTrack, "json");
}

function onPlayTrack(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else {
		clearError();
	}
}

function playTrack(num) {
	$.post("/control", {method: "seek", unit: "TRACK_NR", target: num}, onPlayTrack, "json");
}

function xmlUnescape(s) {
	s = s.replace(/%3a/g, ":");
	s = s.replace(/%2f/g, "/");
	s = s.replace(/%2520/g, " ");
	return s;
}

function jsEscape(s) {
	s = s.replace("'", "\\'");
	return s;
}

function writeTrackRow(track, num) {
	$("#current-queue>tbody").append(
		  "
"
		+ "" + num + "	"
		+ "Jump	"
		+ "Dele	"
		+ "" + track.Creator + "	"
		+ "" + track.Album + "	"
		+ "" + track.Title + "	"
		//+ "	"
		+ "
");
}

function writeTrackRow_2(track) {
	$("#track-table>tbody").append(
		  "
"
		+ "" + track.Title + "	"
		+ "
");
}

function onQueue(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if ("Value" in data) {
		queueSize = data.Value.length;
		$("#current-queue>tbody").empty();
		for (i = currentTrack; i < data.Value.length; i++) {
			writeTrackRow(data.Value[i], i + 1);
		}
		for (i = 0; i < currentTrack; i++) {
			writeTrackRow(data.Value[i], i + 1);
		}
	}
}

function playButtonPlay() {
	options = {
		label: "Play",
		icons: {
			primary: "ui-icon-play"
		}
	}
	$("#control-panel>#play").button("option", options);
}

function playButtonPause() {
	options = {
		label: "Pause",
		icons: {
			primary: "ui-icon-pause"
		}
	}
	$("#control-panel>#play").button("option", options);
}

function onTransportInfo(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		state = data.Value.CurrentTransportState
		if ("STOPPED" == state || "PAUSED_PLAYBACK" == state) {
			playButtonPlay();
		} else if ("PLAYING" == state) {
			playButtonPause();
		}
	}
}

function onGetGenreArtists(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		clearError();
		$("#artist-table>tbody").empty();
		$("#album-table>tbody").empty();
		$("#track-table>tbody").empty();
		for (i in data.Value) {
			artist = data.Value[i];
			writeArtistRow(artist);
		}
	}
}

function getGenre(genre) {
	$.post("/browse", {method: "get-genre-artists", genre: genre}, onGetGenreArtists, "json");
}

function onGetArtist(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		clearError();
		$("#album-table>tbody").empty();
		for (i in data.Value) {
			album = data.Value[i];
			writeAlbumRow(album);
		}
	}
}

function onGetAlbum(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		clearError();
		$("#track-table>tbody").empty();
		for (i in data.Value) {
			track = data.Value[i];
			writeTrackRow_2(track);
		}
	}
}

function getAlbum(album) {
	$.post("/browse", {method: "get-album-tracks", album: album}, onGetAlbum, "json");
}

function getArtist(artist) {
	$.post("/browse", {method: "get-artist-albums", artist: artist}, onGetArtist, "json");
}

function writeGenreRow(genre) {
	$("#genre-table>tbody").append(
		  "
"
		+ "" + genre.TrackURI + "	"
		+ "
");
}

function writeArtistRow(artist) {
	$("#artist-table>tbody").append(
		  "
"
		+ "" + artist.TrackURI + "	"
		+ "
");
}

function writeAlbumRow(album) {
	$("#album-table>tbody").append(
		  "
"
		+ "" + album.TrackURI + "	"
		+ "
");
}

function onGenreList(data) {
	if ("Error" in data) {
		onError(data.Error);
	} else if("Value" in data) {
		clearError();
		$("#genre-table>tbody").empty();
		for (i in data.Value) {
			genre = data.Value[i];
			writeGenreRow(genre);
		}
	}
}

function eventLoop() {
	$.post("/control", {method: "get-volume"}, onVolume, "json");
	$.post("/control", {method: "get-position-info"}, onPositionInfo, "json");
	$.post("/control", {method: "get-transport-info"}, onTransportInfo, "json");
	if (++updateCount % 5 == 0) {
		$.post("/browse", {method: "get-queue-contents"}, onQueue, "json");
	}
}

function initUi() {
	$.post("/control", {method: "get-volume"}, onVolume, "json");
	$.post("/control", {method: "get-position-info"}, onPositionInfo, "json");
	$.post("/control", {method: "get-transport-info"}, onTransportInfo, "json");
	$.post("/browse", {method: "get-queue-contents"}, onQueue, "json");
	$.post("/browse", {method: "get-all-genres"}, onGenreList, "json");
}

<|endoftext|>


<commit_before>OpenShakespeare = ("OpenShakespeare" in window) ? OpenShakespeare : {}

OpenShakespeare.Annotator = function (element) {
  var $ = jQuery, self = this

  this.annotator = $(element).annotator().data('annotator')
  this.currentUser = null

  this.options = {
    user: { }

  }

  return this
}
<commit_msg>Updated for our standard development environment<commit_after>OpenShakespeare = ("OpenShakespeare" in window) ? OpenShakespeare : {}

OpenShakespeare.Annotator = function (element) {
    var $ = jQuery, self = this

    this.annotator = $(element).annotator().data('annotator')
    this.currentUser = null

    this.options = {
        user: {}

    }
/*
    jQuery(function ($) {
        $('#text-to-annotate').annotator();
    });

    // Setup the annotator on the page.
    var content = $('#text-to-annotate').annotator();
*/
    $(element).annotator().annotator('addPlugin', 'Substitutions', 'bbk:english');
    $(element).annotator().annotator('addPlugin', 'Tags');

    jQuery(function ($) {
       $(element).annotator()
                .annotator('setupPlugins');
    });

    return this
}
<|endoftext|>


<commit_before>var tessel = require('tessel');
var blePort = tessel.port('a');

var ble = require('../index').connect(blePort, function(err) {
	if (err) return console.log(err);

	ble.startAdvertising(function(err, response) {
		if (!err) {
			console.log("Began advertising.");
		}
	})
})
<commit_msg>improved formatting, semicolon use<commit_after>var tessel = require('tessel');
var blePort = tessel.port('a');

var ble = require('../index').connect(blePort, function(err) {
	if (err) return console.log(err);

	ble.startAdvertising(function(err, response) {
		if (!err) {
			console.log("Began advertising.");
		}
	});
});
<|endoftext|>


<commit_before>/**
 * Created with JetBrains PhpStorm.
 * User: willy
 * Date: 2/16/14
 * Time: 8:23 AM
 * To change this template use File | Settings | File Templates.
 */

    var on = false;

    var Timer = function( options ) {
        opt = $.extend({}, $.fn.default, options);
    };

    function show(tok) {
        $("#timer").html(tok);
    }

    function formater(number) {
        if(number % 1 == 0){
            var divisor = 60;
            var min = Math.floor(number/divisor);
            var sec = Math.floor(number - (min * 60));

            return min+':'+sec;
        }
    }

    Timer.prototype.start = function() {
        if(!on) {
            on = !on;
            tik = setInterval(function() {
                opt.limit = opt.limit-1;

                if(opt.limit < 0){
                    Timer.prototype.stop();
                }else{
                    show(formater(opt.limit));
                }
            }, 1000);
        }
    }

    Timer.prototype.stop = function() {
        if(on == true) {
            clearInterval(tik);
            on = !on;
        }
    }

    $.fn.default = {
        limit: 3
    }<commit_msg>change jquery code to javascript<commit_after>/**
 * Created with JetBrains PhpStorm.
 * User: willy
 * Date: 2/16/14
 * Time: 8:23 AM
 * To change this template use File | Settings | File Templates.
 */

    var on = false;

    var Timer = function( options ) {
        opt = $.extend({}, defaults, options);
    };

    function show(tok) {
        $("#timer").html(tok);
    }

    function formater(number) {
        if(number % 1 == 0){
            var divisor = 60;
            var min = Math.floor(number/divisor);
            var sec = Math.floor(number - (min * 60));

            return min+':'+sec;
        }
    }

    Timer.prototype.start = function() {
        if(!on) {
            on = !on;
            tik = setInterval(function() {
                show(formater(opt.limit));
                if(opt.limit < 1){
                    Timer.prototype.stop();
                }else{
                    opt.limit = opt.limit-1;
                }
            }, 1000);
        }
    }

    Timer.prototype.stop = function() {
        if(on == true) {
            clearInterval(tik);
            on = !on;
        }
    }

    defaults = {
        limit: 3
    }<|endoftext|>


<commit_before>var endpoint = require('../../lib/endpoints'),
    Hapi = require('hapi'),
    resourceLoader = require('../../lib/api/resource-loader'),
    path = require('path');

describe('endpoints#page', function() {
  var server,
      pageOptions,
      options;

  beforeEach(function(done) {
    server = new Hapi.Server();
    server = new Hapi.Server(0, {labels:['api']});

    //for hapi 8

    server.connection({
      port: 0,
      labels: ['api']
    });

    server.start(done);

    options = {branch: 'foo'};
    pageOptions = {
      cacheResources: true,
      poolSize: 5,
      host: 'localhost:' + server.info.port,
      configVar: 'phoenixShared',
      userConfig: function(req) {
        return options;
      }
    };

    this.stub(resourceLoader, 'routeInfo', function(branch, route) {
      expect(branch).to.equal('foo');
      expect(route).to.equal('/foo/{path*}');
      return {
        serverRender: true,
        js: ['1234/base.js', '1234/foo.js', '1234/bar.js'],
        css: ['1234/base@2x.css', '1234/foo@2x.css']
      };
    });
    this.stub(resourceLoader, 'index', function() {
      return __dirname + '/../artifacts/server-side.html';
    });
  });

  it('should run finalize', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    var finalized;
    pageOptions.finalize = function(req, response, isServer) {
      expect(isServer).to.be.true;
      finalized = true;
    };

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(finalized).to.be.true;
      expect(res.payload).to.match(/\$serverCache/);
      expect(res.payload).to.match(/
(\nit ran){3}/);

      done();
    });
  });

  it('should route to server side without config', function(done) {
    resourceLoader.routeInfo.restore();
    this.stub(resourceLoader, 'routeInfo', function(branch, route) {
      expect(branch).to.not.exist;
      expect(route).to.equal('/foo/{path*}');
      return {
        serverRender: true,
        js: ['1234/base.js', '1234/foo.js', '1234/bar.js'],
        css: ['1234/base@2x.css', '1234/foo@2x.css']
      };
    });
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    delete pageOptions.userConfig;

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.match(/\$serverCache/);
      expect(res.payload).to.match(/
(\nit ran){3}/);

      done();
    });
  });

  it('should route to server side with serverRoute config', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    options = {
      serverRoute: {
        '/foo/{path*}': true
      },
      branch: 'foo'
    };
    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.match(/\$serverCache/);

      done();
    });
  });
  it('should route to index with serverRoute config disabled', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    var finalized;
    pageOptions.finalize = function(req, response, isServer) {
      expect(isServer).to.be.false;
      finalized = true;
    };

    options = {
      serverRoute: {
        '/foo/{path*}': false
      },
      branch: 'foo'
    };
    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(finalized).to.be.true;
      expect(res.payload).to.not.match(/\$serverCache/);

      done();
    });
  });
  it('should route to index with serverRoute all disabled', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    options = {
      serverRoute: false,
      branch: 'foo'
    };
    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.not.match(/\$serverCache/);

      done();
    });
  });
  it('should log and output the default index file on server side throw', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side-error.js.test';
    });

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.not.match(/\$serverCache/);
      expect(res.payload).to.not.match(/
(\nit ran){3}/);
      expect(res.payload).to.match(/module.exports = require\(/);

      done();
    });
  });
  it('should log and output the default index file on 500 error', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side-500.js.test';
    });

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.not.match(/\$serverCache/);
      expect(res.payload).to.not.match(/
(\nit ran){3}/);
      expect(res.payload).to.match(/module.exports = require\(/);

      done();
    });
  });

  it('should log and output the default index file on server side on navigate error', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side-loadUrl-error.js.test';
    });

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.match(/\$serverCache/);
      expect(res.payload).to.not.match(/module.exports = require\(/);

      setTimeout(function() {
        server.inject({
          method: 'get',
          url: '/foo/bar/bat',
          payload: ''
        }, function(res) {
          expect(res.payload).to.match(/module.exports = require\(/);

          setTimeout(done, 15);
        });
      }, 15);
    });
  });
});
<commit_msg>remove additional server.js<commit_after>var endpoint = require('../../lib/endpoints'),
    Hapi = require('hapi'),
    resourceLoader = require('../../lib/api/resource-loader'),
    path = require('path');

describe('endpoints#page', function() {
  var server,
      pageOptions,
      options;

  beforeEach(function(done) {
    server = new Hapi.Server(0, {labels:['api']});

    //for hapi 8

    server.connection({
      port: 0,
      labels: ['api']
    });

    server.start(done);

    options = {branch: 'foo'};
    pageOptions = {
      cacheResources: true,
      poolSize: 5,
      host: 'localhost:' + server.info.port,
      configVar: 'phoenixShared',
      userConfig: function(req) {
        return options;
      }
    };

    this.stub(resourceLoader, 'routeInfo', function(branch, route) {
      expect(branch).to.equal('foo');
      expect(route).to.equal('/foo/{path*}');
      return {
        serverRender: true,
        js: ['1234/base.js', '1234/foo.js', '1234/bar.js'],
        css: ['1234/base@2x.css', '1234/foo@2x.css']
      };
    });
    this.stub(resourceLoader, 'index', function() {
      return __dirname + '/../artifacts/server-side.html';
    });
  });

  it('should run finalize', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    var finalized;
    pageOptions.finalize = function(req, response, isServer) {
      expect(isServer).to.be.true;
      finalized = true;
    };

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(finalized).to.be.true;
      expect(res.payload).to.match(/\$serverCache/);
      expect(res.payload).to.match(/
(\nit ran){3}/);

      done();
    });
  });

  it('should route to server side without config', function(done) {
    resourceLoader.routeInfo.restore();
    this.stub(resourceLoader, 'routeInfo', function(branch, route) {
      expect(branch).to.not.exist;
      expect(route).to.equal('/foo/{path*}');
      return {
        serverRender: true,
        js: ['1234/base.js', '1234/foo.js', '1234/bar.js'],
        css: ['1234/base@2x.css', '1234/foo@2x.css']
      };
    });
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    delete pageOptions.userConfig;

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.match(/\$serverCache/);
      expect(res.payload).to.match(/
(\nit ran){3}/);

      done();
    });
  });

  it('should route to server side with serverRoute config', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    options = {
      serverRoute: {
        '/foo/{path*}': true
      },
      branch: 'foo'
    };
    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.match(/\$serverCache/);

      done();
    });
  });
  it('should route to index with serverRoute config disabled', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    var finalized;
    pageOptions.finalize = function(req, response, isServer) {
      expect(isServer).to.be.false;
      finalized = true;
    };

    options = {
      serverRoute: {
        '/foo/{path*}': false
      },
      branch: 'foo'
    };
    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(finalized).to.be.true;
      expect(res.payload).to.not.match(/\$serverCache/);

      done();
    });
  });
  it('should route to index with serverRoute all disabled', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side.js.test';
    });

    options = {
      serverRoute: false,
      branch: 'foo'
    };
    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.not.match(/\$serverCache/);

      done();
    });
  });
  it('should log and output the default index file on server side throw', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side-error.js.test';
    });

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.not.match(/\$serverCache/);
      expect(res.payload).to.not.match(/
(\nit ran){3}/);
      expect(res.payload).to.match(/module.exports = require\(/);

      done();
    });
  });
  it('should log and output the default index file on 500 error', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side-500.js.test';
    });

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.not.match(/\$serverCache/);
      expect(res.payload).to.not.match(/
(\nit ran){3}/);
      expect(res.payload).to.match(/module.exports = require\(/);

      done();
    });
  });

  it('should log and output the default index file on server side on navigate error', function(done) {
    this.stub(resourceLoader, 'asset', function(path) {
      return __dirname + '/../artifacts/server-side-loadUrl-error.js.test';
    });

    server.route({path: '/foo/{path*}', method: 'GET', config: {handler: endpoint.page('app', pageOptions)} });
    server.inject({
      method: 'get',
      url: '/foo/bar/bat',
      payload: ''
    }, function(res) {
      expect(res.payload).to.match(/\$serverCache/);
      expect(res.payload).to.not.match(/module.exports = require\(/);

      setTimeout(function() {
        server.inject({
          method: 'get',
          url: '/foo/bar/bat',
          payload: ''
        }, function(res) {
          expect(res.payload).to.match(/module.exports = require\(/);

          setTimeout(done, 15);
        });
      }, 15);
    });
  });
});
<|endoftext|>


<commit_before>import { TASK_SERVER_URL as baseURL } from '../config';

const toJSON = response => response.json();

// Status
export const status = () => (
  fetch(`${baseURL}`)
    .then(toJSON)
);

// User
export const loginURL =
  `${baseURL}/connect/openstreetmap`;

export const fetchUserDetails = ({ token }) => (
  fetch(`${baseURL}/user/details`, {
    headers: {
      'Authorization': token,
    },
  })
    .then(toJSON)
);

export const logout = ({ token }) => (
  fetch(`${baseURL}/logout`, {
    headers: {
      'Authorization': token,
    },
  })
    .then(toJSON)
);

// Admin
export const fetchAllUsers = ({ token }) => (
  fetch(`${baseURL}/users`, {
    headers: {
      'Authorization': token,
    },
  })
    .then(toJSON)
);

export const changeUserRole = ({ token, payload }) => (
  fetch(`${baseURL}/users`, {
    method: 'PUT',
    headers: {
      'Authorization': token,
    },
    body: payload,
  })
    .then(toJSON)
);

export const destroyUser = ({ token, payload }) => (
  fetch(`${baseURL}/users`, {
    method: 'DELETE',
    headers: {
      'Authorization': token,
    },
    body: payload,
  })
    .then(toJSON)
);

// Tasks
export const fetchAllTasks = () => (
  fetch(`${baseURL}/tasks`)
    .then(toJSON)
);

export const fetchTaskById = ({ taskId }) => (
  fetch(`${baseURL}/tasks/${taskId}`)
    .then(toJSON)
);

export const createTask = ({ token, payload }) => (
  fetch(`${baseURL}/tasks`, {
    method: 'POST',
    headers: {
      'Authorization': token,
    },
    body: payload,
  })
    .then(toJSON)
);

export const updateTask = ({ token, payload }) => (
  fetch(`${baseURL}/tasks`, {
    method: 'PUT',
    headers: {
      'Authorization': token,
    },
    body: payload,
  })
    .then(toJSON)
);

export const destroyTask = ({ token, payload }) => (
  fetch(`${baseURL}/tasks`, {
    method: 'DELETE',
    headers: {
      'Authorization': token,
    },
    body: payload,
  })
    .then(toJSON)
);

// Items
export const fetchRandomItem = ({ taskId, taskType, payload }) => (
  fetch(`${baseURL}/tasks/${taskId}/${taskType}/items`, {
    method: 'POST',
    body: JSON.stringify(payload),
  })
    .then(toJSON)
);

export const updateItem = ({ taskId, taskType, payload }) => (
  fetch(`${baseURL}/tasks/${taskId}/${taskType}/items`, {
    method: 'PUT',
    body: JSON.stringify(payload),
  })
    .then(toJSON)
);

// Activity
export const fetchRecentActivity = ({ taskId }) => (
  fetch(`${baseURL}/tasks/${taskId}/activity`)
    .then(toJSON)
);

// Stats
export const fetchAllStats = ({ taskId, from, to }) => (
  fetch(`${baseURL}/tasks/${taskId}/track_stats/from:${from}/to:${to}`)
    .then(toJSON)
);
<commit_msg>stringify the payload<commit_after>import { TASK_SERVER_URL as baseURL } from '../config';

const toJSON = response => response.json();

// Status
export const status = () => (
  fetch(`${baseURL}`)
    .then(toJSON)
);

// User
export const loginURL =
  `${baseURL}/connect/openstreetmap`;

export const fetchUserDetails = ({ token }) => (
  fetch(`${baseURL}/user/details`, {
    headers: {
      'Authorization': token,
    },
  })
    .then(toJSON)
);

export const logout = ({ token }) => (
  fetch(`${baseURL}/logout`, {
    headers: {
      'Authorization': token,
    },
  })
    .then(toJSON)
);

// Admin
export const fetchAllUsers = ({ token }) => (
  fetch(`${baseURL}/users`, {
    headers: {
      'Authorization': token,
    },
  })
    .then(toJSON)
);

export const changeUserRole = ({ token, payload }) => (
  fetch(`${baseURL}/users`, {
    method: 'PUT',
    headers: {
      'Authorization': token,
    },
    body: JSON.stringify(payload),
  })
    .then(toJSON)
);

export const destroyUser = ({ token, payload }) => (
  fetch(`${baseURL}/users`, {
    method: 'DELETE',
    headers: {
      'Authorization': token,
    },
    body: JSON.stringify(payload),
  })
    .then(toJSON)
);

// Tasks
export const fetchAllTasks = () => (
  fetch(`${baseURL}/tasks`)
    .then(toJSON)
);

export const fetchTaskById = ({ taskId }) => (
  fetch(`${baseURL}/tasks/${taskId}`)
    .then(toJSON)
);

export const createTask = ({ token, payload }) => (
  fetch(`${baseURL}/tasks`, {
    method: 'POST',
    headers: {
      'Authorization': token,
    },
    body: payload,
  })
    .then(toJSON)
);

export const updateTask = ({ token, payload }) => (
  fetch(`${baseURL}/tasks`, {
    method: 'PUT',
    headers: {
      'Authorization': token,
    },
    body: payload,
  })
    .then(toJSON)
);

export const destroyTask = ({ token, payload }) => (
  fetch(`${baseURL}/tasks`, {
    method: 'DELETE',
    headers: {
      'Authorization': token,
    },
    body: payload,
  })
    .then(toJSON)
);

// Items
export const fetchRandomItem = ({ taskId, taskType, payload }) => (
  fetch(`${baseURL}/tasks/${taskId}/${taskType}/items`, {
    method: 'POST',
    body: JSON.stringify(payload),
  })
    .then(toJSON)
);

export const updateItem = ({ taskId, taskType, payload }) => (
  fetch(`${baseURL}/tasks/${taskId}/${taskType}/items`, {
    method: 'PUT',
    body: JSON.stringify(payload),
  })
    .then(toJSON)
);

// Activity
export const fetchRecentActivity = ({ taskId }) => (
  fetch(`${baseURL}/tasks/${taskId}/activity`)
    .then(toJSON)
);

// Stats
export const fetchAllStats = ({ taskId, from, to }) => (
  fetch(`${baseURL}/tasks/${taskId}/track_stats/from:${from}/to:${to}`)
    .then(toJSON)
);
<|endoftext|>


<commit_before>import React from 'react';
import {
  Col,
  ControlLabel,
  FormControl,
  FormGroup,
  Grid,
  Row,
} from 'react-bootstrap';
import Router from 'next/router';
import classNames from 'classnames';

import withData from '../lib/withData'
import withIntl from '../lib/withIntl';
import { addGetLoggedInUserFunction, addSearchQueryData } from '../graphql/queries';

import Body from '../components/Body';
import Button from '../components/Button';
import CollectiveCard from '../components/CollectiveCard';
import ErrorPage from '../components/ErrorPage';
import Footer from '../components/Footer';
import Header from '../components/Header';
import LoadingGrid from '../components/LoadingGrid';
import { Link } from '../server/pages';

import colors from '../constants/colors';

class SearchPage extends React.Component {
  static getInitialProps({ query = {} }) {
    return {
      limit: query.limit || 20,
      offset: query.offset || 0,
      term: query.q || '',
    };
  }

  state = {
    loadingUserLogin: true,
    LoggedInUser: {},
  }

  async componentDidMount() {
    const { getLoggedInUser } = this.props;
    try {
      const LoggedInUser = getLoggedInUser && await getLoggedInUser();
      this.setState({
        loadingUserLogin: false,
        LoggedInUser,
      });
    } catch (error) {
      this.setState({ loadingUserLogin: false });
    }
  }

  refetch = (event) => {
    event.preventDefault();

    const { target: form } = event;
    const { url } = this.props;
    const { q } = form;

    Router.push({ pathname: url.pathname, query: { q: q.value } });
  }

  render() {
    const { data: { error, loading, search }, term = '' } = this.props;
    const { loadingUserLogin, LoggedInUser } = this.state;

    const {
      collectives,
      limit = 20,
      offset,
      total = 0,
    } = search || {};

    if (error) {
      return <ErrorPage {...error} />;
    }

    const showCollectives = !loading && term.trim() !== "" && !!collectives;

    return (

          <Grid>
            <Row>
              <Col xs={12}>
                <form method="GET" onSubmit={this.refetch}>
                  <FormGroup controlId="search" bsSize="large">
                    <ControlLabel className="h1">Search Open Collective</ControlLabel>

                      <FormControl type="search" name="q" placeholder="open source" className="search-input" defaultValue={term} />
                      <Button type="submit" className="blue" style={{ padding: '0 2rem' }}></Button>

                  </FormGroup>
                </form>
              </Col>
            </Row>
            <Row className="results-row">
              {loading && (

                  <LoadingGrid />

              )}

              {showCollectives && collectives.map(collective => (
                <Col className="col" key={collective.slug}>
                  <CollectiveCard collective={collective} />
                </Col>
              ))}

              { /* TODO: add suggested collectives when the result is empty */ }
              {showCollectives && collectives.length === 0 && (

No collectives found matching your query: "{term}"

              )}
            </Row>
            {showCollectives && collectives.length !== 0 && <Row>

                { Array(Math.ceil(total / limit)).fill(1).map((n, i) => (

                    <Link
                      href={{
                        query: {
                          limit,
                          offset: i * limit,
                          q: term,
                        }
                      }}
                    >
                      {`${n + i}`}
                    </Link>

                )) }

            </Row>}
          </Grid>

    )
  }
}

export { SearchPage as MockSearchPage };

export default withData(addGetLoggedInUserFunction(addSearchQueryData(withIntl(SearchPage))));
<commit_msg>fix(search): scope styles to search-input class<commit_after>import React from 'react';
import {
  Col,
  ControlLabel,
  FormControl,
  FormGroup,
  Grid,
  Row,
} from 'react-bootstrap';
import Router from 'next/router';
import classNames from 'classnames';

import withData from '../lib/withData'
import withIntl from '../lib/withIntl';
import { addGetLoggedInUserFunction, addSearchQueryData } from '../graphql/queries';

import Body from '../components/Body';
import Button from '../components/Button';
import CollectiveCard from '../components/CollectiveCard';
import ErrorPage from '../components/ErrorPage';
import Footer from '../components/Footer';
import Header from '../components/Header';
import LoadingGrid from '../components/LoadingGrid';
import { Link } from '../server/pages';

import colors from '../constants/colors';

class SearchPage extends React.Component {
  static getInitialProps({ query = {} }) {
    return {
      limit: query.limit || 20,
      offset: query.offset || 0,
      term: query.q || '',
    };
  }

  state = {
    loadingUserLogin: true,
    LoggedInUser: {},
  }

  async componentDidMount() {
    const { getLoggedInUser } = this.props;
    try {
      const LoggedInUser = getLoggedInUser && await getLoggedInUser();
      this.setState({
        loadingUserLogin: false,
        LoggedInUser,
      });
    } catch (error) {
      this.setState({ loadingUserLogin: false });
    }
  }

  refetch = (event) => {
    event.preventDefault();

    const { target: form } = event;
    const { url } = this.props;
    const { q } = form;

    Router.push({ pathname: url.pathname, query: { q: q.value } });
  }

  render() {
    const { data: { error, loading, search }, term = '' } = this.props;
    const { loadingUserLogin, LoggedInUser } = this.state;

    const {
      collectives,
      limit = 20,
      offset,
      total = 0,
    } = search || {};

    if (error) {
      return <ErrorPage {...error} />;
    }

    const showCollectives = !loading && term.trim() !== "" && !!collectives;

    return (

          <Grid>
            <Row>
              <Col xs={12}>
                <form method="GET" onSubmit={this.refetch}>
                  <FormGroup controlId="search" bsSize="large">
                    <ControlLabel className="h1">Search Open Collective</ControlLabel>

                      <FormControl type="search" name="q" placeholder="open source" className="search-input" defaultValue={term} />
                      <Button type="submit" className="blue" style={{ padding: '0 2rem' }}></Button>

                  </FormGroup>
                </form>
              </Col>
            </Row>
            <Row className="results-row">
              {loading && (

                  <LoadingGrid />

              )}

              {showCollectives && collectives.map(collective => (
                <Col className="col" key={collective.slug}>
                  <CollectiveCard collective={collective} />
                </Col>
              ))}

              { /* TODO: add suggested collectives when the result is empty */ }
              {showCollectives && collectives.length === 0 && (

No collectives found matching your query: "{term}"

              )}
            </Row>
            {showCollectives && collectives.length !== 0 && <Row>

                { Array(Math.ceil(total / limit)).fill(1).map((n, i) => (

                    <Link
                      href={{
                        query: {
                          limit,
                          offset: i * limit,
                          q: term,
                        }
                      }}
                    >
                      {`${n + i}`}
                    </Link>

                )) }

            </Row>}
          </Grid>

    )
  }
}

export { SearchPage as MockSearchPage };

export default withData(addGetLoggedInUserFunction(addSearchQueryData(withIntl(SearchPage))));
<|endoftext|>