<commit_before>'use strict';

class ImgView extends HTMLElement {

    static get is () {
        return 'img-view';
    }

    /* 画像URIを与える */
    set src (val) {
        this.setAttribute('src', val);
    }

    get src () {
        return this.getAttribute('src');
    }

    /* 背景色を与える */
    set bgcolor (val) {
        this.setAttribute('bgcolor', val);
    }

    get bgcolor () {
        return this.getAttribute('bgcolor');
    }

    /* 角丸長方形（あるいは円形）指定をする */
    set radius (val) {
        this.setAttribute('radius', val);
    }

    get radius () {
        return this.getAttribute('radius');
    }

    createdCallback () {
        this.createShadowRoot().innerHTML = `

                <webview class='imgview-webview' partition='static' src=''></webview>

        `;
        this.updateWebView();
    }

    updateWebView () {
        var g = this.shadowRoot;
        var base = 'i.html?';
        if (this.src !== undefined) {
            var width = this.offsetWidth + 'px';
            var height = this.offsetHeight + 'px';
            var bgcolor = this.bgcolor || '#fff';
            var src = this.src || '#';
            var radius = this.radius || '0px';
            var query = 'src=' + src + '&w=' + width + '&h=' + height + '&c=' + bgcolor + '&r=' + radius;
            g.querySelector('.imgview-webview').setAttribute('src', base + query);
        }
    }

    attachedCallback () {
    }

    detachedCallback () {
    }

    attributeChangedCallback (e) {
        console.info(e)
    }
}

document.registerElement(ImgView.is, ImgView);
<commit_msg>毎回書き換えないと属性が更新されない<commit_after>'use strict';

class ImgView extends HTMLElement {

    static get is () {
        return 'img-view';
    }

    /* 画像URIを与える */
    set src (val) {
        this.setAttribute('src', val);
    }

    get src () {
        return this.getAttribute('src');
    }

    /* 背景色を与える */
    set bgcolor (val) {
        this.setAttribute('bgcolor', val);
    }

    get bgcolor () {
        return this.getAttribute('bgcolor');
    }

    /* 角丸長方形（あるいは円形）指定をする */
    set radius (val) {
        this.setAttribute('radius', val);
    }

    get radius () {
        return this.getAttribute('radius');
    }

    createdCallback () {
        this.createShadowRoot().innerHTML = `

        `;
        this.updateWebView();
    }

    updateWebView () {
        var g = this.shadowRoot;
        var imgViewRoot = g.querySelector('.imgview-root');
        var base = 'i.html?';
        if (this.src !== undefined) {
            var width = this.offsetWidth + 'px';
            var height = this.offsetHeight + 'px';
            var bgcolor = this.bgcolor || '#fff';
            var src = this.src || '#';
            var radius = this.radius || '0px';
            var query = 'src=' + src + '&w=' + width + '&h=' + height + '&c=' + bgcolor + '&r=' + radius;

            /* 各属性を確実に更新するため，毎回描画する */
            var webview ="<webview class='imgview-webview' partition='static' src='"+ (base + query) +"'></webview>";
            var layer = "

";
            imgViewRoot.innerHTML = '';
            imgViewRoot.innerHTML = webview + layer;
        }
    }

    attachedCallback () {
    }

    detachedCallback () {
    }

    attributeChangedCallback () {
        this.updateWebView();
    }
}

document.registerElement(ImgView.is, ImgView);
<|endoftext|>


<commit_before>/** @jsx React.DOM */

var EventHandlerMixin = {
  componentDidMount: function() {
    var node = $(this.getDOMNode()),
        fn = this.props.fieldName;
    node.hallo({placeholder: 'Add ' + fn});
    // Leave the content in editable mode, just disable it. Needed to show
    // the placeholder properly.
    node.data('IKS-hallo').disable();
  },

  updateData: function() {
    var html = this.getDOMNode().innerHTML,
        fn = this.props.fieldName,
        data = {};
    if (html) {
      $(this.getDOMNode()).hallo({editable: false});
      data[fn] = html;
      this.props.updateArticle(data, true);
    }
  },

  onMouseDown: function(event) {
    if (event.ctrlKey) {
      $(this.getDOMNode()).hallo({editable: true});
    }
  },
};

var ArticleTitle = React.createClass({
  mixins: [EventHandlerMixin],

  onKeyDown: function(e) {
    // Persist the data on Enter
    if (e.keyCode === 13) {
      $(this.getDOMNode()).hallo({editable: false});
      this.updateData();
    } else if (e.ctrlKey && $.inArray(e.keyCode, [66, 73, 85]) > -1) {
      // Ignore Hallo shortcuts (^B, ^I, ^U)
      e.stopPropagation();
      return false;
    }
  },

  render: function() {
    return (

    );
  }
});

var ArticleBody = React.createClass({
  mixins: [EventHandlerMixin],

  onKeyDown: function(e) {
    // Persist the data on CTRL+Enter
    if (e.ctrlKey && e.keyCode === 13) {
      $(this.getDOMNode()).hallo({editable: false});
      this.updateData();
    }
  },

  render: function() {
    return (

    );
  }
});

var Article = React.createClass({
  getDefaultProps: function() {
    return {id: '', title: '', body: '', tags: [], created_at: '', updated_at: ''};
  },

  updateArticle: function(data, partial) {
    var url = '/api/v1/article/',
        reqOpts = {
          type: 'POST',
          contentType: 'application/json',
          data: JSON.stringify(data),
          dataType: 'json'
        };

    var id = this.props.id;

    if (id) {
      // The article already exists, so just update it.
      url = url + id + '/';
      // PATCH is forbidden on GAE, so use POST and a special header so
      // Tastypie will interpret it as a partial update.
      reqOpts.headers = partial ? {'X-HTTP-Method-Override': 'PATCH'} : {};
    }

    reqOpts.url = url;

    $.ajax(reqOpts)
      .done(function(response) {
        response.key = id;
        this.props.updateArticleState(response);
      }.bind(this));
  },

  render: function() {
    var tags = [];
    this.props.tags.forEach(function(tag) {
      tags.push(
{tag}
);
    });
    return (

{this.props.created_at}

          <ArticleTitle updateArticle={this.updateArticle} fieldName="title" title={this.props.title} />

{tags}

        <ArticleBody updateArticle={this.updateArticle} fieldName="body" body={this.props.body} />

    );
  }
});

var ArticleList = React.createClass({
  render: function() {
    var articles = this.props.articles.map(function(article, i) {
      return
;
    }.bind(this));
    return
{articles}
;
  }
});

var AddArticleButton = React.createClass({
  componentDidMount: function() {
    $(this.getDOMNode()).tooltip();
  },

  onClick: function() {
    this.props.updateArticleState({});
  },

  render: function() {
    return (
      <button type="button" className="btn btn-primary" onClick={this.onClick}
          data-toggle="tooltip" data-placement="top" title="Add a new article">

      </button>
    );
  }
});

var Content = React.createClass({
  getInitialState: function() {
    return {articles: []};
  },

  componentDidMount: function() {
    $.get(this.props.articleSource, function(result) {
      this.setState({articles: result.objects});
    }.bind(this));
  },

  /**
   * Update an article that already exists in the backend.
   */
  updateExistingArticle: function(articles, articleData) {
    for (var i=0; i < articles.length; i++) {
      if (articleData.key == articles[i].id) {
        articles[i] = articleData;
        break;
      }
    }
  },

  /**
   * Update or create a placeholder article.
   */
  updatePlaceholderArticle: function(articles, articleData) {
    if ($.isEmptyObject(articleData)) {
      if (articles[0] !== undefined && $.isEmptyObject(articles[0])) {
        return;
      }
      // Add a new placeholder article
      articles.splice(0, 0, articleData);
    } else {
      if ($.isEmptyObject(articles[0])) {
        // Update an existing placeholder article
        articles[0] = articleData;
      }
    }
  },

  updateArticleState: function(data) {
    if (this.isMounted()) {
      var articles = this.state.articles;
      if (data.key) {
        this.updateExistingArticle(articles, data);
      } else {
        this.updatePlaceholderArticle(articles, data);
      }
      this.setState({articles: articles})
    }
  },

  render: function() {
    return (

            <AddArticleButton updateArticleState={this.updateArticleState} />

        <ArticleList articles={this.state.articles} updateArticleState={this.updateArticleState} />

    );
  }
});

React.renderComponent(<Content articleSource="/api/v1/article" />, document.getElementById('content'));
<commit_msg>Show placeholder on certain events<commit_after>/** @jsx React.DOM */

var EventHandlerMixin = {
  componentDidMount: function() {
    this.showPlaceholder();
  },

  showPlaceholder: function() {
    var node = $(this.getDOMNode());
    node.hallo({placeholder: 'Add ' + this.props.fieldName});
    // Leave the content in editable mode, just disable it. Needed to show
    // the placeholder properly.
    node.data('IKS-hallo').disable();
  },

  updateData: function() {
    var html = this.getDOMNode().innerHTML,
        fn = this.props.fieldName,
        data = {};
    if (html) {
      data[fn] = html;
      $(this.getDOMNode()).hallo({editable: false});
      this.props.updateArticle(data, true);
    } else {
      this.showPlaceholder();
    }
  },

  onMouseDown: function(event) {
    if (event.ctrlKey) {
      $(this.getDOMNode()).hallo({editable: true});
    }
  },
};

var ArticleTitle = React.createClass({
  mixins: [EventHandlerMixin],

  onKeyDown: function(e) {
    var node = $(this.getDOMNode());
    // Persist the data on Enter
    if (e.keyCode === 13) {
      if (node.text()) {
        node.hallo({editable: false});
        this.updateData();
      } else {
        return false;
      }
    } else if (e.keyCode === 27) {
      this.showPlaceholder();
    } else if (e.ctrlKey && $.inArray(e.keyCode, [66, 73, 85]) > -1) {
      // Ignore Hallo shortcuts (^B, ^I, ^U)
      e.stopPropagation();
      return false;
    }
  },

  render: function() {
    return (

    );
  }
});

var ArticleBody = React.createClass({
  mixins: [EventHandlerMixin],

  onKeyDown: function(e) {
    // Persist the data on CTRL+Enter
    var node = $(this.getDOMNode());
    if (e.ctrlKey && e.keyCode === 13 && node.text()) {
      node.hallo({editable: false});
      this.updateData();
    } else if (e.keyCode === 27) {
      this.showPlaceholder();
    }
  },

  render: function() {
    return (

    );
  }
});

var Article = React.createClass({
  getDefaultProps: function() {
    return {id: '', title: '', body: '', tags: [], created_at: '', updated_at: ''};
  },

  updateArticle: function(data, partial) {
    var url = '/api/v1/article/',
        reqOpts = {
          type: 'POST',
          contentType: 'application/json',
          data: JSON.stringify(data),
          dataType: 'json'
        };

    var id = this.props.id;

    if (id) {
      // The article already exists, so just update it.
      url = url + id + '/';
      // PATCH is forbidden on GAE, so use POST and a special header so
      // Tastypie will interpret it as a partial update.
      reqOpts.headers = partial ? {'X-HTTP-Method-Override': 'PATCH'} : {};
    }

    reqOpts.url = url;

    $.ajax(reqOpts)
      .done(function(response) {
        response.key = id;
        this.props.updateArticleState(response);
      }.bind(this));
  },

  render: function() {
    var tags = [];
    this.props.tags.forEach(function(tag) {
      tags.push(
{tag}
);
    });
    return (

{this.props.created_at}

          <ArticleTitle updateArticle={this.updateArticle} fieldName="title" title={this.props.title} />

{tags}

        <ArticleBody updateArticle={this.updateArticle} fieldName="body" body={this.props.body} />

    );
  }
});

var ArticleList = React.createClass({
  render: function() {
    var articles = this.props.articles.map(function(article, i) {
      return
;
    }.bind(this));
    return
{articles}
;
  }
});

var AddArticleButton = React.createClass({
  componentDidMount: function() {
    $(this.getDOMNode()).tooltip();
  },

  onClick: function() {
    this.props.updateArticleState({});
  },

  render: function() {
    return (
      <button type="button" className="btn btn-primary" onClick={this.onClick}
          data-toggle="tooltip" data-placement="top" title="Add a new article">

      </button>
    );
  }
});

var Content = React.createClass({
  getInitialState: function() {
    return {articles: []};
  },

  componentDidMount: function() {
    $.get(this.props.articleSource, function(result) {
      this.setState({articles: result.objects});
    }.bind(this));
  },

  /**
   * Update an article that already exists in the backend.
   */
  updateExistingArticle: function(articles, articleData) {
    for (var i=0; i < articles.length; i++) {
      if (articleData.key == articles[i].id) {
        articles[i] = articleData;
        break;
      }
    }
  },

  /**
   * Update or create a placeholder article.
   */
  updatePlaceholderArticle: function(articles, articleData) {
    if ($.isEmptyObject(articleData)) {
      if (articles[0] !== undefined && $.isEmptyObject(articles[0])) {
        return;
      }
      // Add a new placeholder article
      articles.splice(0, 0, articleData);
    } else {
      if ($.isEmptyObject(articles[0])) {
        // Update an existing placeholder article
        articles[0] = articleData;
      }
    }
  },

  updateArticleState: function(data) {
    if (this.isMounted()) {
      var articles = this.state.articles;
      if (data.key) {
        this.updateExistingArticle(articles, data);
      } else {
        this.updatePlaceholderArticle(articles, data);
      }
      this.setState({articles: articles})
    }
  },

  render: function() {
    return (

            <AddArticleButton updateArticleState={this.updateArticleState} />

        <ArticleList articles={this.state.articles} updateArticleState={this.updateArticleState} />

    );
  }
});

React.renderComponent(<Content articleSource="/api/v1/article" />, document.getElementById('content'));
<|endoftext|>


<commit_before>/*
 * grunt-devperf
 * https://github.com/gaelmetais/grunt-devperf
 *
 * Copyright (c) 2014 Gaël Métais
 * Licensed under the MIT license.
 */

'use strict';

var fs = require('fs');
var path = require('path');
var dataRoot = 'devperf';
var outputFile = dataRoot + '/results.json';

module.exports = function(grunt) {
  require('grunt-phantomas/tasks/phantomas')(grunt);

  grunt.registerTask('devperfAfter', 'Task to run after phantomas', function() {

    grunt.task.requires('phantomas');

    var pages = [];
    var options = this.options({});
    options.urls.forEach(function(url) {
      var page = {
        url : url,
        timingsHistory : []
      };

      var pageDataFolder = dataRoot + '/' + sanitizeFolderName(url) + '/data';
      grunt.log.writeln('Looking for result files in ' + pageDataFolder);

      var pageJsonFiles = fs.readdirSync(pageDataFolder);

      pageJsonFiles.sort(function(a, b) {
        return parseInt(a, 10) < parseInt(b, 10) ? 1 : -1;
      }).forEach(function(jsonFileName, key) {
        if (jsonFileName.indexOf('.json') === 13) {
          var timestamp = jsonFileName.substring(0, 13);

          var filePath = pageDataFolder + '/' + jsonFileName;
          grunt.log.writeln('Openning ' + filePath + ' ...');
          var content = fs.readFileSync(filePath);
          var json = JSON.parse(content);

          // Get all metrics for most recent data
          if (key === 0) {
            for (var metric in json) {
              page[metric] = json[metric].average;
            }
          }

          // Get history for each
          page.timingsHistory.push({
            'timestamp': timestamp,
            'timeToFirstByte': json.timeToFirstByte.average,
            'onDOMReadyTime': json.onDOMReadyTime.average,
            'windowOnLoadTime': json.windowOnLoadTime.average,
            'httpTrafficCompleted': json.httpTrafficCompleted.average
          });
        }
      });

      pages.push(page);
    });

    // Write result file
    fs.writeFileSync(outputFile, JSON.stringify({pages: pages}, null, 4));
    grunt.log.writeln('File "' + outputFile + '" created.');

    // Write settings file for the front
    var settingsFilePath = dataRoot + '/settings.json';
    fs.writeFileSync(settingsFilePath, JSON.stringify(options, null, 4));
    grunt.log.writeln('File "' + settingsFilePath + '" created.');

    // Copy assets
    var frontFilesPath = __dirname + '/front';
    console.log(frontFilesPath);
    grunt.file.copy(frontFilesPath + '/assets/main.js', dataRoot + '/assets/main.js');
    grunt.file.copy(frontFilesPath + '/assets/main.css', dataRoot + '/assets/main.css');
    grunt.file.copy(frontFilesPath + '/assets/interlace.png', dataRoot + '/assets/interlace.png');
    grunt.file.copy(frontFilesPath + '/assets/handlebars-v1.3.0.js', dataRoot + '/assets/handlebars-v1.3.0.js');
    grunt.file.copy(frontFilesPath + '/assets/jquery-2.1.0.min.js', dataRoot + '/assets/jquery-2.1.0.min.js');
    grunt.file.copy(frontFilesPath + '/assets/highcharts.js', dataRoot + '/assets/highcharts.js');
    grunt.log.writeln('Assets copied.');

    // Write index.html
    var indexHtml = grunt.file.read(frontFilesPath + '/index.html');
    indexHtml = indexHtml.replace('/*%%RESULTS%%*/', 'var results = ' + JSON.stringify({pages: pages}, null, 4));
    indexHtml = indexHtml.replace('/*%%SETTINGS%%*/', 'var settings = ' + JSON.stringify(options, null, 4));
    grunt.file.write(dataRoot + '/index.html', indexHtml);

  });

  // Executes the sequence (phantomas, then devperf)
  grunt.registerTask('devperf', 'Helps front-end developers to maintain a good quality, based on phantomas and grunt-phantomas.', function() {

    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      urls: [
        'http://www.google.fr'
      ],
      warnings: [
        {
          variable : "notFound",
          limit : 1,
          message: "404 errors number"
        },
        {
          variable : "smallImages",
          limit : 10,
          message: "Too many small images, build sprites"
        },
        {
          variable : "imagesWithoutDimensions",
          limit : 5,
          message: "Number of images without dimensions"
        },
        {
          variable : "commentsSize",
          limit : 1000,
          message: "Reduce size of comments in HTML"
        },
        {
          variable : "whiteSpacesSize",
          limit : 5000,
          message: "Reduce the number of whitespaces in HTML"
        },
        {
          variable : "DOMelementsCount",
          limit : 2000,
          message: "Reduce DOM elements number"
        },
        {
          variable : "documentWriteCalls",
          limit : 0,
          message: "Remove all document.write() calls"
        },
        {
          variable : "jsErrors",
          limit : 0,
          message: "Javascript errors"
        },
        {
          variable : "consoleMessages",
          limit : 0,
          message: "Remove console.log or console.*whatever*"
        },
        {
          variable : "DOMqueries",
          limit : 200,
          message: "Reduce number of DOM queries"
        },
        {
          variable : "DOMqueriesDuplicated",
          limit : 30,
          message: "Too many duplicated DOM queries"
        },
        {
          variable : "DOMinserts",
          limit : 200,
          message: "Too many DOM insertions"
        },
        {
          variable : "headersSentSize",
          limit : 20000,
          message: "Reduce size of headers sent (cookies?)"
        },
        {
          variable : "jQuerySizzleCalls",
          limit : 300,
          message: "Reduce number of Sizzle calls (= jQuery DOM queries)"
        }
      ],
      numberOfRuns: 5,
      timeout: 120
    });

    // Inject the phantomas config into grunt config
    var phantomasConfig = {};
    options.urls.forEach(function(url) {
      phantomasConfig[sanitizeFolderName(url)] = {
        options: {
          indexPath: './' + dataRoot + '/' + sanitizeFolderName(url) + '/',
          url: url,
          numberOfRuns: options.numberOfRuns,
          options: {
            timeout: options.timeout
          }
        }
      };
    });
    grunt.config.set('phantomas', phantomasConfig);
    grunt.task.run('phantomas');

    // Inject the config into devperfAfter task
    grunt.config.set('devperfAfter', {options: options});
    grunt.task.run('devperfAfter');
  });
};

function sanitizeFolderName(path) {
  var folderName = path.replace(/[\/\.\?\:\-]/g, '');
  // Shorten name if it's too long
  if (folderName.length > 50) {
    folderName = folderName.substring(0, 50);
  }
  return folderName;
}
<commit_msg>Remove debug trace<commit_after>/*
 * grunt-devperf
 * https://github.com/gaelmetais/grunt-devperf
 *
 * Copyright (c) 2014 Gaël Métais
 * Licensed under the MIT license.
 */

'use strict';

var fs = require('fs');
var path = require('path');
var dataRoot = 'devperf';
var outputFile = dataRoot + '/results.json';

module.exports = function(grunt) {
  require('grunt-phantomas/tasks/phantomas')(grunt);

  grunt.registerTask('devperfAfter', 'Task to run after phantomas', function() {

    grunt.task.requires('phantomas');

    var pages = [];
    var options = this.options({});
    options.urls.forEach(function(url) {
      var page = {
        url : url,
        timingsHistory : []
      };

      var pageDataFolder = dataRoot + '/' + sanitizeFolderName(url) + '/data';
      grunt.log.writeln('Looking for result files in ' + pageDataFolder);

      var pageJsonFiles = fs.readdirSync(pageDataFolder);

      pageJsonFiles.sort(function(a, b) {
        return parseInt(a, 10) < parseInt(b, 10) ? 1 : -1;
      }).forEach(function(jsonFileName, key) {
        if (jsonFileName.indexOf('.json') === 13) {
          var timestamp = jsonFileName.substring(0, 13);

          var filePath = pageDataFolder + '/' + jsonFileName;
          grunt.log.writeln('Openning ' + filePath + ' ...');
          var content = fs.readFileSync(filePath);
          var json = JSON.parse(content);

          // Get all metrics for most recent data
          if (key === 0) {
            for (var metric in json) {
              page[metric] = json[metric].average;
            }
          }

          // Get history for each
          page.timingsHistory.push({
            'timestamp': timestamp,
            'timeToFirstByte': json.timeToFirstByte.average,
            'onDOMReadyTime': json.onDOMReadyTime.average,
            'windowOnLoadTime': json.windowOnLoadTime.average,
            'httpTrafficCompleted': json.httpTrafficCompleted.average
          });
        }
      });

      pages.push(page);
    });

    // Write result file
    fs.writeFileSync(outputFile, JSON.stringify({pages: pages}, null, 4));
    grunt.log.writeln('File "' + outputFile + '" created.');

    // Write settings file for the front
    var settingsFilePath = dataRoot + '/settings.json';
    fs.writeFileSync(settingsFilePath, JSON.stringify(options, null, 4));
    grunt.log.writeln('File "' + settingsFilePath + '" created.');

    // Copy assets
    var frontFilesPath = __dirname + '/front';
    grunt.file.copy(frontFilesPath + '/assets/main.js', dataRoot + '/assets/main.js');
    grunt.file.copy(frontFilesPath + '/assets/main.css', dataRoot + '/assets/main.css');
    grunt.file.copy(frontFilesPath + '/assets/interlace.png', dataRoot + '/assets/interlace.png');
    grunt.file.copy(frontFilesPath + '/assets/handlebars-v1.3.0.js', dataRoot + '/assets/handlebars-v1.3.0.js');
    grunt.file.copy(frontFilesPath + '/assets/jquery-2.1.0.min.js', dataRoot + '/assets/jquery-2.1.0.min.js');
    grunt.file.copy(frontFilesPath + '/assets/highcharts.js', dataRoot + '/assets/highcharts.js');
    grunt.log.writeln('Assets copied.');

    // Write index.html
    var indexHtml = grunt.file.read(frontFilesPath + '/index.html');
    indexHtml = indexHtml.replace('/*%%RESULTS%%*/', 'var results = ' + JSON.stringify({pages: pages}, null, 4));
    indexHtml = indexHtml.replace('/*%%SETTINGS%%*/', 'var settings = ' + JSON.stringify(options, null, 4));
    grunt.file.write(dataRoot + '/index.html', indexHtml);

  });

  // Executes the sequence (phantomas, then devperf)
  grunt.registerTask('devperf', 'Helps front-end developers to maintain a good quality, based on phantomas and grunt-phantomas.', function() {

    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      urls: [
        'http://www.google.fr'
      ],
      warnings: [
        {
          variable : "notFound",
          limit : 1,
          message: "404 errors number"
        },
        {
          variable : "smallImages",
          limit : 10,
          message: "Too many small images, build sprites"
        },
        {
          variable : "imagesWithoutDimensions",
          limit : 5,
          message: "Number of images without dimensions"
        },
        {
          variable : "commentsSize",
          limit : 1000,
          message: "Reduce size of comments in HTML"
        },
        {
          variable : "whiteSpacesSize",
          limit : 5000,
          message: "Reduce the number of whitespaces in HTML"
        },
        {
          variable : "DOMelementsCount",
          limit : 2000,
          message: "Reduce DOM elements number"
        },
        {
          variable : "documentWriteCalls",
          limit : 0,
          message: "Remove all document.write() calls"
        },
        {
          variable : "jsErrors",
          limit : 0,
          message: "Javascript errors"
        },
        {
          variable : "consoleMessages",
          limit : 0,
          message: "Remove console.log or console.*whatever*"
        },
        {
          variable : "DOMqueries",
          limit : 200,
          message: "Reduce number of DOM queries"
        },
        {
          variable : "DOMqueriesDuplicated",
          limit : 30,
          message: "Too many duplicated DOM queries"
        },
        {
          variable : "DOMinserts",
          limit : 200,
          message: "Too many DOM insertions"
        },
        {
          variable : "headersSentSize",
          limit : 20000,
          message: "Reduce size of headers sent (cookies?)"
        },
        {
          variable : "jQuerySizzleCalls",
          limit : 300,
          message: "Reduce number of Sizzle calls (= jQuery DOM queries)"
        }
      ],
      numberOfRuns: 5,
      timeout: 120
    });

    // Inject the phantomas config into grunt config
    var phantomasConfig = {};
    options.urls.forEach(function(url) {
      phantomasConfig[sanitizeFolderName(url)] = {
        options: {
          indexPath: './' + dataRoot + '/' + sanitizeFolderName(url) + '/',
          url: url,
          numberOfRuns: options.numberOfRuns,
          options: {
            timeout: options.timeout
          }
        }
      };
    });
    grunt.config.set('phantomas', phantomasConfig);
    grunt.task.run('phantomas');

    // Inject the config into devperfAfter task
    grunt.config.set('devperfAfter', {options: options});
    grunt.task.run('devperfAfter');
  });
};

function sanitizeFolderName(path) {
  var folderName = path.replace(/[\/\.\?\:\-]/g, '');
  // Shorten name if it's too long
  if (folderName.length > 50) {
    folderName = folderName.substring(0, 50);
  }
  return folderName;
}
<|endoftext|>


<commit_before>"use strict";

/*
 * grunt-docular
 * Copyright (c) 2013 John Martin
 * Licensed under the MIT license.
 */
var colors = require('colors');

module.exports = function(grunt) {

    function recursiveConfigMunge(groupData) {
        if(groupData.sections) {
            groupData.groups = groupData.sections;
        }
        if(groupData.id) {
            groupData.groupId = groupData.id;
            delete groupData.id;
        }
        if(groupData.title) {
            groupData.groupTitle = groupData.title;
        }
        if(!groupData.files) {
            groupData.files = [];
        }
        if(groupData.scripts) {
            groupData.files = groupData.files.concat(groupData.scripts);
            delete groupData.scripts;
        }
        if(groupData.docs) {
            groupData.files = groupData.files.concat(groupData.docs);
            delete groupData.docs;
        }

        groupData.files = grunt.file.expand({cwd: process.cwd()}, groupData.files)

        if(groupData.groupIcon) {
            groupData.groupIcon = groupData.groupIcon.replace('icon-', '').replace('fa-', '');
        } else {
            groupData.groupIcon = 'code';
        }

        if(groupData.groups) {
            for(var i = 0, l = groupData.groups.length; i < l; i++) {
                recursiveConfigMunge(groupData.groups[i]);
            }
        }

        return groupData;
    }

    var sys = require('sys');
    var exec = require('child_process').exec;

    // ==========================================================================
    // TASKS : That can be used and configured in the intiConfigs
    // ==========================================================================

    /**
    * The main docular task
    * @return {[type]}
    */

    grunt.registerTask('docular', 'Configurable setup to generate AngularJS and other class based documentation.', function() {

        var docular = require('docular');
        var options = grunt.config('docular');

        recursiveConfigMunge(options);

        if(!options.plugins) {
            options.plugins = [require('docular-ng-plugin'), require('docular-markdown-plugin')];
        }

        //Run the gen-docs script
        var process_gen_docs_done = this.async();
        docular.genDocs(options).then(function () {
            process_gen_docs_done(true)
        }, function (err) {
            console.error(err);
            process_gen_docs_done(false);
        });
    });

    /**
     * Launch a simple nodeJS web server for documentation
     * @param  {number} requestedPort optionally specifies the port on which the server will listen.  Default is 8000
     */
    grunt.registerTask('docularserver', 'Start a simple Express server so you can view the documentation.', function(requestedPort) {

        var path=require('path');

        var options = grunt.config('docularserver') || {};
        var port = requestedPort || options.port || 8000;
        var targetDir = path.join(process.cwd(), options.targetDir)

        //Grab a new async promise
        var process_server_done = this.async();
        try {
            var express = require('express');
            var app = express();

            if (options.livereload){
                console.log('live reload enabled');
                app.use(require('connect-livereload')({
                    port: 35729
                }));
            }

            app.use('/configs',  express.static(path.join(targetDir, '/configs')));
            app.use('/controller', express.static(path.join(targetDir, '/controller')));
            app.use('/documentation', express.static(path.join(targetDir, '/documentation')));
            app.use('/resources', express.static(path.join(targetDir, '/resources')));

            app.use('/resources', function(req,res){
                res.status(404).send('');
            });

            app.use('/', function (req, res){
               res.sendfile(path.join(targetDir, '/index.html'));
            });

            var server = app.listen(port, function(){
                //Notify the user
                console.log("");
                console.log("Documentation server running at ".yellow + ('http://127.0.0.1:' +  server.address().port + '/').green);
            });
        } catch (e) {
            console.log("ERROR:".red, ' Could not start node server', e);
        }

    });

};
<commit_msg>Bugfix for docularserver task<commit_after>"use strict";

/*
 * grunt-docular
 * Copyright (c) 2013 John Martin
 * Licensed under the MIT license.
 */
var colors = require('colors');

module.exports = function(grunt) {

    function recursiveConfigMunge(groupData) {
        if(groupData.sections) {
            groupData.groups = groupData.sections;
        }
        if(groupData.id) {
            groupData.groupId = groupData.id;
            delete groupData.id;
        }
        if(groupData.title) {
            groupData.groupTitle = groupData.title;
        }
        if(!groupData.files) {
            groupData.files = [];
        }
        if(groupData.scripts) {
            groupData.files = groupData.files.concat(groupData.scripts);
            delete groupData.scripts;
        }
        if(groupData.docs) {
            groupData.files = groupData.files.concat(groupData.docs);
            delete groupData.docs;
        }

        groupData.files = grunt.file.expand({cwd: process.cwd()}, groupData.files)

        if(groupData.groupIcon) {
            groupData.groupIcon = groupData.groupIcon.replace('icon-', '').replace('fa-', '');
        } else {
            groupData.groupIcon = 'code';
        }

        if(groupData.groups) {
            for(var i = 0, l = groupData.groups.length; i < l; i++) {
                recursiveConfigMunge(groupData.groups[i]);
            }
        }

        return groupData;
    }

    var sys = require('sys');
    var exec = require('child_process').exec;

    // ==========================================================================
    // TASKS : That can be used and configured in the intiConfigs
    // ==========================================================================

    /**
    * The main docular task
    * @return {[type]}
    */

    grunt.registerTask('docular', 'Configurable setup to generate AngularJS and other class based documentation.', function() {

        var docular = require('docular');
        var options = grunt.config('docular');

        recursiveConfigMunge(options);

        if(!options.plugins) {
            options.plugins = [require('docular-ng-plugin'), require('docular-markdown-plugin')];
        }

        //Run the gen-docs script
        var process_gen_docs_done = this.async();
        docular.genDocs(options).then(function () {
            process_gen_docs_done(true)
        }, function (err) {
            console.error(err);
            process_gen_docs_done(false);
        });
    });

    /**
     * Launch a simple nodeJS web server for documentation
     * @param  {number} requestedPort optionally specifies the port on which the server will listen.  Default is 8000
     */
    grunt.registerTask('docularserver', 'Start a simple Express server so you can view the documentation.', function(requestedPort) {

        var path=require('path');

        var options = grunt.config('docularserver') || {};
        var port = requestedPort || options.port || 8000;
        var targetDir = path.join(process.cwd(), options.targetDir)

        //Grab a new async promise
        var process_server_done = this.async();
        try {
            var express = require('express');
            var app = express();

            if (options.livereload){
                console.log('live reload enabled');
                app.use(require('connect-livereload')({
                    port: 35729
                }));
            }

            app.use('/configs',  express.static(path.join(targetDir, '/configs')));
            app.use('/controller', express.static(path.join(targetDir, '/controller')));
            app.use('/documentation', express.static(path.join(targetDir, '/documentation')));
            app.use('/sources', express.static(path.join(targetDir, '/sources')));
            app.use('/resources', express.static(path.join(targetDir, '/resources')));
            app.use('/site.json', express.static(path.join(targetDir, '/site.json')));
            app.use('/structure.json', express.static(path.join(targetDir, '/structure.json')));

            app.use('/resources', function(req,res){
                res.status(404).send('');
            });

            app.use('/', function (req, res){
               res.sendfile(path.join(targetDir, '/index.html'));
            });

            var server = app.listen(port, function(){
                //Notify the user
                console.log("");
                console.log("Documentation server running at ".yellow + ('http://127.0.0.1:' +  server.address().port + '/').green);
            });
        } catch (e) {
            console.log("ERROR:".red, ' Could not start node server', e);
        }

    });

};
<|endoftext|>


<commit_before>/*
    Mercy.js
    Copyright (C) 2016 - Wesley Rhodes
    This software may be modified and distributed under the terms
    of the MIT license.  See the LICENSE file for details.

*/

/*
    #Version 0.01

    This bot is a very very very basic barebones implementation of what a Discord bot can do.
    I started this project to see what all the bot was capable of, and look forward to adding
    to it as frequently as I can.  I want to integrate more useful and powerful API's in the
    near future, and hopefully more functionality.

    TO DO NEXT:
        Admin functionality.

    THIS IS THE PERSONAL VERSION, NOT THE GITHUB VERSION, NOT THE PUBLIC VERSION.  PRIVATE
    CODE FOLLOWS, KEEP IT THAT WAY.
*/

// The block here grabs the neccesary ID's.
var servID = "<SERVER ID>"
var staffID = "<STAFF ID>"
var opID = "<OP ID>"
var safeOPID = "<SAFEOP ID>"

// auth.json is used to store token information in token : "<Your Token>".
var AuthInfo = require("./auth.json");
// List of quotes
var quotes = require("./quotes.json");

var Cleverbot = require('cleverbot-node');
cleverBot = new Cleverbot;

// Debug mode: If this is set to 1, the list of roles with their permissions and IDs will be printed to the console.
var debugMode = 0

// Neccesary dependency.
var DiscordClient = require('discord.io');

// Starting the bot with the given token.
var bot = new DiscordClient({
    autorun: true,
    token: AuthInfo.token
});

// Setting command prefixes.
var userPre = "~";
var adminPre = "!";
var maxCount = 0;

bot.on('ready', function () {
    console.log(bot.username + " online @ ");
    if (debugMode === 1) {
        console.log(bot.servers[servID].roles);
    } else {
        return;
    }
});

bot.on('disconnected', function () {
    console.log(bot.username + " (" + bot.id + ") disconnected!");
    process.exit(1);
});

bot.on('message', function (user, userID, channelID, message, rawEvent) {

    // For parsing multiple arguments.
    var messageParts = message.split(" ");

    if (userID === bot.id) {
        return;
    }

    // If userID is defined, define replyID.
    if (typeof userID !== 'undefined') {
        var replyID = "<@" + userID + "> "
    }

    // Simple hello back script.
    if (message === "Hi Mercy!") {
        if (typeof userID !== 'undefined') {
            console.log("I was greeted!");
            bot.sendMessage({
                to: channelID,
                message: "Hello " + replyID + "!"
            });
        }

        else {
            bot.sendMessage({
                to: channelID,
                message: "Hiya!"
            });
        }

    }

    if (message === userPre + "Leeki") {
        bot.sendMessage({
            to: channelID,
            message: quotes.Leeki
        })
    }

    if (message === userPre + "shrug") {
        bot.sendMessage({
            to: channelID,
            message: "¯\\_(ツ)_/¯"
        });
    }

	if (message === userPre + "ayy") {
	    bot.sendMessage({
	        to: channelID,
	        message: quotes.ayy
	    });
	}

    // Array of all possible 8-ball responses.
    var eightBall = ["It is certain.",
                     "It is decidely so.",
                     "Without a doubt.",
                     "Yes, definitely.",
                     "You may rely on it.",
                     "As I see it, yes.",
                     "Most likely.",
                     "Outlook good.",
                     "Yes.",
                     "Signs point to yes.",
                     "Reply hazy, try again.",
                     "Ask again later.",
                     "Cannot predict now.",
                     "Concentrate and ask again.",
                     "Don't count on it.",
                     "My reply is no.",
                     "My sources say no.",
                     "Outlook not so good.",
                     "Very doubtful"];

    // 8-ball implementation.
    if (messageParts[0] === userPre + "8ball") {
        var response = eightBall[Math.floor(Math.random() * eightBall.length)];
        var question = "\"";

        // Reconstruct question.
        for (i = 1; i < messageParts.length; i++) {
            if (i + 1 !== messageParts.length) {
                question += messageParts[i] + " ";
            }

            else {
                question += messageParts[i] + "\" ";
            }
        }

        // Send formatted response.
        bot.sendMessage({
            to: channelID,
            message: replyID + "You asked: " + question + "I respond with: " + response
        });
    }

    if (messageParts[0] === userPre) {
        // Reconstruct phrase.
        var statement = "";
        for (i = 1; i <= messageParts.length; i++) {
            if (i !== messageParts.length) {
                statement += messageParts[i] + " ";
            }
        }

        Cleverbot.prepare(function () {
            cleverBot.write(statement, function (response) {
                bot.sendMessage({
                    to: channelID,
                    message: response.message
                });
            });
        });
    }
});<commit_msg>Add files via upload<commit_after>/*
    Mercy.js
    Copyright (C) 2016 - Wesley Rhodes
    This software may be modified and distributed under the terms
    of the MIT license.  See the LICENSE file for details.

*/

/*
    #Version 0.01

    This bot is a very very very basic barebones implementation of what a Discord bot can do.
    I started this project to see what all the bot was capable of, and look forward to adding
    to it as frequently as I can.  I want to integrate more useful and powerful API's in the
    near future, and hopefully more functionality.

    TO DO NEXT:
        Admin functionality.
*/

// The block here grabs the neccesary ID's.
var servID = "<SERVER ID>"
var staffID = "<STAFF ID>"
var opID = "<OP ID>"
var safeOPID = "<SAFEOP ID>"

// auth.json is used to store token information in token : "<Your Token>".
var AuthInfo = require("./auth.json");
// List of quotes
var quotes = require("./quotes.json");

var Cleverbot = require('cleverbot-node');
cleverBot = new Cleverbot;

// Debug mode: If this is set to 1, the list of roles with their permissions and IDs will be printed to the console.
var debugMode = 0

// Neccesary dependency.
var DiscordClient = require('discord.io');

// Starting the bot with the given token.
var bot = new DiscordClient({
    autorun: true,
    token: AuthInfo.token
});

// Setting command prefixes.
var userPre = "~";
var adminPre = "!";
var maxCount = 0;

bot.on('ready', function () {
    console.log(bot.username + " online @ " + Date());
    if (debugMode === 1) {
        console.log(bot.servers[servID].roles);
    } else {
        return;
    }
});

bot.on('disconnected', function () {
    console.log(bot.username + " (" + bot.id + ") disconnected!");
    process.exit(1);
});

bot.on('message', function (user, userID, channelID, message, rawEvent) {

    // For parsing multiple arguments.
    var messageParts = message.split(" ");

    if (userID === bot.id) {
        return;
    }

    // If userID is defined, define replyID.
    if (typeof userID !== 'undefined') {
        var replyID = "<@" + userID + "> "
    }

    // Simple hello back script.
    if (message === "Hi Mercy!") {
        if (typeof userID !== 'undefined') {
            console.log("I was greeted!");
            bot.sendMessage({
                to: channelID,
                message: "Hello " + replyID + "!"
            });
        }

        else {
            bot.sendMessage({
                to: channelID,
                message: "Hiya!"
            });
        }

    }

    if (message === userPre + "Leeki") {
        bot.sendMessage({
            to: channelID,
            message: quotes.Leeki
        })
    }

    if (message === userPre + "shrug") {
        bot.sendMessage({
            to: channelID,
            message: "¯\\_(ツ)_/¯"
        });
    }

	if (message === userPre + "ayy") {
	    bot.sendMessage({
	        to: channelID,
	        message: quotes.ayy
	    });
	}

    // Array of all possible 8-ball responses.
    var eightBall = ["It is certain.",
                     "It is decidely so.",
                     "Without a doubt.",
                     "Yes, definitely.",
                     "You may rely on it.",
                     "As I see it, yes.",
                     "Most likely.",
                     "Outlook good.",
                     "Yes.",
                     "Signs point to yes.",
                     "Reply hazy, try again.",
                     "Ask again later.",
                     "Cannot predict now.",
                     "Concentrate and ask again.",
                     "Don't count on it.",
                     "My reply is no.",
                     "My sources say no.",
                     "Outlook not so good.",
                     "Very doubtful"];

    // 8-ball implementation.
    if (messageParts[0] === userPre + "8ball") {
        var response = eightBall[Math.floor(Math.random() * eightBall.length)];
        var question = "\"";

        // Reconstruct question.
        for (i = 1; i < messageParts.length; i++) {
            if (i + 1 !== messageParts.length) {
                question += messageParts[i] + " ";
            }

            else {
                question += messageParts[i] + "\" ";
            }
        }

        // Send formatted response.
        bot.sendMessage({
            to: channelID,
            message: replyID + "You asked: " + question + "I respond with: " + response
        });
    }

    if (messageParts[0] === userPre) {
        // Reconstruct phrase.
        var statement = "";
        for (i = 1; i <= messageParts.length; i++) {
            if (i !== messageParts.length) {
                statement += messageParts[i] + " ";
            }
        }

        Cleverbot.prepare(function () {
            cleverBot.write(statement, function (response) {
                bot.sendMessage({
                    to: channelID,
                    message: response.message
                });
            });
        });
    }
});<|endoftext|>


<commit_before>'use strict'

var mongo = require('mongojs')
var inherits = require('inherits')
var MQEmitter = require('mqemitter')
var through = require('through2')
var pump = require('pump')

function MQEmitterMongoDB (opts) {
  if (!(this instanceof MQEmitterMongoDB)) {
    return new MQEmitterMongoDB(opts)
  }

  opts = opts || {}
  opts.size = opts.size || 10 * 1024 * 1024 // 10 MB
  opts.max = opts.max || 10000 // documents
  opts.collection = opts.collection || 'pubsub'
  opts.url = opts.url || 'mongodb://127.0.0.1/mqemitter?auto_reconnect'

  this._opts = opts

  var that = this

  this._db = mongo(opts.url)
  this._collection = this._db.collection(opts.collection)

  this._collection.isCapped(function (err, capped) {
    if (that.closed) { return }

    // if it errs here, the collection might not be there
    if (err || !capped) {
      // the collection is not capped, make it so
      that._collection.runCommand('convertToCapped', {
        size: opts.size,
        max: opts.max
      }, start)
    } else {
      start()
    }
  })

  var oldEmit = MQEmitter.prototype.emit

  this._lastId = new mongo.ObjectId()

  var failures = 0
  function start () {
    if (that.closed) {
      return
    }

    if (failures++ === 10) {
      throw new Error('Connection to mongo is dead')
    }

    that._stream = that._collection.find({
      _id: { $gt: that._lastId }
    }, {}, {
      tailable: true,
      timeout: false,
      awaitData: true,
      numberOfRetries: -1
    })

    pump(that._stream, through.obj(process), start)

    function process (obj, enc, cb) {
      if (that.closed) {
        return cb()
      }

      failures = 0
      that._lastId = obj._id
      oldEmit.call(that, obj, cb)
    }
  }

  MQEmitter.call(this, opts)
}

inherits(MQEmitterMongoDB, MQEmitter)

function nop () {}
MQEmitterMongoDB.prototype.emit = function (obj, cb) {
  this._collection.insert(obj, cb || nop)
  return this
}

MQEmitterMongoDB.prototype.close = function (cb) {
  if (this.closed) {
    return
  }

  if (this._stream) {
    this._stream.destroy()
    this._stream.on('error', function () {})
    this._stream = null
  }

  var that = this
  MQEmitter.prototype.close.call(this, function () {
    that._db.close(cb)
  })

  return this
}

module.exports = MQEmitterMongoDB
<commit_msg>Wait for the server to come up.<commit_after>'use strict'

var mongo = require('mongojs')
var inherits = require('inherits')
var MQEmitter = require('mqemitter')
var through = require('through2')
var pump = require('pump')

function MQEmitterMongoDB (opts) {
  if (!(this instanceof MQEmitterMongoDB)) {
    return new MQEmitterMongoDB(opts)
  }

  opts = opts || {}
  opts.size = opts.size || 10 * 1024 * 1024 // 10 MB
  opts.max = opts.max || 10000 // documents
  opts.collection = opts.collection || 'pubsub'
  opts.url = opts.url || 'mongodb://127.0.0.1/mqemitter?auto_reconnect'

  this._opts = opts

  var that = this

  this._db = mongo(opts.url)
  this._collection = this._db.collection(opts.collection)

  function waitStartup () {
    that._db.runCommand({ ping: 1 }, function (err, res) {
      if (that.closed) { return }

      if (err || !res.ok) {
        return setTimeout(waitStartup, 1000)
      }

      that._collection.isCapped(function (err, capped) {
        if (that.closed) { return }

        // if it errs here, the collection might not be there
        if (err || !capped) {
          // the collection is not capped, make it so
          that._collection.runCommand('convertToCapped', {
            size: opts.size,
            max: opts.max
          }, start)
        } else {
          start()
        }
      })
    })
  }

  waitStartup()

  var oldEmit = MQEmitter.prototype.emit

  this._lastId = new mongo.ObjectId()

  var failures = 0
  function start () {
    if (that.closed) {
      return
    }

    if (failures++ === 10) {
      throw new Error('Connection to mongo is dead')
    }

    that._stream = that._collection.find({
      _id: { $gt: that._lastId }
    }, {}, {
      tailable: true,
      timeout: false,
      awaitData: true,
      numberOfRetries: -1
    })

    pump(that._stream, through.obj(process), start)

    function process (obj, enc, cb) {
      if (that.closed) {
        return cb()
      }

      failures = 0
      that._lastId = obj._id
      oldEmit.call(that, obj, cb)
    }
  }

  MQEmitter.call(this, opts)
}

inherits(MQEmitterMongoDB, MQEmitter)

function nop () {}
MQEmitterMongoDB.prototype.emit = function (obj, cb) {
  this._collection.insert(obj, cb || nop)
  return this
}

MQEmitterMongoDB.prototype.close = function (cb) {
  if (this.closed) {
    return
  }

  if (this._stream) {
    this._stream.destroy()
    this._stream.on('error', function () {})
    this._stream = null
  }

  var that = this
  MQEmitter.prototype.close.call(this, function () {
    that._db.close(cb)
  })

  return this
}

module.exports = MQEmitterMongoDB
<|endoftext|>


<commit_before>/*
 * grunt-htmlint
 * https://github.com/nikestep/grunt-htmlint
 *
 * Copyright (c) 2014 Nik Estep
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

    var w3cjs = require('w3cjs');
    var colors = require('colors');

    colors.setTheme({
        silly: 'rainbow',
        input: 'grey',
        verbose: 'cyan',
        prompt: 'grey',
        info: 'green',
        data: 'grey',
        help: 'cyan',
        warn: 'yellow',
        debug: 'blue',
        error: 'red',
        blue: 'blue'
    });

    grunt.registerMultiTask('htmlint', 'An HTML5 linter aimed at AngularJS projects.', function() {
        // Merge task-specific and/or target-specific options with these defaults.
        var options = this.options({
            punctuation: '.',
            separator: ', '
        });

        // Iterate over all specified file groups.
        this.files.forEach(function(f) {
            // Concat specified files.
            var src = f.src.filter(function(filepath) {
                // Warn on and remove invalid source files (if nonull was set).
                if (!grunt.file.exists(filepath)) {
                    grunt.log.warn('Source file "' + filepath + '" not found.');
                    return false;
                } else {
                    return true;
                }
            }).map(function(filepath) {
                // Read file source.
                return grunt.file.read(filepath);
            }).join(grunt.util.normalizelf(options.separator));

            // Handle options.
            src += options.punctuation;

            // Write the destination file.
            grunt.file.write(f.dest, src);

            // Print a success message.
            grunt.log.writeln('File "' + f.dest + '" created.');
        });
    });
};<commit_msg>Getting each file and running it through w3c validator<commit_after>/*
 * grunt-htmlint
 * https://github.com/nikestep/grunt-htmlint
 *
 * Copyright (c) 2014 Nik Estep
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

    var w3cjs = require('w3cjs');
    var colors = require('colors');

    colors.setTheme({
        silly: 'rainbow',
        input: 'grey',
        verbose: 'cyan',
        prompt: 'grey',
        info: 'green',
        data: 'grey',
        help: 'cyan',
        warn: 'yellow',
        debug: 'blue',
        error: 'red',
        blue: 'blue'
    });

    grunt.registerMultiTask('htmlint', 'An HTML5 linter aimed at AngularJS projects.', function() {
        // Force task into async mode and grab a handle to the "done" function.
        var done = this.async();

        // Set up the linked list for processing
        var count = 0,
            list = {
                head: null,
                tail: null
            },
            succeedCount = 0;

        // Iterate over all specified file groups.
        this.files.forEach(function(f) {
            // Build the list of files to validate
            f.src.filter(function(filepath) {
                if (!grunt.file.exists(filepath)) {
                    // Warn that the file cannot be found
                    grunt.log.warn('Source file "' + filepath + '" not found.');
                    return false;
                } else {
                    // Add the file to the list
                    count += 1;
                    if (list.head === null) {
                        list.head = {
                            path: filepath,
                            next: null
                        };
                        list.tail = list.head;
                    }
                    else {
                        list.tail.next = {
                            path: filepath,
                            next: null
                        };
                        list.tail = list.tail.next;
                    }
                    return true;
                }
            });
        });

        // Check that we got files
        if (count === 0) {
            grunt.log.warn('No source files were found');
            done();
            return;
        }

        var validate = function(file) {
            var results = w3cjs.validate({
                file: file.path, // file can either be a local file or a remote file
                output: 'json', // Defaults to 'json', other option includes html
                doctype: 'HTML5', // Defaults false for autodetect
                charset: 'utf-8', // Defaults false for autodetect
                callback: function (res) {
                    // Handle results
                    if (res.messages.length === 0) {
                        succeedCount += 1;
                    } else {
                        grunt.log.write('Linting ' + file.path + ' ...');
                        grunt.log.errorlns('ERROR');
                    }

                    // Move on to next file or finish
                    if (file.next === null) {
                        if (succeedCount === count) {
                            grunt.log.oklns(succeedCount + ' files lint free');
                        }
                        done();
                    } else {
                        validate(file.next);
                    }
                    // depending on the output type, res will either be a json object or a html string
                }
            });
        };

        // Start the validation
        validate(list.head);
    });
};<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Jarrod Overson
 * Copyright (c) 2012 "Cowboy" Ben Alman
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 */

/*jshint node:true, curly:false*/

"use strict";

var fs = require('fs'),
    path = require('path'),
    URL = require('url'),
    sysopen = require('open'),
    grunt = require('grunt');

var server = require('./lib/server'),
    jasmine = require('./lib/jasmine'),
    phantomjs = require('./lib/phantomjs');

var baseDir = '.',
    tmpRunner = '_SpecRunner.html',
    options,
    defaultOptions = {
      timeout : 10000,
      specs   : [],
      src     : [],
      helpers : [],
      template: {
        src: __dirname + '/../jasmine/SpecRunner.tmpl',
        opts: {}
      },
      phantomjs : {}
};

module.exports = task;

function task(grunt){
  grunt.util = grunt.utils;

  grunt.registerTask('jasmine', 'Run jasmine specs headlessly through PhantomJS.', function() {
    options = grunt.config('jasmine');

    var done = this.async();

    task.phantomRunner(options, function(err,status) {
      if (status && status.failed > 0) {
        grunt.log.error(grunt.util._("%s of %s total specs failed").sprintf(status.failed, status.total));
      }
      if (err) grunt.log.error(err);
      done(!err && status.failed === 0);
    });

  });

  grunt.registerTask('jasmine-server', 'Run jasmine specs headlessly through PhantomJS.', function() {
    var done   = this.async();
    task.interactiveRunner(grunt.config('jasmine'));
  });

  phantomjs.on('fail.timeout',function(){
    grunt.log.writeln();
    grunt.warn('PhantomJS timed out, possibly due to an unfinished async spec.', 90);
  });

  phantomjs.on('console',console.log.bind(console));
  phantomjs.on('verbose',grunt.verbose.writeln.bind(grunt.verbose));
  phantomjs.on('debug', grunt.log.debug.bind(grunt.log, 'phantomjs'));
  phantomjs.on('write', grunt.log.write.bind(grunt.log));
  phantomjs.on('writeln', grunt.log.writeln.bind(grunt.log));
  phantomjs.on('onError',function(string, trace){
    if (trace && trace.stack) {
      console.log(trace.stack.red);
    } else {
      console.log(string.red);
    }
  });

  phantomjs.on('jasmine.*', function() {
    //var args = [this.event].concat(grunt.util.toArray(arguments));
    // grunt 0.4.0
    // grunt.event.emit.apply(grunt.event, args);
  });
}

task.phantomRunner = function(options,cb){
  options = grunt.util._.extend({},defaultOptions,options);

  var phantomReporters = [
      grunt.task.getFile('jasmine/reporters/ConsoleReporter.js'),
      grunt.task.getFile('jasmine/reporters/JUnitReporter.js')
    ],
    port = (options.server && options.server.port) || 8888;

  var url = URL.format({
    protocol : 'http',
    hostname : '127.0.0.1',
    port : port + '',
    pathname : path.join(baseDir,tmpRunner)
  });

  grunt.verbose.subhead('Testing jasmine specs via phantom').or.writeln('Testing jasmine specs via phantom');
  jasmine.buildSpecrunner(baseDir, options, phantomReporters);
  var server = startServer(baseDir, port);

  runPhantom(url,options,phantomReporters.length,function(err,status){
    server.close();
    if (typeof cb === 'function') cb(err,status);
  });
};

task.interactiveRunner = function(options,cb){
  options = grunt.util._.extend({},defaultOptions,options);

  var port = (options.server && options.server.port) || 8888;

  var url = URL.format({
    protocol : 'http',
    hostname : '127.0.0.1',
    port : port + '',
    pathname : path.join(baseDir,tmpRunner)
  });

  jasmine.buildSpecrunner(baseDir, options, []);
  startServer(baseDir, port);
  grunt.log.writeln('Run your tests at ' + url);

  var serverSettings = grunt.config('jasmine-server') || {};
  if (serverSettings.browser !== false) sysopen(url);

  if (typeof cb === 'function') cb();
};

function startServer(base, port) {
  grunt.verbose.writeln('Starting static web server on port ' + port);
  return server.start(base, port, { debug : grunt.option('debug') });
}

function runPhantom(url,options,numReporters, cb) {
  var status;
  setupTestListeners(options,numReporters,function(testStatus){
    status = testStatus;
  });
  phantomjs.spawn(url, {
    failCode : 90,
    options  : options,
    done     : function(err){
      cb(err,status);
    }
  });
}

function setupTestListeners(options,numReporters, doneCallback) {
  var status = {
    specs    : 0,
    failed   : 0,
    passed   : 0,
    total    : 0,
    skipped  : 0,
    duration : 0
  };

  phantomjs.on('jasmine.begin',function(){
    grunt.verbose.writeln('Starting...');
  });

  phantomjs.on('jasmine.writeFile',function(type,filename, xml){
    var dir = options[type] && options[type].output;
    if (dir) {
      grunt.file.mkdir(dir);
      grunt.file.write(path.join(dir, filename), xml);
    }
  });

  phantomjs.on('jasmine.testDone',function(totalAssertions, passedAssertions, failedAssertions, skippedAssertions){
    status.specs++;
    status.failed  += failedAssertions;
    status.passed  += passedAssertions;
    status.total   += totalAssertions;
    status.skipped += skippedAssertions;
  });

  phantomjs.on('jasmine.done',function(elapsed){
    grunt.verbose.writeln('All reporters done.');
    phantomjs.halt();
    status.duration = elapsed;
    doneCallback(status);
  });

  var reportersDone = 0;
  phantomjs.on('jasmine.done.*',function(){
    reportersDone++;
    if (reportersDone === numReporters) phantomjs.emit('jasmine.done');
  });

  phantomjs.on('jasmine.done.ConsoleReporter',function(){
  });
  phantomjs.on('jasmine.done.JUnitReporter',function(){
  });

  phantomjs.on('jasmine.done_fail',function(url){
    grunt.log.error();
    grunt.warn('PhantomJS unable to load "' + url + '" URI.', 90);
  });
}

<commit_msg>backwards/forward compat<commit_after>/*
 * Copyright (c) 2012 Jarrod Overson
 * Copyright (c) 2012 "Cowboy" Ben Alman
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 */

/*jshint node:true, curly:false*/

"use strict";

var fs = require('fs'),
    path = require('path'),
    URL = require('url'),
    sysopen = require('open'),
    grunt = require('grunt');

grunt.util = grunt.utils;

var server = require('./lib/server'),
    jasmine = require('./lib/jasmine'),
    phantomjs = require('./lib/phantomjs');

var baseDir = '.',
    tmpRunner = '_SpecRunner.html',
    options,
    defaultOptions = {
      timeout : 10000,
      specs   : [],
      src     : [],
      helpers : [],
      template: {
        src: __dirname + '/../jasmine/SpecRunner.tmpl',
        opts: {}
      },
      phantomjs : {}
};

module.exports = task;

function task(grunt){
  grunt.util = grunt.utils;

  grunt.registerTask('jasmine', 'Run jasmine specs headlessly through PhantomJS.', function() {
    options = grunt.config('jasmine');

    var done = this.async();

    task.phantomRunner(options, function(err,status) {
      if (status && status.failed > 0) {
        grunt.log.error(grunt.util._("%s of %s total specs failed").sprintf(status.failed, status.total));
      }
      if (err) grunt.log.error(err);
      done(!err && status.failed === 0);
    });

  });

  grunt.registerTask('jasmine-server', 'Run jasmine specs headlessly through PhantomJS.', function() {
    var done   = this.async();
    task.interactiveRunner(grunt.config('jasmine'));
  });

  phantomjs.on('fail.timeout',function(){
    grunt.log.writeln();
    grunt.warn('PhantomJS timed out, possibly due to an unfinished async spec.', 90);
  });

  phantomjs.on('console',console.log.bind(console));
  phantomjs.on('verbose',grunt.verbose.writeln.bind(grunt.verbose));
  phantomjs.on('debug', grunt.log.debug.bind(grunt.log, 'phantomjs'));
  phantomjs.on('write', grunt.log.write.bind(grunt.log));
  phantomjs.on('writeln', grunt.log.writeln.bind(grunt.log));
  phantomjs.on('onError',function(string, trace){
    if (trace && trace.stack) {
      console.log(trace.stack.red);
    } else {
      console.log(string.red);
    }
  });

  phantomjs.on('jasmine.*', function() {
    //var args = [this.event].concat(grunt.util.toArray(arguments));
    // grunt 0.4.0
    // grunt.event.emit.apply(grunt.event, args);
  });
}

task.phantomRunner = function(options,cb){
  options = grunt.util._.extend({},defaultOptions,options);

  var phantomReporters = [
      grunt.task.getFile('jasmine/reporters/ConsoleReporter.js'),
      grunt.task.getFile('jasmine/reporters/JUnitReporter.js')
    ],
    port = (options.server && options.server.port) || 8888;

  var url = URL.format({
    protocol : 'http',
    hostname : '127.0.0.1',
    port : port + '',
    pathname : path.join(baseDir,tmpRunner)
  });

  grunt.verbose.subhead('Testing jasmine specs via phantom').or.writeln('Testing jasmine specs via phantom');
  jasmine.buildSpecrunner(baseDir, options, phantomReporters);
  var server = startServer(baseDir, port);

  runPhantom(url,options,phantomReporters.length,function(err,status){
    server.close();
    if (typeof cb === 'function') cb(err,status);
  });
};

task.interactiveRunner = function(options,cb){
  options = grunt.util._.extend({},defaultOptions,options);

  var port = (options.server && options.server.port) || 8888;

  var url = URL.format({
    protocol : 'http',
    hostname : '127.0.0.1',
    port : port + '',
    pathname : path.join(baseDir,tmpRunner)
  });

  jasmine.buildSpecrunner(baseDir, options, []);
  startServer(baseDir, port);
  grunt.log.writeln('Run your tests at ' + url);

  var serverSettings = grunt.config('jasmine-server') || {};
  if (serverSettings.browser !== false) sysopen(url);

  if (typeof cb === 'function') cb();
};

function startServer(base, port) {
  grunt.verbose.writeln('Starting static web server on port ' + port);
  return server.start(base, port, { debug : grunt.option('debug') });
}

function runPhantom(url,options,numReporters, cb) {
  var status;
  setupTestListeners(options,numReporters,function(testStatus){
    status = testStatus;
  });
  phantomjs.spawn(url, {
    failCode : 90,
    options  : options,
    done     : function(err){
      cb(err,status);
    }
  });
}

function setupTestListeners(options,numReporters, doneCallback) {
  var status = {
    specs    : 0,
    failed   : 0,
    passed   : 0,
    total    : 0,
    skipped  : 0,
    duration : 0
  };

  phantomjs.on('jasmine.begin',function(){
    grunt.verbose.writeln('Starting...');
  });

  phantomjs.on('jasmine.writeFile',function(type,filename, xml){
    var dir = options[type] && options[type].output;
    if (dir) {
      grunt.file.mkdir(dir);
      grunt.file.write(path.join(dir, filename), xml);
    }
  });

  phantomjs.on('jasmine.testDone',function(totalAssertions, passedAssertions, failedAssertions, skippedAssertions){
    status.specs++;
    status.failed  += failedAssertions;
    status.passed  += passedAssertions;
    status.total   += totalAssertions;
    status.skipped += skippedAssertions;
  });

  phantomjs.on('jasmine.done',function(elapsed){
    grunt.verbose.writeln('All reporters done.');
    phantomjs.halt();
    status.duration = elapsed;
    doneCallback(status);
  });

  var reportersDone = 0;
  phantomjs.on('jasmine.done.*',function(){
    reportersDone++;
    if (reportersDone === numReporters) phantomjs.emit('jasmine.done');
  });

  phantomjs.on('jasmine.done.ConsoleReporter',function(){
  });
  phantomjs.on('jasmine.done.JUnitReporter',function(){
  });

  phantomjs.on('jasmine.done_fail',function(url){
    grunt.log.error();
    grunt.warn('PhantomJS unable to load "' + url + '" URI.', 90);
  });
}

<|endoftext|>


<commit_before>var pg = require('pg');

module.exports = function (grunt) {
  var config = grunt.config.get('pgutils'),
    _ = grunt.util._,
    log = function (args, depth) { console.log(require('util').inspect(args, { colors: true, depth: depth })); };

  grunt.task.registerTask('backup-sp', 'Dump PostgresSQL stored procedures in separated files.', function () {
    var done = this.async(),
      pgClient = null,
      // Success count
      success = 0,
      query;

    var serverConfig = (this.args.length)? config.connections[parseInt(this.args[0], 10)] : config.connections[0];

    pgClient = new pg.Client(serverConfig);
    // Actually connecting to postgreSQL
    pgClient.connect();

    query = pgClient.query("select pg_get_functiondef(sp.oid) as functiondef, sp.proname as proname, sp.pronargs as pronargs from (select oid, proname, pronargs from pg_proc where proname ~ '" + config.spRegex + "') as sp");
    query.on('row', function (row, result) {
      grunt.file.write(config.dest + '/' + row.proname + '_' + row.pronargs + '.sql', row.functiondef);
      success++;
    });

    query.on('error', grunt.fail.fatal);
    query.on('end', function () {
      grunt.log.ok('Correctly backupped ' + success + ' stored procedures.');
      done();
    });
  });

  grunt.task.registerTask('restore-sp', 'Restore stored procedures.', function () {
    var done = this.async(),
      async = grunt.util.async,
      pgClient,
      // File listing
      sqlFiles,
      filesIterator = 0,
      // Error and Success count
      errors = [],
      success = 0,
      query;

    var serverConfig = (this.args.length)? config.connections[parseInt(this.args[0], 10)] : config.connections[0];

    pgClient = new pg.Client(serverConfig);

    // Actually connecting to postgreSQL
    pgClient.connect();

    sqlFiles = grunt.file.expand(config.src);

    async.whilst(
      function () {
        return filesIterator < sqlFiles.length;
      },
      function (callback) {
        pgClient.query(grunt.file.read(sqlFiles[filesIterator]), function (err, result) {
          if (err) {
            errors.push(err);
            callback();
          } else {
            success++;
            callback();
          }
        });
        filesIterator++;
      },
      function (err) {
        if (errors.length) {
          grunt.log.error(errors.length + ' Errors occurred, listing them:');
          _.forEach(errors, function (value, index) {
            grunt.log.errorlns(value);
          });
        }
        grunt.log.ok('Correctly restored ' + success + ' stored procedures.');
        done();
      }
    );
  });

  grunt.task.registerTask('run-sql', 'Run SQL commands from file and return results for grunt use', function () {
    var done = this.async(),
      pgClient,
      query,
      results = [],
      sqlResultsName = config.sqlResultsName || 'results';

    var options = this.options();

    var serverConfig = (this.args.length > 1)? config.connections[parseInt(this.args[0], 10)] : config.connections[0];

    pgClient = new pg.Client(serverConfig);
    pgClient.connect();

   query = pgClient.query(grunt.file.read(config.sqlDir + this.args[this.args.length - 1] + '.sql'));
    query.on('row', function (row, result) {
      results.push(row);
    });

    query.on('error', grunt.fail.fatal);
    query.on('end', function () {
      grunt.config(sqlResultsName, results);
      done();
    });
  });

};
<commit_msg>ensure that configured params are defined or use a default value close #1<commit_after>var pg = require('pg');

module.exports = function (grunt) {
  var config = grunt.config.get('pgutils'),
    _ = grunt.util._,
    log = function (args, depth) { console.log(require('util').inspect(args, { colors: true, depth: depth })); };

  grunt.task.registerTask('backup-sp', 'Dump PostgresSQL stored procedures in separated files.', function () {
    var done = this.async(),
      pgClient = null,
      // Success count
      success = 0,
      query;

    config.dest = config.dest || 'spsql/';
    var serverConfig = (this.args.length)? config.connections[parseInt(this.args[0], 10)] : config.connections[0];

    pgClient = new pg.Client(serverConfig);
    // Actually connecting to postgreSQL
    pgClient.connect();

    query = pgClient.query("select pg_get_functiondef(sp.oid) as functiondef, sp.proname as proname, sp.pronargs as pronargs from (select oid, proname, pronargs from pg_proc where proname ~ '" + config.spRegex + "') as sp");
    query.on('row', function (row, result) {
      grunt.file.write(config.dest + '/' + row.proname + '_' + row.pronargs + '.sql', row.functiondef);
      success++;
    });

    query.on('error', grunt.fail.fatal);
    query.on('end', function () {
      grunt.log.ok('Correctly backupped ' + success + ' stored procedures.');
      done();
    });
  });

  grunt.task.registerTask('restore-sp', 'Restore stored procedures.', function () {
    var done = this.async(),
      async = grunt.util.async,
      pgClient,
      // File listing
      sqlFiles,
      filesIterator = 0,
      // Error and Success count
      errors = [],
      success = 0,
      query;

    config.src = config.src || 'spsql/*.js';
    var serverConfig = (this.args.length)? config.connections[parseInt(this.args[0], 10)] : config.connections[0];

    pgClient = new pg.Client(serverConfig);

    // Actually connecting to postgreSQL
    pgClient.connect();

    sqlFiles = grunt.file.expand(config.src);

    async.whilst(
      function () {
        return filesIterator < sqlFiles.length;
      },
      function (callback) {
        pgClient.query(grunt.file.read(sqlFiles[filesIterator]), function (err, result) {
          if (err) {
            errors.push(err);
            callback();
          } else {
            success++;
            callback();
          }
        });
        filesIterator++;
      },
      function (err) {
        if (errors.length) {
          grunt.log.error(errors.length + ' Errors occurred, listing them:');
          _.forEach(errors, function (value, index) {
            grunt.log.errorlns(value);
          });
        }
        grunt.log.ok('Correctly restored ' + success + ' stored procedures.');
        done();
      }
    );
  });

  grunt.task.registerTask('run-sql', 'Run SQL commands from file and return results for grunt use', function () {
    var done = this.async(),
      pgClient,
      query,
      results = [];

    config.sqlDir = config.sqlDir || 'sqls/';
    var sqlResultsName = config.sqlResultsName || 'results';
    var serverConfig = (this.args.length > 1)? config.connections[parseInt(this.args[0], 10)] : config.connections[0];
    var options = this.options();

    pgClient = new pg.Client(serverConfig);
    pgClient.connect();

   query = pgClient.query(grunt.file.read(config.sqlDir + this.args[this.args.length - 1] + '.sql'));
    query.on('row', function (row, result) {
      results.push(row);
    });

    query.on('error', grunt.fail.fatal);
    query.on('end', function () {
      grunt.config(sqlResultsName, results);
      done();
    });
  });

};
<|endoftext|>


<commit_before>var wrench = require("wrench");
var fs     = require("fs");

module.exports = {
    /**
     * Symlinks the assets directory
     */
    symlink: function ()
    {
        if (fs.existsSync("web/assets"))
        {
            var stat = fs.lstatSync("web/assets");

            if (stat.isFile() || stat.isSymbolicLink())
            {
                fs.unlinkSync("web/assets");
            }
            else
            {
                wrench.rmdirSyncRecursive("web/assets");
            }
        }

        fs.symlinkSync("../public", "web/assets");
    },

    /**
     * Copies the assets directory
     */
    copy: function ()
    {
        wrench.copyDirSyncRecursive("public", "web/assets", {
            forceDelete: true
        });
    }
};
<commit_msg>First remove the already published assets dir<commit_after>var wrench = require("wrench");
var fs     = require("fs");

/**
 * Removes the existing directory
 */
function removeExisting ()
{
    if (fs.existsSync("web/assets"))
    {
        var stat = fs.lstatSync("web/assets");

        if (stat.isFile() || stat.isSymbolicLink())
        {
            fs.unlinkSync("web/assets");
        }
        else
        {
            wrench.rmdirSyncRecursive("web/assets");
        }
    }
}

module.exports = {
    /**
     * Symlinks the assets directory
     */
    symlink: function ()
    {
        removeExisting();

        fs.symlinkSync("../public", "web/assets");
    },

    /**
     * Copies the assets directory
     */
    copy: function ()
    {
        removeExisting();

        wrench.copyDirSyncRecursive("public", "web/assets", {
            forceDelete: true
        });
    }
};
<|endoftext|>