<commit_before>/*
Copyright 2012 Twitter, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * This module defines the Table view which generates a dynamic tabular view of a Workflow's jobs.
 */
define(['jquery', 'd3', '../core', './core'], function($, d3, Ambrose, View) {
  // Table ctor
  var Table = View.Table = function(workflow, container) {
    return new View.Table.fn.init(workflow, container);
  };

  /**
   * Table prototype.
   */
  Table.fn = Table.prototype = {
    /**
     * Constructor.
     *
     * @param workflow the Workflow instance to bind to.
     * @param container the DOM element in which to render the view.
     * @param params extra options.
     */
    init: function(workflow, container, params) {
      this.workflow = workflow;
      this.container = $(container);
      this.initTable();
      this.params = $.extend(true, {
        colors: {
          running: d3.rgb(98, 196, 98).brighter(),
          complete: d3.rgb(98, 196, 98),
          failed: d3.rgb(196, 98, 98),
          mouseover: d3.rgb(98, 98, 196).brighter(),
          selected: d3.rgb(98, 98, 196),
        },
      }, params);
      var self = this;
      workflow.on('jobsLoaded', function(event, jobs) {
        self.loadTable(jobs);
      });
      workflow.on('jobStarted jobProgress jobComplete jobFailed', function(event, job) {
        self.updateTableRows([job], 350);
      });
      workflow.on('jobSelected jobMouseOver', function(event, job, prev) {
        var jobs = [];
        if (prev) jobs.push(prev);
        if (job) jobs.push(job);
        self.updateTableRows(jobs);
      });
    },

    initTable: function() {
      var self = this;
      var tbody = this.tbody = $('
');
      $('
'
        + '

'
        + '#	'
        + 'Identifier	'
        + 'Status	'
        + 'Aliases	'
        + 'Features	'
        + 'Mappers	'
        + 'Reducers	'
        + '

'
        + '
')
        .appendTo(this.container.empty())
        .append(tbody);
    },

    loadTable: function(jobs) {
      var tr = this.selectRows(jobs);
      this.removeRows(tr);
      this.createRows(tr);
      this.updateRows(tr);
    },

    updateTableRows: function(jobs, duration) {
      this.updateRows(this.selectRows(jobs), duration);
    },

    selectRows: function(jobs) {
      // select rows and bind to jobs data
      return d3.select(this.tbody.get(0)).selectAll('tr')
        .data(jobs, function(job) { return job.name; });
    },

    removeRows: function(tr) {
      // remove rows for missing jobs data
      tr.exit().remove();
    },

    createRows: function(tr) {
      // create rows for new jobs data
      tr = tr.enter().append('tr');
      tr.style('background-color', 'white');
      tr.append('td').attr('class', 'job-num')
        .text(function(job) { return 1 + (job.topologicalIndex || job.index); });
      tr.append('td').attr('class', 'job-id')
        .append('a').attr('class', 'job-url')
        .attr('target', '_blank')
        .attr('href', 'javascript:void(0);');
      tr.append('td').attr('class', 'job-status');
      tr.append('td').attr('class', 'job-aliases');
      tr.append('td').attr('class', 'job-features');
      tr.append('td').attr('class', 'job-mappers');
      tr.append('td').attr('class', 'job-reducers');
      var self = this;
      tr.on('mouseover', function(job) { self.workflow.mouseOverJob(job); })
        .on('mouseout', function(job) { self.workflow.mouseOverJob(null); })
        .on('click', function(job) { self.workflow.selectJob(job); });
    },

    updateRows: function(tr, duration) {
      // update mutable row properties
      var colors = this.params.colors;
      if (duration) {
        // only update background color of rows whose jobs are not selected or mouseover
        tr.transition().duration(duration).filter(function(job) {
          return !(job.mouseover || job.selected);
        }).style('background-color', function(job) {
          if (job.status == 'RUNNING') return colors.running;
          if (job.status == 'COMPLETE') return colors.complete;
          if (job.status == 'FAILED') return colors.failed;
          return 'white';
        });
      } else {
        // rows updated due to user interaction; rapidly update background color
        tr.style('background-color', function(job) {
          if (job.mouseover) return colors.mouseover;
          if (job.selected) return colors.selected;
          if (job.status == 'RUNNING') return colors.running;
          if (job.status == 'COMPLETE') return colors.complete;
          if (job.status == 'FAILED') return colors.failed;
          return 'white';
        });
      }
      // update all other params normally
      tr.selectAll('a.job-url')
        .attr('href', function(job) { return job.trackingUrl || 'javascript:void(0);'; })
        .text(function(job) { return job.id || 'pending'; });
      tr.selectAll('td.job-status')
        .text(function (job) { return job.status || ''; });
      tr.selectAll('td.job-aliases')
        .text(function (job) { return Ambrose.commaDelimit(job.aliases); });
      tr.selectAll('td.job-features')
        .text(function (job) { return Ambrose.commaDelimit(job.features); });
      tr.selectAll('td.job-mappers')
        .text(function (job) { return Ambrose.taskProgressMessage(job.totalMappers, job.mapProgress); });
      tr.selectAll('td.job-reducers')
        .text(function (job) { return Ambrose.taskProgressMessage(job.totalReducers, job.reduceProgress); });
    },
  };

  // bind prototype to ctor
  Table.fn.init.prototype = Table.fn;
  return Table;
});
<commit_msg>Fixes table view job url click + selection bug<commit_after>/*
Copyright 2012 Twitter, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * This module defines the Table view which generates a dynamic tabular view of a Workflow's jobs.
 */
define(['jquery', 'd3', '../core', './core'], function($, d3, Ambrose, View) {
  // Table ctor
  var Table = View.Table = function(workflow, container) {
    return new View.Table.fn.init(workflow, container);
  };

  /**
   * Table prototype.
   */
  Table.fn = Table.prototype = {
    /**
     * Constructor.
     *
     * @param workflow the Workflow instance to bind to.
     * @param container the DOM element in which to render the view.
     * @param params extra options.
     */
    init: function(workflow, container, params) {
      this.workflow = workflow;
      this.container = $(container);
      this.initTable();
      this.params = $.extend(true, {
        colors: {
          running: d3.rgb(98, 196, 98).brighter(),
          complete: d3.rgb(98, 196, 98),
          failed: d3.rgb(196, 98, 98),
          mouseover: d3.rgb(98, 98, 196).brighter(),
          selected: d3.rgb(98, 98, 196),
        },
      }, params);
      var self = this;
      workflow.on('jobsLoaded', function(event, jobs) {
        self.loadTable(jobs);
      });
      workflow.on('jobStarted jobProgress jobComplete jobFailed', function(event, job) {
        self.updateTableRows([job], 350);
      });
      workflow.on('jobSelected jobMouseOver', function(event, job, prev) {
        var jobs = [];
        if (prev) jobs.push(prev);
        if (job) jobs.push(job);
        self.updateTableRows(jobs);
      });
    },

    initTable: function() {
      var self = this;
      var tbody = this.tbody = $('
');
      $('
'
        + '

'
        + '#	'
        + 'Identifier	'
        + 'Status	'
        + 'Aliases	'
        + 'Features	'
        + 'Mappers	'
        + 'Reducers	'
        + '

'
        + '
')
        .appendTo(this.container.empty())
        .append(tbody);
    },

    loadTable: function(jobs) {
      var tr = this.selectRows(jobs);
      this.removeRows(tr);
      this.createRows(tr);
      this.updateRows(tr);
    },

    updateTableRows: function(jobs, duration) {
      this.updateRows(this.selectRows(jobs), duration);
    },

    selectRows: function(jobs) {
      // select rows and bind to jobs data
      return d3.select(this.tbody.get(0)).selectAll('tr')
        .data(jobs, function(job) { return job.name; });
    },

    removeRows: function(tr) {
      // remove rows for missing jobs data
      tr.exit().remove();
    },

    createRows: function(tr) {
      // create rows for new jobs data
      tr = tr.enter().append('tr');
      tr.style('background-color', 'white');
      tr.append('td').attr('class', 'job-num')
        .text(function(job) { return 1 + (job.topologicalIndex || job.index); });
      tr.append('td').attr('class', 'job-id')
        .append('a').attr('class', 'job-url')
        .attr('target', '_blank')
        .attr('href', 'javascript:void(0);')
        .on('click', function() {
          d3.event.stopPropagation();
        });
      tr.append('td').attr('class', 'job-status');
      tr.append('td').attr('class', 'job-aliases');
      tr.append('td').attr('class', 'job-features');
      tr.append('td').attr('class', 'job-mappers');
      tr.append('td').attr('class', 'job-reducers');
      var self = this;
      tr.on('mouseover', function(job) { self.workflow.mouseOverJob(job); })
        .on('mouseout', function(job) { self.workflow.mouseOverJob(null); })
        .on('click', function(job) { self.workflow.selectJob(job); });
    },

    updateRows: function(tr, duration) {
      // update mutable row properties
      var colors = this.params.colors;
      if (duration) {
        // only update background color of rows whose jobs are not selected or mouseover
        tr.transition().duration(duration).filter(function(job) {
          return !(job.mouseover || job.selected);
        }).style('background-color', function(job) {
          if (job.status == 'RUNNING') return colors.running;
          if (job.status == 'COMPLETE') return colors.complete;
          if (job.status == 'FAILED') return colors.failed;
          return 'white';
        });
      } else {
        // rows updated due to user interaction; rapidly update background color
        tr.style('background-color', function(job) {
          if (job.mouseover) return colors.mouseover;
          if (job.selected) return colors.selected;
          if (job.status == 'RUNNING') return colors.running;
          if (job.status == 'COMPLETE') return colors.complete;
          if (job.status == 'FAILED') return colors.failed;
          return 'white';
        });
      }
      // update all other params normally
      tr.selectAll('a.job-url')
        .attr('href', function(job) { return job.trackingUrl || 'javascript:void(0);'; })
        .text(function(job) { return job.id || 'pending'; });
      tr.selectAll('td.job-status')
        .text(function (job) { return job.status || ''; });
      tr.selectAll('td.job-aliases')
        .text(function (job) { return Ambrose.commaDelimit(job.aliases); });
      tr.selectAll('td.job-features')
        .text(function (job) { return Ambrose.commaDelimit(job.features); });
      tr.selectAll('td.job-mappers')
        .text(function (job) { return Ambrose.taskProgressMessage(job.totalMappers, job.mapProgress); });
      tr.selectAll('td.job-reducers')
        .text(function (job) { return Ambrose.taskProgressMessage(job.totalReducers, job.reduceProgress); });
    },
  };

  // bind prototype to ctor
  Table.fn.init.prototype = Table.fn;
  return Table;
});
<|endoftext|>


<commit_before>// Internal modules
var path = require("path");
var fs = require("fs");

// NPM modules
var request = require("request");
var lunr = require("lunr");
var rimraf = require("rimraf");
var mkdirp = require("mkdirp");
var router = require("express").Router();
var showdown  = require("showdown");
var converter = new showdown.Converter();
var fs2obj = require('fs2obj');

// Project modules
var config = require("../lib/config");

// Define base folder for dcos/examples repo
var dcosExamplesFolder = path.join(__dirname, "../", "dcos-examples");

// Clean dcos/examples repo folder
rimraf.sync(dcosExamplesFolder);

// Global git object
var git = {};

// Create cache object for the dcos/example packages
var exampleCache = {};

// Placeholder for the pull interval
var pullInterval = {};

// Placeholder for the repository interval
var repositoryInterval = {};

// Create clean folder for dcos/examples repo
mkdirp(dcosExamplesFolder, function (err) {
    if (err) {
        console.error(err);
        process.exit(1);
    } else {
        console.log("Created folder for repo dcos/examples");
        // Instantiate git
        git = require('simple-git')(dcosExamplesFolder);
        console.log("Instantiated git");
        // Clone the repo
        git.clone("https://github.com/dcos/examples.git", dcosExamplesFolder, {}, function (err, result) {
            if (err) {
                console.log(err);
                process.exit(1);
            } else {
                console.log("Successfully cloned dcos/example repository");
                // Fill the examplesCache with the rendered results of the markdown files
                fillExamples();
                console.log("Generated and cached HTML from the dcos/example repository");
                // Load the repository initially
                loadRepository();
                console.log("Initially loaded the DC/OS repository information");
                // Set the periodical "git pull" as interval, every 5 minutes
                pullInterval = setInterval(function () {
                    var startTime = new Date().getTime();
                    git.pull("origin", "master", function(err, result) {
                        var endTime = new Date().getTime();
                        if (err) {
                            console.log("Pull from origin/master failed in " + (endTime-startTime) + "ms");
                            console.log(err);
                            //process.exit(1);
                        } else {
                            console.log("Successfully pulled from origin/master in " + (endTime-startTime) + "ms");
                            // Fill the examplesCache with the rendered results of the markdown files
                            fillExamples();
                            console.log("Updated and cached HTML from the dcos/example repository");
                        }
                    });
                }, config.application.refresh.examples);
                console.log("Started dcos/example pull interval (" + (config.application.refresh.examples/1000) + " secs)!");
                // Set periodical for repository refresh as interval
                repositoryInterval = setInterval(loadRepository, config.application.refresh.universe);
                console.log("Started load repository interval (" + (config.application.refresh.universe/1000) + " secs)!");
            }
        });
    }
});

function fillExamples() {

    // Read the folder/file structure
    var folderStructure = fs2obj(dcosExamplesFolder);

    // RegExp for finding anchor links in the markdown files
    var relativeLinkRegExp = /\(#(.*?)\)/g; // Matches "(#my-test-link)" as "my-test-link"

    // Reset exampleCache
    exampleCache = {};

    // Iterate over items
    folderStructure.items.forEach(function (item) {
        // Use folders
        if (item.type === "folder" && item.name !== "1.8") {
            var packageName = item.name.toLowerCase();
            // Set baseUrl
            var baseUrl = "https://raw.githubusercontent.com/dcos/examples/master/" + packageName + "/";
            // Example version
            var exampleVersion = null;
            // Check if 1.9 example exists
            if (fs.existsSync(dcosExamplesFolder + "/" + packageName + "/1.9/README.md")) {
                exampleVersion = "1.9";
            } else if (fs.existsSync(dcosExamplesFolder + "/" + packageName + "/1.8/README.md")) {
                exampleVersion = "1.8";
            }
            // Check if we have a valid example
            if (exampleVersion) {
                // Read README.md contents
                var exampleContents = fs.readFileSync(dcosExamplesFolder + "/" + packageName + "/" + exampleVersion + "/README.md", "utf8").toString();
                // Get relative links
                var relativeLinks = exampleContents.match(relativeLinkRegExp);
                // Check if anchor links found
                if (relativeLinks && relativeLinks.length > 0) {
                    // Handle relative links -> Replace with full link including the anchor
                    relativeLinks.forEach(function (relativeLink) {
                        var bareLink = relativeLink.replace("(", "").replace(")", "").replace(/-/g, "");
                        var replaceRelativeLink = "(/#/package/" + packageName + "/docs" + bareLink + ")";
                        exampleContents = exampleContents.replace(relativeLink, replaceRelativeLink)
                    });
                }
                // Convert to HTML and replace image sources
                var htmlCode = converter.makeHtml(exampleContents).replace(/img\//g, baseUrl + "/" + exampleVersion + "/img/"); // Replace relative URL with absolute URL

                // There is an example for this package
                exampleCache[packageName] = {
                    renderedHtml: htmlCode,
                    enabled: true
                };
            }
        }
    });

}

// Sample call to DC/OS universe
// curl -X GET -L -H "user-agent: dcos/1.8" -H "accept: application/vnd.dcos.universe.repo+json;charset=utf-8;version=v3" "https://universe.mesosphere.com/repo"

// Set request options
var options = {
    "headers": {
        "user-agent": "dcos/1.8",
        "accept": "application/vnd.dcos.universe.repo+json;charset=utf-8;version=v3"
    },
    "uri": "https://universe.mesosphere.com/repo",
    "method": "GET"
};

// Create packages singleton
var packages = {
    index: lunr(function () {
        this.field("name");
        this.field("tags", {boost: 10});
        this.field("description");
        this.field("releaseVersion");
        this.ref("name")
    }),
    map: {},
    list: []
};

// Tags
var tags = {};

// Reset packages function
var resetPackages = function () {
    packages.index = lunr(function () {
        this.field("name");
        this.field("tags", {boost: 10});
        this.field("description");
        this.field("releaseVersion");
        this.ref("name")
    });
    // Reset other properties
    packages.list.length = 0;
    packages.map = {};
};

// Reset tags function
var resetTags = function () {
    tags = {};
};

function generateSortFn(prop, reverse) {
    return function (a, b) {
        if (a[prop] < b[prop]) return reverse ? 1 : -1;
        if (a[prop] > b[prop]) return reverse ? -1 : 1;
        return 0;
    };
}

var loadRepository = function () {
    request(options, function (error, response, body) {
        if (!error && response.statusCode == 200) {

            var universeResponse = JSON.parse(body);

            // Reset package singleton
            resetPackages();

            // Reset tags singleton
            resetTags();

            // Create temporary array
            var tempPackagesArray = [];

            // Iterate over the packages/package versions
            universeResponse.packages.forEach(function (packageObj) {

                // Initialize the package if it doesn't exist yet
                if (!packages.map.hasOwnProperty(packageObj.name)) {
                    packages.map[packageObj.name] = {
                        versions: {},
                        releaseVersions: {},
                        latest: null,
                        latestVersion: -1
                    }
                }

                var imagesObj = {};
                var screenshots = {};

                // Replace plain http image urls with https urls, to get rid of mixed-content warnings
                // Workaround for excluding erroneous packages"dynatrace", "sysdig-cloud" -> Remove once they're fixed
                if (packageObj.resource && packageObj.resource.images && Object.getOwnPropertyNames(packageObj.resource.images).length > 0 && ["dynatrace", "sysdig-cloud"].indexOf(packageObj.name) === -1) {
                    if (packageObj.resource.images.screenshots) {
                        screenshots = packageObj.resource.images.screenshots;
                        delete packageObj.resource.images.screenshots;
                    }
                    Object.getOwnPropertyNames(packageObj.resource.images).forEach(function (imageType) {
                        imagesObj[imageType] = packageObj.resource.images[imageType].replace(/^http:\/\//i, 'https://');
                    });
                } else {
                    // Assign placeholder images in the correct dimensions
                    imagesObj = {
                        "icon-small": "https://placehold.it/48x48&text=" + packageObj.name,
                        "icon-medium": "https://placehold.it/96x96&text=" + packageObj.name,
                        "icon-large": "https://placehold.it/256x256&text=" + packageObj.name
                    }
                }

                // Create smaller packageObj
                var smallPackageObj = {
                    id: packageObj.name + "-" + packageObj.releaseVersion,
                    name: packageObj.name,
                    description: packageObj.description,
                    tags: packageObj.tags,
                    version: packageObj.version,
                    releaseVersion: packageObj.releaseVersion,
                    packagingVersion: packageObj.packagingVersion,
                    minDcosReleaseVersion: packageObj.minDcosReleaseVersion,
                    maintainer: packageObj.maintainer || null,
                    website: packageObj.website || null,
                    scm: packageObj.scm || null,
                    isFramework: packageObj.framework || false,
                    preInstallNotes: packageObj.preInstallNotes || null,
                    postInstallNotes: packageObj.postInstallNotes || null,
                    postUninstallNotes: packageObj.postUninstallNotes || null,
                    licenses: packageObj.licenses || null,
                    images: imagesObj,
                    screenshots: screenshots || null,
                    hasExample : ((exampleCache[packageObj.name] && exampleCache[packageObj.name].hasOwnProperty("enabled")) ? exampleCache[packageObj.name].enabled : false)
                };

                // Create version map entry
                packages.map[packageObj.name].releaseVersions[packageObj.releaseVersion.toString()] = smallPackageObj;
                packages.map[packageObj.name].versions[packageObj.version.toString()] = smallPackageObj;

                // Check if it's the latest release version, if so sure the version number
                if (packages.map[packageObj.name].latestVersion < packageObj.releaseVersion) {
                    // Set the latestVersion
                    packages.map[packageObj.name].latestVersion = packageObj.releaseVersion;
                    // Set the packageObj as current latest
                    packages.map[packageObj.name].latest = smallPackageObj;
                }

            });

            // Get latest versions per package, and store them (for search)
            Object.getOwnPropertyNames(packages.map).forEach(function (packageName) {
                // Get current package
                var latestPackageVersion = packages.map[packageName].latest;
                // Add to tempPackagesArray
                tempPackagesArray.push(latestPackageVersion);
                // Index the current package
                packages.index.add({
                    name: latestPackageVersion.name,
                    description: latestPackageVersion.description,
                    tags: latestPackageVersion.tags,
                    releaseVersion: latestPackageVersion.releaseVersion
                });
                // Add tags
                if (latestPackageVersion.tags && Array.isArray(latestPackageVersion.tags)) {
                    latestPackageVersion.tags.forEach(function (tag) {
                        if (!tags.hasOwnProperty(tag.toLowerCase())) {
                            tags[tag.toLowerCase()] = {
                                count: 0,
                                packages: []
                            };
                        }
                        tags[tag.toLowerCase()].count++;
                        tags[tag.toLowerCase()].packages.push(latestPackageVersion.name);
                    });
                }
            });
            console.log(JSON.stringify(tags));

            // Store the array as pac
            packages.list = tempPackagesArray.sort(generateSortFn("name", false));

        }
    });
};

router.get("/search", function(req, res) {

    var searchString = req.query.q;

    var searchResult = packages.index.search(searchString);

    var resultArray = [];

    searchResult.forEach(function (searchResult) {
        resultArray.push(packages.map[searchResult.ref].latest);
    });

    res.json({ results: resultArray });

});

router.get("/packages", function(req, res) {

    res.json(packages.list);

});

router.get("/package/:packageName/docs", function(req, res) {

    if (packages.map[req.params.packageName]) {

        // Check if there there's already a renderedHtml property
        if (exampleCache.hasOwnProperty(req.params.packageName) && exampleCache[req.params.packageName].renderedHtml) {

            // Send renderedHtml
            res.send(exampleCache[req.params.packageName].renderedHtml);

        } else {
            res.status(404).json({ error: "No rendered example found for " + req.params.packageName });
        }

    } else {
        res.status(404).json({ error: "No matching package found!" });
    }

});

router.get("/package/:packageName/version/:packageVersion", function(req, res) {

    if (packages.map[req.params.packageName]) {

        if (req.params.packageVersion === "latest") {
            res.json(packages.map[req.params.packageName].latest)
        } else {
            if (packages.map[req.params.packageName].versions.hasOwnProperty(req.params.packageVersion)) {
                res.json(packages.map[req.params.packageName].versions[req.params.packageVersion])
            } else {
                res.status(404).json({ error: "No matching package version found!" });
            }
        }

    } else {
        res.status(404).json({ error: "No matching package found!" });
    }

});

router.get("/package/:packageName/releaseVersion/:packageReleaseVersion", function(req, res) {

    if (packages.map[req.params.packageName]) {

        if (req.params.packageReleaseVersion === "latest") {
            res.json(packages.map[req.params.packageName].latest)
        } else {
            if (packages.map[req.params.packageName].releaseVersions.hasOwnProperty(req.params.packageReleaseVersion)) {
                res.json(packages.map[req.params.packageName].releaseVersions[req.params.packageReleaseVersion])
            } else {
                res.status(404).json({ error: "No matching package version found!" });
            }
        }

    } else {
        res.status(404).json({ error: "No matching package found!" });
    }

});

router.get("/package/:packageName/versions", function(req, res) {

    if (packages.map[req.params.packageName]) {

        res.json({
            name: req.params.packageName,
            versions: Object.getOwnPropertyNames(packages.map[req.params.packageName].versions).sort()
        });

    } else {
        res.json({ error: "No matching package found!" });
    }

});

router.get("/package/:packageName/releaseVersions", function(req, res) {

    if (packages.map[req.params.packageName]) {

        res.json({
            name: req.params.packageName,
            releaseVersions: Object.getOwnPropertyNames(packages.map[req.params.packageName].releaseVersions).sort()
        });

    } else {
        res.json({ error: "No matching package found!" });
    }

});

router.get("/health", function(req, res) {

    res.send("OK");

});

router.get("/tags", function(req, res) {

    res.json(tags);

});

module.exports = router;<commit_msg>Filter out tag which are equivalent to package names<commit_after>// Internal modules
var path = require("path");
var fs = require("fs");

// NPM modules
var request = require("request");
var lunr = require("lunr");
var rimraf = require("rimraf");
var mkdirp = require("mkdirp");
var router = require("express").Router();
var showdown  = require("showdown");
var converter = new showdown.Converter();
var fs2obj = require('fs2obj');

// Project modules
var config = require("../lib/config");

// Define base folder for dcos/examples repo
var dcosExamplesFolder = path.join(__dirname, "../", "dcos-examples");

// Clean dcos/examples repo folder
rimraf.sync(dcosExamplesFolder);

// Global git object
var git = {};

// Create cache object for the dcos/example packages
var exampleCache = {};

// Placeholder for the pull interval
var pullInterval = {};

// Placeholder for the repository interval
var repositoryInterval = {};

// Create clean folder for dcos/examples repo
mkdirp(dcosExamplesFolder, function (err) {
    if (err) {
        console.error(err);
        process.exit(1);
    } else {
        console.log("Created folder for repo dcos/examples");
        // Instantiate git
        git = require('simple-git')(dcosExamplesFolder);
        console.log("Instantiated git");
        // Clone the repo
        git.clone("https://github.com/dcos/examples.git", dcosExamplesFolder, {}, function (err, result) {
            if (err) {
                console.log(err);
                process.exit(1);
            } else {
                console.log("Successfully cloned dcos/example repository");
                // Fill the examplesCache with the rendered results of the markdown files
                fillExamples();
                console.log("Generated and cached HTML from the dcos/example repository");
                // Load the repository initially
                loadRepository();
                console.log("Initially loaded the DC/OS repository information");
                // Set the periodical "git pull" as interval, every 5 minutes
                pullInterval = setInterval(function () {
                    var startTime = new Date().getTime();
                    git.pull("origin", "master", function(err, result) {
                        var endTime = new Date().getTime();
                        if (err) {
                            console.log("Pull from origin/master failed in " + (endTime-startTime) + "ms");
                            console.log(err);
                            //process.exit(1);
                        } else {
                            console.log("Successfully pulled from origin/master in " + (endTime-startTime) + "ms");
                            // Fill the examplesCache with the rendered results of the markdown files
                            fillExamples();
                            console.log("Updated and cached HTML from the dcos/example repository");
                        }
                    });
                }, config.application.refresh.examples);
                console.log("Started dcos/example pull interval (" + (config.application.refresh.examples/1000) + " secs)!");
                // Set periodical for repository refresh as interval
                repositoryInterval = setInterval(loadRepository, config.application.refresh.universe);
                console.log("Started load repository interval (" + (config.application.refresh.universe/1000) + " secs)!");
            }
        });
    }
});

function fillExamples() {

    // Read the folder/file structure
    var folderStructure = fs2obj(dcosExamplesFolder);

    // RegExp for finding anchor links in the markdown files
    var relativeLinkRegExp = /\(#(.*?)\)/g; // Matches "(#my-test-link)" as "my-test-link"

    // Reset exampleCache
    exampleCache = {};

    // Iterate over items
    folderStructure.items.forEach(function (item) {
        // Use folders
        if (item.type === "folder" && item.name !== "1.8") {
            var packageName = item.name.toLowerCase();
            // Set baseUrl
            var baseUrl = "https://raw.githubusercontent.com/dcos/examples/master/" + packageName + "/";
            // Example version
            var exampleVersion = null;
            // Check if 1.9 example exists
            if (fs.existsSync(dcosExamplesFolder + "/" + packageName + "/1.9/README.md")) {
                exampleVersion = "1.9";
            } else if (fs.existsSync(dcosExamplesFolder + "/" + packageName + "/1.8/README.md")) {
                exampleVersion = "1.8";
            }
            // Check if we have a valid example
            if (exampleVersion) {
                // Read README.md contents
                var exampleContents = fs.readFileSync(dcosExamplesFolder + "/" + packageName + "/" + exampleVersion + "/README.md", "utf8").toString();
                // Get relative links
                var relativeLinks = exampleContents.match(relativeLinkRegExp);
                // Check if anchor links found
                if (relativeLinks && relativeLinks.length > 0) {
                    // Handle relative links -> Replace with full link including the anchor
                    relativeLinks.forEach(function (relativeLink) {
                        var bareLink = relativeLink.replace("(", "").replace(")", "").replace(/-/g, "");
                        var replaceRelativeLink = "(/#/package/" + packageName + "/docs" + bareLink + ")";
                        exampleContents = exampleContents.replace(relativeLink, replaceRelativeLink)
                    });
                }
                // Convert to HTML and replace image sources
                var htmlCode = converter.makeHtml(exampleContents).replace(/img\//g, baseUrl + "/" + exampleVersion + "/img/"); // Replace relative URL with absolute URL

                // There is an example for this package
                exampleCache[packageName] = {
                    renderedHtml: htmlCode,
                    enabled: true
                };
            }
        }
    });

}

// Sample call to DC/OS universe
// curl -X GET -L -H "user-agent: dcos/1.8" -H "accept: application/vnd.dcos.universe.repo+json;charset=utf-8;version=v3" "https://universe.mesosphere.com/repo"

// Set request options
var options = {
    "headers": {
        "user-agent": "dcos/1.8",
        "accept": "application/vnd.dcos.universe.repo+json;charset=utf-8;version=v3"
    },
    "uri": "https://universe.mesosphere.com/repo",
    "method": "GET"
};

// Create packages singleton
var packages = {
    index: lunr(function () {
        this.field("name");
        this.field("tags", {boost: 10});
        this.field("description");
        this.field("releaseVersion");
        this.ref("name")
    }),
    map: {},
    list: []
};

// Tags
var tags = {};

// Reset packages function
var resetPackages = function () {
    packages.index = lunr(function () {
        this.field("name");
        this.field("tags", {boost: 10});
        this.field("description");
        this.field("releaseVersion");
        this.ref("name")
    });
    // Reset other properties
    packages.list.length = 0;
    packages.map = {};
};

// Reset tags function
var resetTags = function () {
    tags = {};
};

function generateSortFn(prop, reverse) {
    return function (a, b) {
        if (a[prop] < b[prop]) return reverse ? 1 : -1;
        if (a[prop] > b[prop]) return reverse ? -1 : 1;
        return 0;
    };
}

var loadRepository = function () {
    request(options, function (error, response, body) {
        if (!error && response.statusCode == 200) {

            var universeResponse = JSON.parse(body);

            // Reset package singleton
            resetPackages();

            // Reset tags singleton
            resetTags();

            // Create temporary array
            var tempPackagesArray = [];

            // Iterate over the packages/package versions
            universeResponse.packages.forEach(function (packageObj) {

                // Initialize the package if it doesn't exist yet
                if (!packages.map.hasOwnProperty(packageObj.name)) {
                    packages.map[packageObj.name] = {
                        versions: {},
                        releaseVersions: {},
                        latest: null,
                        latestVersion: -1
                    }
                }

                var imagesObj = {};
                var screenshots = {};

                // Replace plain http image urls with https urls, to get rid of mixed-content warnings
                // Workaround for excluding erroneous packages"dynatrace", "sysdig-cloud" -> Remove once they're fixed
                if (packageObj.resource && packageObj.resource.images && Object.getOwnPropertyNames(packageObj.resource.images).length > 0 && ["dynatrace", "sysdig-cloud"].indexOf(packageObj.name) === -1) {
                    if (packageObj.resource.images.screenshots) {
                        screenshots = packageObj.resource.images.screenshots;
                        delete packageObj.resource.images.screenshots;
                    }
                    Object.getOwnPropertyNames(packageObj.resource.images).forEach(function (imageType) {
                        imagesObj[imageType] = packageObj.resource.images[imageType].replace(/^http:\/\//i, 'https://');
                    });
                } else {
                    // Assign placeholder images in the correct dimensions
                    imagesObj = {
                        "icon-small": "https://placehold.it/48x48&text=" + packageObj.name,
                        "icon-medium": "https://placehold.it/96x96&text=" + packageObj.name,
                        "icon-large": "https://placehold.it/256x256&text=" + packageObj.name
                    }
                }

                // Create smaller packageObj
                var smallPackageObj = {
                    id: packageObj.name + "-" + packageObj.releaseVersion,
                    name: packageObj.name,
                    description: packageObj.description,
                    tags: packageObj.tags,
                    version: packageObj.version,
                    releaseVersion: packageObj.releaseVersion,
                    packagingVersion: packageObj.packagingVersion,
                    minDcosReleaseVersion: packageObj.minDcosReleaseVersion,
                    maintainer: packageObj.maintainer || null,
                    website: packageObj.website || null,
                    scm: packageObj.scm || null,
                    isFramework: packageObj.framework || false,
                    preInstallNotes: packageObj.preInstallNotes || null,
                    postInstallNotes: packageObj.postInstallNotes || null,
                    postUninstallNotes: packageObj.postUninstallNotes || null,
                    licenses: packageObj.licenses || null,
                    images: imagesObj,
                    screenshots: screenshots || null,
                    hasExample : ((exampleCache[packageObj.name] && exampleCache[packageObj.name].hasOwnProperty("enabled")) ? exampleCache[packageObj.name].enabled : false)
                };

                // Create version map entry
                packages.map[packageObj.name].releaseVersions[packageObj.releaseVersion.toString()] = smallPackageObj;
                packages.map[packageObj.name].versions[packageObj.version.toString()] = smallPackageObj;

                // Check if it's the latest release version, if so sure the version number
                if (packages.map[packageObj.name].latestVersion < packageObj.releaseVersion) {
                    // Set the latestVersion
                    packages.map[packageObj.name].latestVersion = packageObj.releaseVersion;
                    // Set the packageObj as current latest
                    packages.map[packageObj.name].latest = smallPackageObj;
                }

            });

            // Get latest versions per package, and store them (for search)
            Object.getOwnPropertyNames(packages.map).forEach(function (packageName) {
                // Get current package
                var latestPackageVersion = packages.map[packageName].latest;
                // Add to tempPackagesArray
                tempPackagesArray.push(latestPackageVersion);
                // Index the current package
                packages.index.add({
                    name: latestPackageVersion.name,
                    description: latestPackageVersion.description,
                    tags: latestPackageVersion.tags,
                    releaseVersion: latestPackageVersion.releaseVersion
                });
                // Add tags
                if (latestPackageVersion.tags && Array.isArray(latestPackageVersion.tags)) {
                    latestPackageVersion.tags.forEach(function (tag) {
                        // Check if the tag is not a package name
                        if (Object.getOwnPropertyNames(packages.map).indexOf(tag) === -1) {
                            if (!tags.hasOwnProperty(tag.toLowerCase())) {
                                tags[tag.toLowerCase()] = {
                                    count: 0,
                                    packages: []
                                };
                            }
                            tags[tag.toLowerCase()].count++;
                            tags[tag.toLowerCase()].packages.push(latestPackageVersion.name);
                        }
                    });
                }
            });
            console.log(JSON.stringify(tags));

            // Store the array as pac
            packages.list = tempPackagesArray.sort(generateSortFn("name", false));

        }
    });
};

router.get("/search", function(req, res) {

    var searchString = req.query.q;

    var searchResult = packages.index.search(searchString);

    var resultArray = [];

    searchResult.forEach(function (searchResult) {
        resultArray.push(packages.map[searchResult.ref].latest);
    });

    res.json({ results: resultArray });

});

router.get("/packages", function(req, res) {

    res.json(packages.list);

});

router.get("/package/:packageName/docs", function(req, res) {

    if (packages.map[req.params.packageName]) {

        // Check if there there's already a renderedHtml property
        if (exampleCache.hasOwnProperty(req.params.packageName) && exampleCache[req.params.packageName].renderedHtml) {

            // Send renderedHtml
            res.send(exampleCache[req.params.packageName].renderedHtml);

        } else {
            res.status(404).json({ error: "No rendered example found for " + req.params.packageName });
        }

    } else {
        res.status(404).json({ error: "No matching package found!" });
    }

});

router.get("/package/:packageName/version/:packageVersion", function(req, res) {

    if (packages.map[req.params.packageName]) {

        if (req.params.packageVersion === "latest") {
            res.json(packages.map[req.params.packageName].latest)
        } else {
            if (packages.map[req.params.packageName].versions.hasOwnProperty(req.params.packageVersion)) {
                res.json(packages.map[req.params.packageName].versions[req.params.packageVersion])
            } else {
                res.status(404).json({ error: "No matching package version found!" });
            }
        }

    } else {
        res.status(404).json({ error: "No matching package found!" });
    }

});

router.get("/package/:packageName/releaseVersion/:packageReleaseVersion", function(req, res) {

    if (packages.map[req.params.packageName]) {

        if (req.params.packageReleaseVersion === "latest") {
            res.json(packages.map[req.params.packageName].latest)
        } else {
            if (packages.map[req.params.packageName].releaseVersions.hasOwnProperty(req.params.packageReleaseVersion)) {
                res.json(packages.map[req.params.packageName].releaseVersions[req.params.packageReleaseVersion])
            } else {
                res.status(404).json({ error: "No matching package version found!" });
            }
        }

    } else {
        res.status(404).json({ error: "No matching package found!" });
    }

});

router.get("/package/:packageName/versions", function(req, res) {

    if (packages.map[req.params.packageName]) {

        res.json({
            name: req.params.packageName,
            versions: Object.getOwnPropertyNames(packages.map[req.params.packageName].versions).sort()
        });

    } else {
        res.json({ error: "No matching package found!" });
    }

});

router.get("/package/:packageName/releaseVersions", function(req, res) {

    if (packages.map[req.params.packageName]) {

        res.json({
            name: req.params.packageName,
            releaseVersions: Object.getOwnPropertyNames(packages.map[req.params.packageName].releaseVersions).sort()
        });

    } else {
        res.json({ error: "No matching package found!" });
    }

});

router.get("/health", function(req, res) {

    res.send("OK");

});

router.get("/tags", function(req, res) {

    res.json(tags);

});

module.exports = router;<|endoftext|>


<commit_before>/* @flow */

import React, { Component } from 'react';
import { Link } from 'react-router';

export default class PatientList extends Component {
  state: {
    unsubscribeChange: () => void;
  };

  componentWillMount() {
    this.props.fetchPatientList();

    this.setState({
      unsubscribeChange: this.props.subscribeChange(),
    });
  }

  componentWillUnmount() {
    if (this.state.unsubscribeChange) {
      this.state.unsubscribeChange();
    }
  }

  props: {
    isFetching: boolean,
    fetchPatientList: () => void,
    subscribeChange: () => () => void,
    patientList: Array<PatientObject>,
  };

  render() {
    const {
      isFetching,
      patientList,
    } = this.props;

    if (isFetching) {
      return
Fetching patient list...
;
    }

    return (

            <Link to={'/patient/'} className="button">
              New
            </Link>

              {patientList.map((patient, i) =>

                  <Link to={`/patient/${patient._id}`}>
                    {patient.name || ''}
                  </Link>

              )}

    );
  }
}
<commit_msg>(refs #32) Change PatientList from div.menu to nav.panel<commit_after>/* @flow */

import React, { Component } from 'react';
import { Link } from 'react-router';

export default class PatientList extends Component {
  state: {
    unsubscribeChange: () => void;
  };

  componentWillMount() {
    this.props.fetchPatientList();

    this.setState({
      unsubscribeChange: this.props.subscribeChange(),
    });
  }

  componentWillUnmount() {
    if (this.state.unsubscribeChange) {
      this.state.unsubscribeChange();
    }
  }

  props: {
    isFetching: boolean,
    fetchPatientList: () => void,
    subscribeChange: () => () => void,
    patientList: Array<PatientObject>,
  };

  render() {
    const {
      isFetching,
      patientList,
    } = this.props;

    if (isFetching) {
      return
Fetching patient list...
;
    }

    return (

            <Link to={'/patient/'} className="button">
              New
            </Link>

            {patientList.map((patient) =>
              <Link
                key={patient._id}
                className="panel-block"
                to={`/patient/${patient._id}`}
              >{patient.name || ''}</Link>
            )}

    );
  }
}
<|endoftext|>


<commit_before>'use strict';

angular.module('ui.dashboard.widgets')
  .directive('gauge', function () {
    return {
      replace: true,
      scope: {
        label: '@',
        min: '=',
        max: '=',
        value: '='
      },
      link: function (scope, element, attrs) {
        var config = {
          size: 250,
          label: attrs.label,
          min: undefined !== scope.min ? scope.min : 0,
          max: undefined !== scope.max ? scope.max : 100,
          minorTicks: 5
        };

        var range = config.max - config.min;
        config.yellowZones = [
          { from: config.min + range * 0.75, to: config.min + range * 0.9 }
        ];
        config.redZones = [
          { from: config.min + range * 0.9, to: config.max }
        ];

        scope.gauge = new Gauge(element[0], config);
        scope.gauge.render();
        scope.gauge.redraw(scope.value);

        scope.$watch('value', function () {
          if (scope.gauge) {
            scope.gauge.redraw(scope.value);
          }
        });
      }
    };
  });<commit_msg>gauge widget, d3.js<commit_after>'use strict';

angular.module('ui.dashboard.widgets')
  .directive('gauge', function () {
    return {
      replace: true,
      scope: {
        label: '@',
        min: '=',
        max: '=',
        value: '='
      },
      link: function (scope, element, attrs) {
        var config = {
          size: 200,
          label: attrs.label,
          min: undefined !== scope.min ? scope.min : 0,
          max: undefined !== scope.max ? scope.max : 100,
          minorTicks: 5
        };

        var range = config.max - config.min;
        config.yellowZones = [
          { from: config.min + range * 0.75, to: config.min + range * 0.9 }
        ];
        config.redZones = [
          { from: config.min + range * 0.9, to: config.max }
        ];

        scope.gauge = new Gauge(element[0], config);
        scope.gauge.render();
        scope.gauge.redraw(scope.value);

        scope.$watch('value', function () {
          if (scope.gauge) {
            scope.gauge.redraw(scope.value);
          }
        });
      }
    };
  });<|endoftext|>


<commit_before>'use strict';
var db = require("./auth.js");

var slugExists = function(slug, callable) {
  db.url.findOne({"slug": slug}, function(error, doc) {
    if (error) throw error;
    if (doc) {
      generateSlug(callable);
    } else {
      callable(slug);
    }
  });
};

var findExistingUrl = function(url, callable) {
  db.url.findOne({"url": url}, function(error, doc) {
    if (error) throw error;
    if (doc) {
      callable(doc.slug);
    } else {
      callable(false);
    }
  });
};

var generateSlug = function(callable) {
  var lib = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  var slug = "";

  for (var i = 0; i < Math.floor((Math.random() * 8) + 1); i++) {
    slug += lib.charAt(Math.floor(Math.random() * lib.length));
  }

  slugExists(slug, callable);
};

exports.getUrl = function(request, response) {
  db.url.findOne({"slug": request.params.id}, function(error, url) {
    if(error) {
      response.json(error);
    } else {
      response.json(url);
    }
  });
};

exports.addUrl = function(request, response) {
  var urlRegex = /(http(s?)):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
  var urlLoopProtection = /\b(http(s?)):(\/\/|\/\/www.)tau\.pe\b/;
  var url = request.body.url;

  if(urlRegex.test(url) && false === urlLoopProtection.test(url)) {
    findExistingUrl(url, function(existingSlug) {
       if (existingSlug) {
         response.json({"slug": existingSlug});
       } else {
         generateSlug(function(slug) {
           db.url.insert({
             "url": url,
             "slug": slug,
             "date": Date.now()
           });
           response.json({"slug": slug});
         });
       }
    });
  }
};
<commit_msg>spacings<commit_after>'use strict';
var db = require("./auth.js");

var slugExists = function(slug, callable) {
  db.url.findOne({"slug": slug}, function(error, doc) {
    if (error) throw error;
    if (doc) {
      generateSlug(callable);
    } else {
      callable(slug);
    }
  });
};

var findExistingUrl = function(url, callable) {
  db.url.findOne({"url": url}, function(error, doc) {
    if (error) throw error;
    if (doc) {
      callable(doc.slug);
    } else {
      callable(false);
    }
  });
};

var generateSlug = function(callable) {
  var lib = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  var slug = "";

  for (var i = 0; i < Math.floor((Math.random() * 8) + 1); i++) {
    slug += lib.charAt(Math.floor(Math.random() * lib.length));
  }

  slugExists(slug, callable);
};

exports.getUrl = function(request, response) {
  db.url.findOne({"slug": request.params.id}, function(error, url) {
    if (error) {
      response.json(error);
    } else {
      response.json(url);
    }
  });
};

exports.addUrl = function(request, response) {
  var urlRegex = /(http(s?)):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
  var urlLoopProtection = /\b(http(s?)):(\/\/|\/\/www.)tau\.pe\b/;
  var url = request.body.url;

  if (urlRegex.test(url) && false === urlLoopProtection.test(url)) {
    findExistingUrl(url, function(existingSlug) {
       if (existingSlug) {
         response.json({"slug": existingSlug});
       } else {
         generateSlug(function(slug) {
           db.url.insert({
             "url": url,
             "slug": slug,
             "date": Date.now()
           });
           response.json({"slug": slug});
         });
       }
    });
  }
};
<|endoftext|>


<commit_before>;
(function (angular, $, undefined) {
  'use strict';
  if ($.fn['nanoScroller'] === undefined)
    throw new Error("nanoScrollerJS is not defined in jQuery");
  //jQuery must be used, cause angular method 'find' has different behavior
  if (angular.element !== $)
    throw new Error("Angular must use jQuery not jqLite");

  var AS_ELEMENT = 1, AS_ATTRIBUTE = 0;
  /**
   * Wrapper of nanoScrollerJS
   * @name sun.scrollable
   */
  var module = angular.module('sun.scrollable', ['ng']);

  /**
   * Configuration for the directive
   * @name scrollableConfig
   * @param scrollableConfig.template Template of the scroller
   * @param scrollableConfig.bottomMargin Available number of pixels from the bottom,
   *        in which it is considered that scroller is in bottom
   *
   */
  module.constant("scrollableConfig", {
    template: '

',
    bottomMargin: 40
  });

  /**
   * Default configuration of the nanoScroller
   * @name nanoScrollerDefaults
   */
  module.constant("nanoScrollerDefaults", {
    nanoClass: 'nano',
    contentClass: 'content'
  });
  module.directive("scrollable", createScrollableDirective(AS_ELEMENT));
  module.directive("scrollable", createScrollableDirective(AS_ATTRIBUTE));

  /**
   * Create directive 'scrollable' specified by variable `type`.
   * If type equals to `AS_ELEMENT` directive will replace element, otherwise template will be appended.
   * @param type Type of the directive: `AS_ELEMENT` or `AS_ATTRIBUTE`
   * @returns {function} Directive creation function
   */
  function createScrollableDirective(type) {
    var directive = function ($timeout, scrollableConfig, nanoScrollerDefaults) {
      return {
        transclude: true,
        replace: type === AS_ELEMENT,
        restrict: type === AS_ELEMENT ? 'E' : 'A',
        priority: 1000,
        template: format(scrollableConfig.template, nanoScrollerDefaults),
        link: function (scope, element, attr) {
          var oldHeight,
            listener,
            collectionListener,
            contentElement = element.find('.' + nanoScrollerDefaults.contentClass)[0],
          // Find element with nano class including current
            $nanoElement = element.hasClass(nanoScrollerDefaults.nanoClass)
              ? element
              : element.find('.' + nanoScrollerDefaults.nanoClass),
            parentElement = contentElement.parentElement,
            options = angular.extend({}, nanoScrollerDefaults, convertStringToValue(attr), scope.$eval(attr['scrollable']));
          listener = function (newHeight, oldHeight) {
            // If this is first run, create nanoScroller
            if (newHeight === oldHeight) {
              $nanoElement.nanoScroller(options)
            }
            //If scroller was on the bottom, scroll to bottom
            else if (newHeight !== oldHeight && contentElement.scrollTop &&
              (oldHeight - contentElement.scrollTop - parentElement.clientHeight) < scrollableConfig.bottomMargin) {
              $nanoElement.nanoScroller({scroll: 'bottom'});
            }
            // Otherwise just update the pane
            else {
              $nanoElement.nanoScroller();
            }
          };
          if ('static' in attr) {
            // Call scroller after transclusion
            $timeout(listener);
          }
          else {
            if (attr['watch'] || attr['watchCollection']) {
              collectionListener = function () {
                var newHeight = contentElement.scrollHeight;
                if (oldHeight === undefined) {
                  oldHeight = newHeight;
                }
                // Execution of listener must be delayed, because dom update will be later
                $timeout(listener.bind(listener, newHeight, oldHeight));
                console.log('upd')
              }
              attr['watch'] && angular.forEach(attr['watch'].replace(",", ";").split(";"), function (v) {
                scope.$watch(v, collectionListener);
              });
              attr['watchCollection'] && angular.forEach(attr['watchCollection'].replace(",", ";").split(";"), function (v) {
                scope.$watchCollection(v, collectionListener);
              });
            }
            else {
              // Now watching only for height, watching collection will be added later
              // http://jsperf.com/angular-watch-collection-vs-element-scroll-height
              scope.$watch( // Call nanoScroller, when height of content is changed
                function () {
                  return contentElement.scrollHeight;
                },
                listener);
            }
          }
          scope.$on("$destroy", function () {
            $nanoElement.nanoScroller({ destroy: true });
            $nanoElement = contentElement = parentElement = null;
          })
        }
      };
    };
    directive.$inject = ['$timeout', 'scrollableConfig', 'nanoScrollerDefaults'];
    return directive;
  }

  /**
   * Convert element attributes from stings to objects.
   * Also filter attribute (starting from '$' and class)
   * @param attr Attribute array
   * @returns {{}} Filtered object of converted attributes
   */
  function convertStringToValue(attr) {
    var result = {};
    angular.forEach(attr, function (value, key) {
      if (key.indexOf("$") === 0)
        return;
      switch (key) {
        case "true":
          value = true;
          break;
        case "false":
          value = false;
          break;
        case "null":
          value = null;
          break;
        case "class":
          return;
      }
      result[key] = value;
    });
    return result
  }

  function format(str, params) {
    return str.replace(new RegExp("{.*?}", "g"), function (a) {
      return params[a.slice(1, -1)] || "";
    })
  }

}(angular, jQuery));<commit_msg>Refactoring<commit_after>;
(function (angular, $, undefined) {
  'use strict';
  if ($.fn['nanoScroller'] === undefined)
    throw new Error("nanoScrollerJS is not defined in jQuery");
  //jQuery must be used, cause angular method 'find' has different behavior
  if (angular.element !== $)
    throw new Error("Angular must use jQuery not jqLite");

  var AS_ELEMENT = 1, AS_ATTRIBUTE = 0;
  /**
   * Wrapper of nanoScrollerJS
   * @name sun.scrollable
   */
  var module = angular.module('sun.scrollable', ['ng']);

  /**
   * Configuration for the directive
   * @name scrollableConfig
   * @param scrollableConfig.template Template of the scroller
   * @param scrollableConfig.bottomMargin Available number of pixels from the bottom,
   *        in which it is considered that scroller is in bottom
   *
   */
  module.constant("scrollableConfig", {
    template: '

',
    bottomMargin: 40
  });

  /**
   * Default configuration of the nanoScroller
   * @name nanoScrollerDefaults
   */
  module.constant("nanoScrollerDefaults", {
    nanoClass: 'nano',
    contentClass: 'content'
  });
  module.directive("scrollable", createScrollableDirective(AS_ELEMENT));
  module.directive("scrollable", createScrollableDirective(AS_ATTRIBUTE));

  /**
   * Create directive 'scrollable' specified by variable `type`.
   * If type equals to `AS_ELEMENT` directive will replace element, otherwise template will be appended.
   * @param type Type of the directive: `AS_ELEMENT` or `AS_ATTRIBUTE`
   * @returns {function} Directive creation function
   */
  function createScrollableDirective(type) {
    var directive = function ($timeout, scrollableConfig, nanoScrollerDefaults) {
      return {
        transclude: true,
        replace: type === AS_ELEMENT,
        restrict: type === AS_ELEMENT ? 'E' : 'A',
        priority: 1000,
        template: format(scrollableConfig.template, nanoScrollerDefaults),
        link: function (scope, element, attr) {
          var oldHeight,
            timerCancelCollection = angular.noop,
            timerCancelStatic = angular.noop,
            contentClass = nanoScrollerDefaults.contentClass,
            nanoClass = nanoScrollerDefaults.nanoClass,
            contentElement = element.find('.' + contentClass)[0],
            parentElement = contentElement.parentElement,
            $nanoElement = element.hasClass(nanoClass) ? element : element.find('.' + nanoClass),
            options = angular.extend({}, nanoScrollerDefaults, convertStringToValue(attr), scope.$eval(attr['scrollable']));

          function listener(newHeight, oldHeight) {
            // If this is first run, create nanoScroller
            if (newHeight === oldHeight) {
              $nanoElement.nanoScroller(options)
            }
            //If scroller was on the bottom, scroll to bottom
            else if (newHeight !== oldHeight && contentElement.scrollTop &&
              (oldHeight - contentElement.scrollTop - parentElement.clientHeight) < scrollableConfig.bottomMargin) {
              $nanoElement.nanoScroller({scroll: 'bottom'});
            }
            // Otherwise just update the pane
            else {
              $nanoElement.nanoScroller();
            }
          }

          function collectionListener() {
            var newHeight = contentElement.scrollHeight;
            if (oldHeight === undefined) {
              oldHeight = newHeight;
            }
            // Execution of listener must be delayed, because DOM update will be later
            timerCancelCollection = $timeout(listener.bind(listener, newHeight, oldHeight));
          }

          if ('static' in attr) {
            // Call scroller after transclusion
            timerCancelStatic = $timeout(listener);
          }
          else if (attr['watch'] || attr['watchCollection']) {
            angular.forEach(splitter(attr['watch']), function (v) {
              scope.$watch(v, collectionListener);
            });
            angular.forEach(splitter(attr['watchCollection']), function (v) {
              scope.$watchCollection(v, collectionListener);
            });
          }
          // If no watchers are supplied fall back to content element height check
          else {
            // http://jsperf.com/angular-watch-collection-vs-element-scroll-height
            // Call nanoScroller, when height of content is changed
            scope.$watch(function () {
                return contentElement.scrollHeight;
              },
              listener);
          }
          scope.$on("$destroy", function () {
            $nanoElement.nanoScroller({ destroy: true });
            $nanoElement = contentElement = parentElement = null;
            timerCancelCollection();
            timerCancelStatic();
          })
        }
      };
    };
    directive.$inject = ['$timeout', 'scrollableConfig', 'nanoScrollerDefaults'];
    return directive;
  }

  /**
   * Convert element attributes from stings to objects.
   * Also filter attribute (starting from '$' and class)
   * @param attr Attribute array
   * @returns {{}} Filtered object of converted attributes
   */
  function convertStringToValue(attr) {
    var result = {};
    angular.forEach(attr, function (value, key) {
      if (key.indexOf("$") === 0)
        return;
      switch (key) {
        case "true":
          value = true;
          break;
        case "false":
          value = false;
          break;
        case "null":
          value = null;
          break;
        case "class":
          return;
      }
      result[key] = value;
    });
    return result
  }

  /**
   * Split text in attribute by `,` or `;`
   * @param val Attribute value
   * @returns {Array} Array of name
   */
  function splitter(val) {
    if (!val) {
      return [];
    }
    return val.replace(",", ";").split(";");
  }

  /**
   * Format `str` in python way (only dictionary)
   * @param str Input string
   * @param params Replacing variables
   * @returns {String}
   */
  function format(str, params) {
    return str.replace(new RegExp("{.*?}", "g"), function (variable) {
      return params[variable.slice(1, -1)] || "";
    })
  }

}(angular, jQuery));<|endoftext|>


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

/**
 * Constructor
 * PartRegistry
 *
 * @see DataSource, Workbench, PartContainer, Part
 * @since: 2015.07.15
 * @author: hw.shim
 */

// @formatter:off
define([
	'external/eventEmitter/EventEmitter',
	'webida-lib/util/genetic',
	'webida-lib/util/logger/logger-client',
	'./DataSource',
	'./DataSourceRegistry',
	'./Part'
], function(
	EventEmitter,
	genetic,
	Logger,
	DataSource,
	DataSourceRegistry,
	Part
) {
	'use strict';
// @formatter:on

    /**
     * @typedef {Object.<Object, Object>} Map
     * @typedef {Object} Part
     * @typedef {Object} DataSource
     */

    var logger = new Logger();
    //logger.setConfig('level', Logger.LEVELS.log);
    //logger.off();

    function PartRegistry() {
        logger.info('new PartRegistry()');

        /** @type {Map.<DataSource, {Array.<Part>}>} */
        this.parts = new Map();

        /** @type {Map.<DataSource, {Map.<Function, Part>}>} */
        this.recentParts = new Map();
    }

    genetic.inherits(PartRegistry, EventEmitter, {

        /**
         * @param {Part} part
         */
        registerPart: function(part) {
            if (!( part instanceof Part)) {
                throw new Error('part should implement Part interface');
            }
            var dataSource = part.getContainer().getDataSource();
            var parts = this.getParts();
            if (parts.has(dataSource) === false) {
                parts.set(dataSource, []);
            }
            parts.get(dataSource).push(part);
            this.emit(DataSourceRegistry.PART_REGISTERED, part);
        },

        /**
         * @param {Part} part
         */
        unregisterPart: function(part) {
            var dataSource = part.getContainer().getDataSource();
            var parts = this.getParts();
            if (parts.has(dataSource) === true) {
                var partsOfDs = parts.get(dataSource);
                var index = partsOfDs.indexOf(part);
                partsOfDs.splice(index, 1);
                if (partsOfDs.length === 0) {
                    parts['delete'](dataSource);
                }
                this.emit(DataSourceRegistry.PART_REGISTERED, part);
            }
        },

        /**
         * @param {DataSource} dataSource
         * @return {Array} Parts related to the specified dataSource.
         * If not found returns undefined.
         */
        getPartsByDataSource: function(dataSource) {
            return this.getParts().get(dataSource);
        },

        /**
         * @param {DataSource} dataSource
         * @param {Function} PartClass
         * @return {Array} Parts with DataSource and PartClass
         */
        getPartsByClass: function(dataSource, PartClass) {
            var partsOfDs = this.getPartsByDataSource(dataSource);
            var result = [];
            if (partsOfDs) {
                partsOfDs.forEach(function(part) {
                    if ( part instanceof PartClass) {
                        result.push(part);
                    }
                });
            }
            return result;
        },

        /**
         * @param {DataSource} dataSource
         * @param {string} PartClassName
         * @return {Array} Parts with DataSource and PartClass
         */
        getPartsByClassName: function(dataSource, PartClassName) {
            var partsOfDs = this.getPartsByDataSource(dataSource);
            var result = [];
            if (partsOfDs) {
                partsOfDs.forEach(function(part) {
                    if (part.constructor === PartClassName) {
                        result.push(part);
                    }
                });
            }
            return result;
        },

        setRecentPart: function(part) {
            var dataSource = part.getContainer().getDataSource();
            if (this.recentParts.has(dataSource)) {
                this.recentParts.get(dataSource).set(part.constructor, part);
            }
        },

        /**
         * @param {DataSource} dataSource
         * @param {Function} PartClass
         * @return {Part} Recently opened Part with given DataSource and
         * PartClass. If not found returns undefined.
         */
        getRecentPart: function(dataSource, PartClass) {
            if (this.recentParts.has(dataSource)) {
                var partsOfDs = this.recentParts.get(dataSource);
                return partsOfDs.get(PartClass);
            }
        },

        /**
         * @return {Map.<DataSource, {Array.<Part>}>} PartMap
         */
        getParts: function() {
            return this.parts;
        },

        /**
         * @return {Array.<Part>} Dirty state Part array
         */
        getDirtyParts: function() {
            var parts = [];
            this.getParts().forEach(function(parts, dataSource) {
                parts.forEach(function(part) {
                    if (part.isDirty()) {
                        parts.push(part);
                    }
                });
            });
            return parts;
        }
    });

    /** @type {string} */
    PartRegistry.PART_REGISTERED = 'partRegistered';

    /** @type {string} */
    PartRegistry.PART_UNREGISTERED = 'partUnregistered';

    return PartRegistry;
});
<commit_msg>[TASK] PartRegistry : setCurrentEditorPart, getCurrentEditorPart added<commit_after>/*
* Copyright (c) 2012-2015 S-Core Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
 * Constructor
 * PartRegistry
 *
 * @see DataSource, Workbench, PartContainer, Part
 * @since: 2015.07.15
 * @author: hw.shim
 */

// @formatter:off
define([
	'external/eventEmitter/EventEmitter',
	'webida-lib/util/genetic',
	'webida-lib/util/logger/logger-client',
	'./DataSource',
	'./DataSourceRegistry',
	'./Part'
], function(
	EventEmitter,
	genetic,
	Logger,
	DataSource,
	DataSourceRegistry,
	Part
) {
	'use strict';
// @formatter:on

    /**
     * @typedef {Object.<Object, Object>} Map
     * @typedef {Object} Part
     * @typedef {Object} DataSource
     */

    var logger = new Logger();
    //logger.setConfig('level', Logger.LEVELS.log);
    //logger.off();

    function PartRegistry() {
        logger.info('new PartRegistry()');

        /** @type {Map.<DataSource, {Array.<Part>}>} */
        this.parts = new Map();

        /** @type {Map.<DataSource, {Map.<Function, Part>}>} */
        this.recentParts = new Map();

        /** @type {Part} */
        this.currentEditorPart = null;
    }

    genetic.inherits(PartRegistry, EventEmitter, {

        /**
         * @param {Part} part
         */
        registerPart: function(part) {
            if (!( part instanceof Part)) {
                throw new Error('part should implement Part interface');
            }
            var dataSource = part.getContainer().getDataSource();
            var parts = this.getParts();
            if (parts.has(dataSource) === false) {
                parts.set(dataSource, []);
            }
            parts.get(dataSource).push(part);
            this.emit(DataSourceRegistry.PART_REGISTERED, part);
        },

        /**
         * @param {Part} part
         */
        unregisterPart: function(part) {
            var dataSource = part.getContainer().getDataSource();
            var parts = this.getParts();
            if (parts.has(dataSource) === true) {
                var partsOfDs = parts.get(dataSource);
                var index = partsOfDs.indexOf(part);
                partsOfDs.splice(index, 1);
                if (partsOfDs.length === 0) {
                    parts['delete'](dataSource);
                }
                this.emit(DataSourceRegistry.PART_REGISTERED, part);
            }
        },

        /**
         * @param {DataSource} dataSource
         * @return {Array} Parts related to the specified dataSource.
         * If not found returns undefined.
         */
        getPartsByDataSource: function(dataSource) {
            return this.getParts().get(dataSource);
        },

        /**
         * @param {DataSource} dataSource
         * @param {Function} PartClass
         * @return {Array} Parts with DataSource and PartClass
         */
        getPartsByClass: function(dataSource, PartClass) {
            var partsOfDs = this.getPartsByDataSource(dataSource);
            var result = [];
            if (partsOfDs) {
                partsOfDs.forEach(function(part) {
                    if ( part instanceof PartClass) {
                        result.push(part);
                    }
                });
            }
            return result;
        },

        /**
         * @param {DataSource} dataSource
         * @param {string} PartClassName
         * @return {Array} Parts with DataSource and PartClass
         */
        getPartsByClassName: function(dataSource, PartClassName) {
            var partsOfDs = this.getPartsByDataSource(dataSource);
            var result = [];
            if (partsOfDs) {
                partsOfDs.forEach(function(part) {
                    if (part.constructor === PartClassName) {
                        result.push(part);
                    }
                });
            }
            return result;
        },

        setRecentPart: function(part) {
            var dataSource = part.getContainer().getDataSource();
            if (this.recentParts.has(dataSource)) {
                this.recentParts.get(dataSource).set(part.constructor, part);
            }
        },

        /**
         * @param {DataSource} dataSource
         * @param {Function} PartClass
         * @return {Part} Recently opened Part with given DataSource and
         * PartClass. If not found returns undefined.
         */
        getRecentPart: function(dataSource, PartClass) {
            if (this.recentParts.has(dataSource)) {
                var partsOfDs = this.recentParts.get(dataSource);
                return partsOfDs.get(PartClass);
            }
        },

        /**
         * Remember currently focused EditorPart
         * @param {Part} part
         */
        setCurrentEditorPart: function(part) {
            this.currentEditorPart = part;
        },

        /**
         * Returns currently focused EditorPart
         * @return {Part}
         */
        getCurrentEditorPart: function() {
            return this.currentEditorPart;
        },

        /**
         * @return {Map.<DataSource, {Array.<Part>}>} PartMap
         */
        getParts: function() {
            return this.parts;
        },

        /**
         * @return {Array.<Part>} Dirty state Part array
         */
        getDirtyParts: function() {
            var parts = [];
            this.getParts().forEach(function(parts, dataSource) {
                parts.forEach(function(part) {
                    if (part.isDirty()) {
                        parts.push(part);
                    }
                });
            });
            return parts;
        }
    });

    /** @type {string} */
    PartRegistry.PART_REGISTERED = 'partRegistered';

    /** @type {string} */
    PartRegistry.PART_UNREGISTERED = 'partUnregistered';

    return PartRegistry;
});
<|endoftext|>


<commit_before>'use strict';

var express = require('express');
var router = express.Router();
var extend = require('node.extend');
var redis = require("redis");
var client = redis.createClient();
var request = require('request');
var lxc = require('../lxc');

var timeoutEvents = {};
var ip2name = {};

var lxcTimeout = function(ip, time){
	var name = ip2name[ip];
	console.log(name)
	time = time || 900000; // 15 minutes
	var keys = Object.keys(timeoutEvents)
	if(keys.indexOf(name) !== -1){
		clearTimeout(timeoutEvents[name])
	}
	timeoutEvents[name] = setTimeout(function(){
		console.log('killing:', name)
		lxc.stop(name);
	}, time);
}

var runner = function(req, res, ip){
	console.log('ip:', ip);
	lxcTimeout(ip);
	console.log('code to run:\n', req.body.code);
	return request.post({url:'http://'+ip, body: JSON.stringify({code: req.body.code}) }, function(error, response, body){
		console.log(response);
		// body = JSON.parse(body);
		body['ip'] = ip.replace('10.0.', '');
		return res.json(body);
	});
};

var addToRedis = function(){
	lxc.info(req.params.name, null, function(data){
			var domain = req.query.domain || 'vm42.us';
			domain = req.params.name+'.'+domain;
			client.SADD("hosts", domain, function(){});

			var ip = data.ip + ':5000';
			client.HSET(domain, "ip", ip, redis.print);
			client.HSET(domain, "updated", (new Date).getTime(), redis.print);
			client.hset(domain, "include", "proxy.include");
			return res.json({status: 200, info: data});
	 });
};

router.get('/start/:name', function(req, res, next){
	return lxc.start(req.params.name, function(data){
		console.log('start', arguments);
		if(!data){
			return res.json({status: 500, name: req.params.name, message: data});
		}else{
			res.json({});
		}
	});
});

router.get('/live/:template/:name', function(req, res, next){
	return lxc.startEphemeral(req.params.name, req.params.template, function (data) {
		console.log('live', arguments);
		return res.json(data);
	});
});

router.get('/stop/:name', function(req, res, next){
	return lxc.stop(req.params.name, function(data){
		console.log('stop', arguments);
		if(data){
			return res.json({status: 500, name: req.params.name, message: data});
		}else{
			return res.json({status: 200});
		}
	});
});

router.get('/clone/:template/:name', function(req, res, next){
	return lxc.clone(req.params.name, req.params.template, function(data){
		console.log('clone', arguments);
		if( data.match(/Created container/) ){
			return res.json({status: 200});
		}else{
			return res.json({status: 500, message: data});
		}
	});
});

router.get('/destroy/:name', function(req, res, next){
	return lxc.destroy(req.params.name, function(data){
		console.log('destroy', arguments);
		if(data){
			return res.json({status: 500, message: data});
		}else{
			return res.json({status: 200});
		}
	});
});

router.get('/info/:name', function(req, res, next){
	return lxc.info(req.params.name, function(data){
		return res.json(data);
	});
});

router.get('/list', function(req, res, next) {
	return lxc.list(function(data){
		return res.json(data);
	});
});

router.post('/run/:ip?', function doRun(req, res, next){
	// check if server is

	return lxc.list(function(data){
		if(!req.params.ip) data = [];
		var ip = '10.0.'+ req.params.ip;
		var found = false;

		for(var idx=data.length; idx--;){
			if( data[idx]['ipv4'] === ip ){
				found = true;
				break;
			}
		}

		if(found){
			return runner(req, res, ip)
		}else{
			var name = 'crunner-'+(Math.random()*100).toString().replace('.','');
			return lxc.startEphemeral(name, 'crunner', function(data){
				ip2name[data.ip] = name;
				return runner(req, res, data.ip);
			});
		}
	});

});

module.exports = router;
<commit_msg>crunner<commit_after>'use strict';

var express = require('express');
var router = express.Router();
var extend = require('node.extend');
var redis = require("redis");
var client = redis.createClient();
var request = require('request');
var lxc = require('../lxc');

var timeoutEvents = {};
var ip2name = {};

var lxcTimeout = function(ip, time){
	var name = ip2name[ip];
	console.log(name)
	time = time || 900000; // 15 minutes
	var keys = Object.keys(timeoutEvents)
	if(keys.indexOf(name) !== -1){
		clearTimeout(timeoutEvents[name])
	}
	timeoutEvents[name] = setTimeout(function(){
		console.log('killing:', name)
		lxc.stop(name);
	}, time);
}

var runner = function(req, res, ip){
	console.log('ip:', ip);
	lxcTimeout(ip);
	console.log('code to run:\n', req.body.code);
	return request.post({url:'http://'+ip, body: JSON.stringify({code: req.body.code}) }, function(error, response, body){
		console.log('arguments:\n', arguments);
		// body = JSON.parse(body);
		body['ip'] = ip.replace('10.0.', '');
		return res.json(body);
	});
};

var addToRedis = function(){
	lxc.info(req.params.name, null, function(data){
			var domain = req.query.domain || 'vm42.us';
			domain = req.params.name+'.'+domain;
			client.SADD("hosts", domain, function(){});

			var ip = data.ip + ':5000';
			client.HSET(domain, "ip", ip, redis.print);
			client.HSET(domain, "updated", (new Date).getTime(), redis.print);
			client.hset(domain, "include", "proxy.include");
			return res.json({status: 200, info: data});
	 });
};

router.get('/start/:name', function(req, res, next){
	return lxc.start(req.params.name, function(data){
		console.log('start', arguments);
		if(!data){
			return res.json({status: 500, name: req.params.name, message: data});
		}else{
			res.json({});
		}
	});
});

router.get('/live/:template/:name', function(req, res, next){
	return lxc.startEphemeral(req.params.name, req.params.template, function (data) {
		console.log('live', arguments);
		return res.json(data);
	});
});

router.get('/stop/:name', function(req, res, next){
	return lxc.stop(req.params.name, function(data){
		console.log('stop', arguments);
		if(data){
			return res.json({status: 500, name: req.params.name, message: data});
		}else{
			return res.json({status: 200});
		}
	});
});

router.get('/clone/:template/:name', function(req, res, next){
	return lxc.clone(req.params.name, req.params.template, function(data){
		console.log('clone', arguments);
		if( data.match(/Created container/) ){
			return res.json({status: 200});
		}else{
			return res.json({status: 500, message: data});
		}
	});
});

router.get('/destroy/:name', function(req, res, next){
	return lxc.destroy(req.params.name, function(data){
		console.log('destroy', arguments);
		if(data){
			return res.json({status: 500, message: data});
		}else{
			return res.json({status: 200});
		}
	});
});

router.get('/info/:name', function(req, res, next){
	return lxc.info(req.params.name, function(data){
		return res.json(data);
	});
});

router.get('/list', function(req, res, next) {
	return lxc.list(function(data){
		return res.json(data);
	});
});

router.post('/run/:ip?', function doRun(req, res, next){
	// check if server is

	return lxc.list(function(data){
		if(!req.params.ip) data = [];
		var ip = '10.0.'+ req.params.ip;
		var found = false;

		for(var idx=data.length; idx--;){
			if( data[idx]['ipv4'] === ip ){
				found = true;
				break;
			}
		}

		if(found){
			return runner(req, res, ip)
		}else{
			var name = 'crunner-'+(Math.random()*100).toString().replace('.','');
			return lxc.startEphemeral(name, 'crunner', function(data){
				ip2name[data.ip] = name;
				return runner(req, res, data.ip);
			});
		}
	});

});

module.exports = router;
<|endoftext|>


<commit_before>const main = () => {
  document.querySelectorAll('.calendar-day-list > .calendar-list-header').forEach($el => {
    const $div = $el.nextSibling
    const $a = $div.querySelector('.list-card-title')

    $a.childNodes.forEach($child => {
      if ($child.nodeType === 3) {
        const $span = document.createElement('span')
        $span.className = 'list-card-title__span'
        $span.appendChild($child)
        $a.appendChild($span)
      }
    })

    $a.appendChild($el)
  })
}

setInterval(main, 5000);
<commit_msg>No semicolons<commit_after>const main = () => {
  document.querySelectorAll('.calendar-day-list > .calendar-list-header').forEach($el => {
    const $div = $el.nextSibling
    const $a = $div.querySelector('.list-card-title')

    $a.childNodes.forEach($child => {
      if ($child.nodeType === 3) {
        const $span = document.createElement('span')
        $span.className = 'list-card-title__span'
        $span.appendChild($child)
        $a.appendChild($span)
      }
    })

    $a.appendChild($el)
  })
}

setInterval(main, 5000)
<|endoftext|>


<commit_before>'use strict';

module.exports = grunt => {

  const
    fs = require('fs'),
    pathUtil = require('path'),
    filelist = require('stats-filelist'),
    htmlclean = require('htmlclean'),
    CleanCSS = require('clean-css'),

    SRC_DIR_PATH = pathUtil.join(__dirname, 'lib/app'),
    WORK_DIR_PATH = pathUtil.join(__dirname, 'temp/' + pathUtil.basename(SRC_DIR_PATH)),
    MAIN_HTML_PATH = pathUtil.join(SRC_DIR_PATH, 'ui.html');

  var assets = [], protectedText = [];

  function minCss(content) {
    return (new CleanCSS({keepSpecialComments: 0})).minify(content).styles;
  }

  function addProtectedText(text) {
    if (typeof text !== 'string' || text === '') { return ''; }
    protectedText.push(text);
    return '\f' + (protectedText.length - 1) + '\x07';
  }

  // Redo String#replace until target is not found
  function replaceComplete(text, re, fnc) {
    var doNext = true, reg = new RegExp(re); // safe (not literal)
    function fncWrap() {
      doNext = true;
      return fnc.apply(null, arguments);
    }
    // This is faster than using RegExp#exec() and RegExp#lastIndex,
    // because replace() isn't called more than twice in almost all cases.
    while (doNext) {
      doNext = false;
      text = text.replace(reg, fncWrap);
    }
    return text;
  }

  grunt.initConfig({
    clean: {
      workDir: {
        options: {force: true},
        src: [WORK_DIR_PATH + '/**/*']
      }
    },

    taskHelper: {
      packHtml: {
        options: {
          handlerByContent: content => {
            var packedFiles = {};

            function getContent(path) {
              var content;
              path = pathUtil.join(SRC_DIR_PATH, path);

              if (path.indexOf(SRC_DIR_PATH) !== 0) {
                grunt.fail.fatal('File doesn\'t exist in src dir: ' + path);
              } else if (!fs.existsSync(path)) {
                grunt.fail.fatal('File doesn\'t exist: ' + path);
              }
              packedFiles[path] = true;

              content = fs.readFileSync(path, {encoding: 'utf8'}).trim();
              if (/\f|\x07/.test(content)) {
                grunt.fail.fatal('\\f or \\x07 that is used as marker is included: ' + path);
              }
              return content;
            }

            function packCss(str, path) {
              var content = getContent(path)
                .replace(/^\s*(?:\/\*[\s\S]*?\*\/\s*)+/, '')
                .replace(/^\s*@charset\s+[^;]+;/gm, '');
              if (!/\.min\.css$/.test(path)) {
                content = minCss(content);
              }
              return '<style>' + addProtectedText(content) + '</style>';
            }

            function packJs(str, path) {
              var content = getContent(path)
                .replace(/^\s*(?:\/\*[\s\S]*?\*\/\s*)+/, '')
                .replace(/\s*\n\s*\/\/[^\n]*\s*$/, '')
                .replace(/^[;\s]+/, '')
                .replace(/[;\s]*$/, ';');
              return '<script>' + addProtectedText(content) + '</script>';
            }

            if (/\f|\x07/.test(content)) {
              grunt.fail.fatal('\\f or \\x07 that is used as marker is included: ' + MAIN_HTML_PATH);
            }

            content = htmlclean(content)
              .replace(/<link\b[^>]*href="(.+?)"[^>]*>/g, packCss)
              .replace(/<script\b[^>]*src="(.+?)"[^>]*><\/script>/g, packJs)
              .replace(/<\/style><style>/g, '')
              .replace(/<\/script><script>/g, '');
            // Restore protected texts
            content = replaceComplete(content, /\f(\d+)\x07/g, (s, i) => protectedText[i] || '');

            assets = filelist.getSync(SRC_DIR_PATH, {
              filter: stats => !( // list of excluded items
                  !stats.isFile() ||
                  /^\./.test(stats.name) ||
                  /\.scss$/.test(stats.name) ||
                  stats.fullPath === MAIN_HTML_PATH ||
                  stats.name === 'tr-bg.svg' ||
                  packedFiles[stats.fullPath]
                ),
              listOf: 'fullPath'
            }).map(srcPath => ({
              src: srcPath,
              dest: pathUtil.join(WORK_DIR_PATH, pathUtil.relative(SRC_DIR_PATH, srcPath))
            }));
            grunt.config.merge({
              copy: {
                assets: {
                  files: assets
                }
              }
            });

            return content;
          }
        },
        src: MAIN_HTML_PATH,
        dest: pathUtil.join(WORK_DIR_PATH, pathUtil.relative(SRC_DIR_PATH, MAIN_HTML_PATH))
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-task-helper');
  grunt.loadNpmTasks('grunt-contrib-copy');

  grunt.registerTask('default', [
    'clean:workDir',
    'taskHelper:packHtml',
    'copy:assets'
  ]);
};
<commit_msg>Add code for debugging to build script<commit_after>'use strict';

module.exports = grunt => {

  const
    fs = require('fs'),
    pathUtil = require('path'),
    filelist = require('stats-filelist'),
    htmlclean = require('htmlclean'),
    CleanCSS = require('clean-css'),

    SRC_DIR_PATH = pathUtil.join(__dirname, 'lib/app'),
    WORK_DIR_PATH = pathUtil.join(__dirname, 'temp/' + pathUtil.basename(SRC_DIR_PATH)),
    MAIN_HTML_PATH = pathUtil.join(SRC_DIR_PATH, 'ui.html');

  var assets = [], protectedText = [];

  function productSrc(src) {
    return src
      .replace(/[^\n]*\[DEBUG\/\][^\n]*\n?/g, '')
      .replace(/[^\n]*\[DEBUG\][\s\S]*?\[\/DEBUG\][^\n]*\n?/g, '');
  }

  function minCss(content) {
    return (new CleanCSS({keepSpecialComments: 0})).minify(content).styles;
  }

  function addProtectedText(text) {
    if (typeof text !== 'string' || text === '') { return ''; }
    protectedText.push(text);
    return '\f' + (protectedText.length - 1) + '\x07';
  }

  // Redo String#replace until target is not found
  function replaceComplete(text, re, fnc) {
    var doNext = true, reg = new RegExp(re); // safe (not literal)
    function fncWrap() {
      doNext = true;
      return fnc.apply(null, arguments);
    }
    // This is faster than using RegExp#exec() and RegExp#lastIndex,
    // because replace() isn't called more than twice in almost all cases.
    while (doNext) {
      doNext = false;
      text = text.replace(reg, fncWrap);
    }
    return text;
  }

  grunt.initConfig({
    clean: {
      workDir: {
        options: {force: true},
        src: [WORK_DIR_PATH + '/**/*']
      }
    },

    taskHelper: {
      packHtml: {
        options: {
          handlerByContent: content => {
            var packedFiles = {};

            function getContent(path) {
              var content;
              path = pathUtil.join(SRC_DIR_PATH, path);

              if (path.indexOf(SRC_DIR_PATH) !== 0) {
                grunt.fail.fatal('File doesn\'t exist in src dir: ' + path);
              } else if (!fs.existsSync(path)) {
                grunt.fail.fatal('File doesn\'t exist: ' + path);
              }
              packedFiles[path] = true;

              content = fs.readFileSync(path, {encoding: 'utf8'}).trim();
              if (/\f|\x07/.test(content)) {
                grunt.fail.fatal('\\f or \\x07 that is used as marker is included: ' + path);
              }
              return content;
            }

            function packCss(str, path) {
              var content = getContent(path)
                .replace(/^\s*(?:\/\*[\s\S]*?\*\/\s*)+/, '')
                .replace(/^\s*@charset\s+[^;]+;/gm, '');
              if (!/\.min\.css$/.test(path)) {
                content = minCss(content);
              }
              return '<style>' + addProtectedText(content) + '</style>';
            }

            function packJs(str, path) {
              var content = getContent(path)
                .replace(/^\s*(?:\/\*[\s\S]*?\*\/\s*)+/, '')
                .replace(/\s*\n\s*\/\/[^\n]*\s*$/, '')
                .replace(/^[;\s]+/, '')
                .replace(/[;\s]*$/, ';');
              return '<script>' + addProtectedText(content) + '</script>';
            }

            if (/\f|\x07/.test(content)) {
              grunt.fail.fatal('\\f or \\x07 that is used as marker is included: ' + MAIN_HTML_PATH);
            }

            content = htmlclean(content)
              .replace(/<link\b[^>]*href="(.+?)"[^>]*>/g, packCss)
              .replace(/<script\b[^>]*src="(.+?)"[^>]*><\/script>/g, packJs)
              .replace(/<\/style><style>/g, '')
              .replace(/<\/script><script>/g, '');
            // Restore protected texts
            content = replaceComplete(content, /\f(\d+)\x07/g, (s, i) => protectedText[i] || '');

            assets = filelist.getSync(SRC_DIR_PATH, {
              filter: stats => !( // list of excluded items
                  !stats.isFile() ||
                  /^\./.test(stats.name) ||
                  /\.scss$/.test(stats.name) ||
                  stats.fullPath === MAIN_HTML_PATH ||
                  stats.name === 'tr-bg.svg' ||
                  packedFiles[stats.fullPath]
                ),
              listOf: 'fullPath'
            }).map(srcPath => ({
              src: srcPath,
              dest: pathUtil.join(WORK_DIR_PATH, pathUtil.relative(SRC_DIR_PATH, srcPath))
            }));
            grunt.config.merge({
              copy: {
                assets: {
                  files: assets
                }
              }
            });

            return content;
          }
        },
        src: MAIN_HTML_PATH,
        dest: pathUtil.join(WORK_DIR_PATH, pathUtil.relative(SRC_DIR_PATH, MAIN_HTML_PATH))
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-task-helper');
  grunt.loadNpmTasks('grunt-contrib-copy');

  grunt.registerTask('default', [
    'clean:workDir',
    'taskHelper:packHtml',
    'copy:assets'
  ]);
};
<|endoftext|>