<commit_before>import React from 'react';
import { connect } from 'react-redux'
import {Helmet} from "react-helmet";
import i18nURL from '../../../lib/i18nURL';
var sd = require('sharify').data;
var I18N = sd.I18N;

var Head = React.createClass({

  propTypes: {

    location: React.PropTypes.object.isRequired,
    lang: React.PropTypes.string.isRequired,
    title: React.PropTypes.string.isRequired,
    description: React.PropTypes.string.isRequired,
    noIndex: React.PropTypes.bool.isRequired,
  },

  render: function () {

    var props = this.props;
    const langSelected = props.lang;
    var location = props.location;

    var pathname = location.pathname + location.search;

    if(langSelected == I18N.default){

      var defaultPathname = pathname;

    }else{

      var pathname_parts = pathname.split('/');

      pathname_parts.shift();
      pathname_parts.shift();

      var defaultPathname = '/' + pathname_parts.join('/');

    }

    return (

    	<Helmet>

    		<html lang={props.lang}/>
            <title>{props.title}</title>
            <meta name="description" content={props.description} />

            {props.noIndex || process.env.NODE_ENV == 'development' ? <meta name="robots" content="noindex"/> : null}

            {I18N.langs.map((lang, index) => {

              if(lang == langSelected) return null

              return <link rel="alternate" hreflang={lang} href={i18nURL(defaultPathname, lang)} />

            })}

        </Helmet>

    )
  }

});

export default connect((state, ownProps) => {

  return Object.assign({}, state.head, {

    lang: state.i18nState.lang,
    location : state.routing.locationBeforeTransitions ? state.routing.locationBeforeTransitions : {}
  })

})(Head)<commit_msg>add canonical and full paths<commit_after>import React from 'react';
import { connect } from 'react-redux'
import {Helmet} from "react-helmet";
import i18nURL from '../../../lib/i18nURL';
var sd = require('sharify').data;
var I18N = sd.I18N;

var Head = React.createClass({

  propTypes: {

    location: React.PropTypes.object.isRequired,
    lang: React.PropTypes.string.isRequired,
    title: React.PropTypes.string.isRequired,
    description: React.PropTypes.string.isRequired,
    noIndex: React.PropTypes.bool.isRequired,
  },

  render: function () {

    var props = this.props;
    const langSelected = props.lang;
    var location = props.location;

    var pathname = location.pathname;// + location.search;

    if(langSelected == I18N.default){

      var defaultPathname = pathname;

    }else{

      var pathname_parts = pathname.split('/');

      pathname_parts.shift();
      pathname_parts.shift();

      var defaultPathname = '/' + pathname_parts.join('/');

    }

    return (

      <Helmet>

        <html lang={props.lang}/>
            <title>{props.title}</title>
            <meta name="description" content={props.description} />

            {props.noIndex || process.env.NODE_ENV == 'development' ? <meta name="robots" content="noindex"/> : null}

            <link rel="canonical" href={sd.SERVER_URL + pathname} />

            {I18N.langs.map((lang, index) => {

              if(lang == langSelected) return null

              return <link rel="alternate" hreflang={lang} href={sd.SERVER_URL + i18nURL(defaultPathname, lang)} />

            })}

        </Helmet>

    )
  }

});

export default connect((state, ownProps) => {

  return Object.assign({}, state.head, {

    lang: state.i18nState.lang,
    location : state.routing.locationBeforeTransitions ? state.routing.locationBeforeTransitions : {}
  })

})(Head)<|endoftext|>


<commit_before>
/*!--------------------------------*\
   3-Jekyll Theme
   @author Peiwen Lu (P233)
   https://github.com/P233/3-Jekyll
\*---------------------------------*/

// Detect window size, if less than 1280px add class 'mobile' to sidebar therefore it will be auto hide when trigger the pjax request in small screen devices.
if ($(window).width() <= 1280) {
  $('#sidebar').addClass('mobile')
}

// Variables
    tag1       = $('.pl__all'),
    tag2       = $('.tag_multi_thread'),
var sidebar    = $('#sidebar'),
    container  = $('#post'),
    content    = $('#pjax'),
    button     = $('#icon-arrow');

// Tags switcher
var clickHandler = function(k) {
  return function() {
    $(this).addClass('active').siblings().removeClass('active');
    tag1.hide();
    window['tag'+k].delay(50).fadeIn(350);
  }
};
for (var i = 1; i <= 2; i++) {
  $('#js-label' + i).on('click', clickHandler(i));
}

// If sidebar has class 'mobile', hide it after clicking.
tag1.on('click', function() {
  $(this).addClass('active').siblings().removeClass('active');
  if (sidebar.hasClass('mobile')) {
    $('#sidebar, #pjax, #icon-arrow').addClass('fullscreen');
  }
});

// Enable fullscreen.
$('#js-fullscreen').on('click', function() {
  if (button.hasClass('fullscreen')) {
    sidebar.removeClass('fullscreen');
    button.removeClass('fullscreen');
    content.delay(300).queue(function(){
      $(this).removeClass('fullscreen').dequeue();
    });
  } else {
    sidebar.addClass('fullscreen');
    button.addClass('fullscreen');
    content.delay(200).queue(function(){
      $(this).addClass('fullscreen').dequeue();
    });
  }
});

$('#mobile-avatar').on('click', function(){
  $('#sidebar, #pjax, #icon-arrow').addClass('fullscreen');
});

// Pjax
$(document).pjax('#avatar, #mobile-avatar, .pl__all', '#pjax', { fragment: '#pjax', timeout: 10000 });
$(document).on({
  'pjax:click': function() {
    content.removeClass('fadeIn').addClass('fadeOut');
    NProgress.start();
  },
  'pjax:start': function() {
    content.css({'opacity':0});
  },
  'pjax:end': function() {
    NProgress.done();
    container.scrollTop(0);
    content.css({'opacity':1}).removeClass('fadeOut').addClass('fadeIn');
    afterPjax();
  }
});

// Codepen embed js
// http://codepen.io/assets/embed/ei.js
// Added on 17 Nov 2013
var CodePenEmbed={width:"100%",init:function(){this.showCodePenEmbeds(),this.listenToParentPostMessages()},showCodePenEmbeds:function(){var e=document.getElementsByClassName("codepen");for(var t=e.length-1;t>-1;t--){var n=this._getParamsFromAttributes(e[t]);n=this._convertOldDataAttributesToNewDataAttributes(n);var r=this._buildURL(n),i=this._buildIFrame(n,r);this._addIFrameToPage(e[t],i)}},_getParamsFromAttributes:function(e){var t={},n=e.attributes;for(var r=0,i=n.length;r<i;r++)name=n[r].name,name.indexOf("data-")===0&&(t[name.replace("data-","")]=n[r].value);return t},_convertOldDataAttributesToNewDataAttributes:function(e){return e.href&&(e["slug-hash"]=e.href),e.type&&(e["default-tab"]=e.type),e.safe&&(e["safe"]=="true"?e.animations="run":e.animations="stop-after-5"),e},_buildURL:function(e){var t=this._getHost(e),n=e.user?e.user:"anon",r="?"+this._getGetParams(e),i=[t,n,"embed",e["slug-hash"]+r].join("/");return i.replace(/\/\//g,"//")},_getHost:function(e){return e.host?e.host:document.location.protocol=="file:"?"http://codepen.io":"//codepen.io"},_getGetParams:function(e){var t="",n=0;for(var r in e)t!==""&&(t+="&"),t+=r+"="+encodeURIComponent(e[r]);return t},_buildIFrame:function(e,t){var n={id:"cp_embed_"+e["slug-hash"].replace("/","_"),src:t,scrolling:"no",frameborder:"0",height:this._getHeight(e),allowTransparency:"true","class":"cp_embed_iframe",style:"width: "+this.width+"; overflow: hidden;"},r="",r},_getHeight:function(e){return e.height?e["height"]=="auto"?300:e.height:300},_addIFrameToPage:function(e,t){if(e.parentNode){var n=document.createElement("div");n.innerHTML=t,e.parentNode.replaceChild(n,e)}else e.innerHTML=t},listenToParentPostMessages:function(){var eventMethod=window.addEventListener?"addEventListener":"attachEvent",eventListener=window[eventMethod],messageEvent=eventMethod=="attachEvent"?"onmessage":"message";eventListener(messageEvent,function(e){try{var dataObj=eval("("+e.data+")"),iframe=document.getElementById("cp_embed_"+dataObj.hash);iframe&&(iframe.height=dataObj.height)}catch(err){}},!1)}};

// Re-run scripts for post content after pjax
function afterPjax() {
  // Open links in new tab
  $('#post__content a').attr('target','_blank');

  // Embed codepen after pjax
  CodePenEmbed.init();

  // Generate post TOC for h1 h2 and h3
  var toc = $('#post__toc-ul');
  // Empty TOC and generate an entry for h1
  toc.empty().append('
' + $('#post__title').text() + '
');

  // Generate entries for h2 and h3
  $('#post__content').children('h2,h3').each(function() {
    // Generate random ID for each heading
    $(this).attr('id', function() {
      var ID = "",
          alphabet = "abcdefghijklmnopqrstuvwxyz";

      for(var i=0; i < 5; i++) {
        ID += alphabet.charAt(Math.floor(Math.random() * alphabet.length));
      }
      return ID;
    });

    if ($(this).prop("tagName") == 'H2') {
      toc.append('
' + $(this).text() + '
');
    } else {
      toc.append('
' + $(this).text() + '
');
    }
  });

  // Smooth scrolling
  $('.js-anchor-link').on('click', function() {
    var target = $(this.hash);
    container.animate({scrollTop: target.offset().top + container.scrollTop() - 70}, 500, function() {
      target.addClass('flash').delay(700).queue(function() {
        $(this).removeClass('flash').dequeue();
      });
    });
  });

  // Lazy Loading Disqus
  // http://jsfiddle.net/dragoncrew/SHGwe/1/
  var ds_loaded = false,
      top = $('#disqus_thread').offset().top;
      identifier = $('#post__title').data('identifier');
  window.disqus_shortname = '';
  window.disqus_identifier = identifier;

  function check() {
    if ( !ds_loaded && container.scrollTop() + container.height() > top ) {
      $.ajax({
        type: 'GET',
        url: 'http://' + disqus_shortname + '.disqus.com/embed.js',
        dataType: 'script',
        cache: true
      });
      ds_loaded = true;
    }
  }check();
  container.scroll(check);
}afterPjax();

<commit_msg>bug fix<commit_after>
/*!--------------------------------*\
   3-Jekyll Theme
   @author Peiwen Lu (P233)
   https://github.com/P233/3-Jekyll
\*---------------------------------*/

// Detect window size, if less than 1280px add class 'mobile' to sidebar therefore it will be auto hide when trigger the pjax request in small screen devices.
if ($(window).width() <= 1280) {
  $('#sidebar').addClass('mobile')
}

// Variables
    tag1       = $('.pl__all'),
    tag2       = $('.tag_multi_thread');
var sidebar    = $('#sidebar'),
    container  = $('#post'),
    content    = $('#pjax'),
    button     = $('#icon-arrow');

// Tags switcher
var clickHandler = function(k) {
  return function() {
    $(this).addClass('active').siblings().removeClass('active');
    tag1.hide();
    window['tag'+k].delay(50).fadeIn(350);
  }
};
for (var i = 1; i <= 2; i++) {
  $('#js-label' + i).on('click', clickHandler(i));
}

// If sidebar has class 'mobile', hide it after clicking.
tag1.on('click', function() {
  $(this).addClass('active').siblings().removeClass('active');
  if (sidebar.hasClass('mobile')) {
    $('#sidebar, #pjax, #icon-arrow').addClass('fullscreen');
  }
});

// Enable fullscreen.
$('#js-fullscreen').on('click', function() {
  if (button.hasClass('fullscreen')) {
    sidebar.removeClass('fullscreen');
    button.removeClass('fullscreen');
    content.delay(300).queue(function(){
      $(this).removeClass('fullscreen').dequeue();
    });
  } else {
    sidebar.addClass('fullscreen');
    button.addClass('fullscreen');
    content.delay(200).queue(function(){
      $(this).addClass('fullscreen').dequeue();
    });
  }
});

$('#mobile-avatar').on('click', function(){
  $('#sidebar, #pjax, #icon-arrow').addClass('fullscreen');
});

// Pjax
$(document).pjax('#avatar, #mobile-avatar, .pl__all', '#pjax', { fragment: '#pjax', timeout: 10000 });
$(document).on({
  'pjax:click': function() {
    content.removeClass('fadeIn').addClass('fadeOut');
    NProgress.start();
  },
  'pjax:start': function() {
    content.css({'opacity':0});
  },
  'pjax:end': function() {
    NProgress.done();
    container.scrollTop(0);
    content.css({'opacity':1}).removeClass('fadeOut').addClass('fadeIn');
    afterPjax();
  }
});

// Codepen embed js
// http://codepen.io/assets/embed/ei.js
// Added on 17 Nov 2013
var CodePenEmbed={width:"100%",init:function(){this.showCodePenEmbeds(),this.listenToParentPostMessages()},showCodePenEmbeds:function(){var e=document.getElementsByClassName("codepen");for(var t=e.length-1;t>-1;t--){var n=this._getParamsFromAttributes(e[t]);n=this._convertOldDataAttributesToNewDataAttributes(n);var r=this._buildURL(n),i=this._buildIFrame(n,r);this._addIFrameToPage(e[t],i)}},_getParamsFromAttributes:function(e){var t={},n=e.attributes;for(var r=0,i=n.length;r<i;r++)name=n[r].name,name.indexOf("data-")===0&&(t[name.replace("data-","")]=n[r].value);return t},_convertOldDataAttributesToNewDataAttributes:function(e){return e.href&&(e["slug-hash"]=e.href),e.type&&(e["default-tab"]=e.type),e.safe&&(e["safe"]=="true"?e.animations="run":e.animations="stop-after-5"),e},_buildURL:function(e){var t=this._getHost(e),n=e.user?e.user:"anon",r="?"+this._getGetParams(e),i=[t,n,"embed",e["slug-hash"]+r].join("/");return i.replace(/\/\//g,"//")},_getHost:function(e){return e.host?e.host:document.location.protocol=="file:"?"http://codepen.io":"//codepen.io"},_getGetParams:function(e){var t="",n=0;for(var r in e)t!==""&&(t+="&"),t+=r+"="+encodeURIComponent(e[r]);return t},_buildIFrame:function(e,t){var n={id:"cp_embed_"+e["slug-hash"].replace("/","_"),src:t,scrolling:"no",frameborder:"0",height:this._getHeight(e),allowTransparency:"true","class":"cp_embed_iframe",style:"width: "+this.width+"; overflow: hidden;"},r="",r},_getHeight:function(e){return e.height?e["height"]=="auto"?300:e.height:300},_addIFrameToPage:function(e,t){if(e.parentNode){var n=document.createElement("div");n.innerHTML=t,e.parentNode.replaceChild(n,e)}else e.innerHTML=t},listenToParentPostMessages:function(){var eventMethod=window.addEventListener?"addEventListener":"attachEvent",eventListener=window[eventMethod],messageEvent=eventMethod=="attachEvent"?"onmessage":"message";eventListener(messageEvent,function(e){try{var dataObj=eval("("+e.data+")"),iframe=document.getElementById("cp_embed_"+dataObj.hash);iframe&&(iframe.height=dataObj.height)}catch(err){}},!1)}};

// Re-run scripts for post content after pjax
function afterPjax() {
  // Open links in new tab
  $('#post__content a').attr('target','_blank');

  // Embed codepen after pjax
  CodePenEmbed.init();

  // Generate post TOC for h1 h2 and h3
  var toc = $('#post__toc-ul');
  // Empty TOC and generate an entry for h1
  toc.empty().append('
' + $('#post__title').text() + '
');

  // Generate entries for h2 and h3
  $('#post__content').children('h2,h3').each(function() {
    // Generate random ID for each heading
    $(this).attr('id', function() {
      var ID = "",
          alphabet = "abcdefghijklmnopqrstuvwxyz";

      for(var i=0; i < 5; i++) {
        ID += alphabet.charAt(Math.floor(Math.random() * alphabet.length));
      }
      return ID;
    });

    if ($(this).prop("tagName") == 'H2') {
      toc.append('
' + $(this).text() + '
');
    } else {
      toc.append('
' + $(this).text() + '
');
    }
  });

  // Smooth scrolling
  $('.js-anchor-link').on('click', function() {
    var target = $(this.hash);
    container.animate({scrollTop: target.offset().top + container.scrollTop() - 70}, 500, function() {
      target.addClass('flash').delay(700).queue(function() {
        $(this).removeClass('flash').dequeue();
      });
    });
  });

  // Lazy Loading Disqus
  // http://jsfiddle.net/dragoncrew/SHGwe/1/
  var ds_loaded = false,
      top = $('#disqus_thread').offset().top;
      identifier = $('#post__title').data('identifier');
  window.disqus_shortname = '';
  window.disqus_identifier = identifier;

  function check() {
    if ( !ds_loaded && container.scrollTop() + container.height() > top ) {
      $.ajax({
        type: 'GET',
        url: 'http://' + disqus_shortname + '.disqus.com/embed.js',
        dataType: 'script',
        cache: true
      });
      ds_loaded = true;
    }
  }check();
  container.scroll(check);
}afterPjax();

<|endoftext|>


<commit_before>describe('Controller: AssessmentsCtrl', function() {
  var subject, scope, $httpBackend, SessionService;

  beforeEach(module('PDRClient'));

  beforeEach(inject(function($controller, $rootScope, $injector) {
    $httpBackend   = $injector.get('$httpBackend');
    SessionService = $injector.get('SessionService');

    spyOn(SessionService, 'getCurrentUser')
      .and.returnValue({role: 'member'});

    scope    = $rootScope.$new();
    subject  = $controller('AssessmentsCtrl', {
      $scope: scope
    });

  }));

  it('#roundNumber rounds', function(){
    expect(scope.roundNumber(50.999)).toEqual(50);
  });

  it('#meetingTime returns formattd date', function(){
    expect(scope.meetingTime(null))
      .toEqual("TBD");

    expect(scope.meetingTime("Jan 1, 1999"))
      .toEqual("1st Jan 1999");
  });

  it('#consensusReportIcon returns correct icon', function() {
    var assessment = {
      links: {
        'report': {
          'active' : true
        }
      }
    };

    expect(scope.consensusReportIcon(assessment))
      .toEqual("fa-check");

    assessment.links['report']['active'] = false;
    expect(scope.consensusReportIcon(assessment))
      .toEqual("fa-spinner");
  });

});

<commit_msg>Fixed Spec.<commit_after>describe('Controller: AssessmentsCtrl', function() {
  var subject, scope, $httpBackend, SessionService;

  beforeEach(module('PDRClient'));

  beforeEach(inject(function($controller, $rootScope, $injector) {

    $httpBackend   = $injector.get('$httpBackend');
    SessionService = $injector.get('SessionService');

    spyOn(SessionService, 'getCurrentUser')
      .and.returnValue({role: 'member'});

    scope    = $rootScope.$new();
    subject  = $controller('AssessmentsCtrl', {
      $scope: scope,
      assessments: {}
    });

  }));

  it('#roundNumber rounds', function(){
    expect(scope.roundNumber(50.999)).toEqual(50);
  });

  it('#meetingTime returns formattd date', function(){
    expect(scope.meetingTime(null))
      .toEqual("TBD");

    expect(scope.meetingTime("Jan 1, 1999"))
      .toEqual("1st Jan 1999");
  });

  it('#consensusReportIcon returns correct icon', function() {
    var assessment = {
      links: {
        'report': {
          'active' : true
        }
      }
    };

    expect(scope.consensusReportIcon(assessment))
      .toEqual("fa-check");

    assessment.links['report']['active'] = false;
    expect(scope.consensusReportIcon(assessment))
      .toEqual("fa-spinner");
  });

});

<|endoftext|>


<commit_before>// http://stackoverflow.com/questions/13567312/working-project-structure-that-uses-grunt-js-to-combine-javascript-files-using-r

/*global module:false*/
module.exports = function(grunt) {

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        localConfig: (function(){
                        try {
                            return grunt.file.readJSON('localConfig.json')
                        } catch(e) {
                            return {};
                        }
                    })(),
        lint: {
            files: ['grunt.js', 'src/**/*.js', 'tests/**/*.js']
        },
        qunit: {
            all: {
              options: {
                urls: [
                  'http://localhost:3000/tests/capture.html',
                ]
              }
            }
        },
        connect: {
            server: {
                options: {
                    hostname: '0.0.0.0',
                    port: 3000,
                    base: '.'
                }
            }
        },
        requirejs: {
            // Building capturing only
            capture: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    optimize: "none",
                    keepBuildDir: true,
                    name: "mobify-capture",
                    out: "./build/capture-<%= pkg.version %>.js",
                }
            },
            // Building full Mobify.js library
            full: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    optimize: "none",
                    keepBuildDir: true,
                    name: "mobify-full",
                    out: "./build/mobify-<%= pkg.version %>.js",
                }
            },
            fullOptimized: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    keepBuildDir: true,
                    name: "mobify-full",
                    out: "./build/mobify-<%= pkg.version %>.min.js",
                }
            },
            // Building custom Mobify.js library
            custom: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    optimize: "none",
                    keepBuildDir: true,
                    name: "../mobify-custom.js",
                    out: "./build/custom/mobify.js",
                }
            },
            customOptimized: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    keepBuildDir: true,
                    name: "../mobify-custom.js",
                    out: "./build/custom/mobify.min.js",
                }
            }
        },
        watch: {
            files: ["src/**/*.js",
                  "mobify-custom.js"
            ],
            tasks: ['requirejs'],
        },
        'saucelabs-qunit': {
            all: {
                username: '<%= localConfig.saucelabs.username %>', // if not provided it'll default to ENV SAUCE_USERNAME (if applicable)
                key: '<%= localConfig.saucelabs.key %>', // if not provided it'll default to ENV SAUCE_ACCESS_KEY (if applicable)
                urls: ['http://localhost:3000/tests/capture.html'],
                concurrency: 2,
                tunneled: true,
                browsers: [
                { // Only working version of IE compatable
                    browserName: 'internet explorer',
                    platform: 'Windows 2012',
                    version: '10'
                },
                { // Lowest known working version of FF
                    browserName: 'opera',
                    platform: 'Windows 2003',
                    version: '11'
                },
                { // Highest known working version of Opera
                    browserName: 'opera',
                    platform: 'Windows 2008',
                    version: '12'
                },
                { // Latest Chrome on Windows XP
                    browserName: 'chrome',
                    platform: 'Windows 2003'
                },
                { // Latest Chrome on Windows 7
                    browserName: 'chrome',
                    platform: 'Windows 2008'
                },
                { // Latest Chrome on Linux (unknown distro)
                    browserName: 'chrome',
                    platform: 'Linux'
                },
                { // Lowest known working version of FF
                    browserName: 'firefox',
                    version: '4.0'
                },
                { // Highest known working version of FF on Windows
                    browserName: 'firefox',
                    version: '18.0'
                },
                { // Highest FF on OSX
                    browserName: 'firefox',
                    platform: 'Mac 10.6',
                    version: '14.0'
                },
                { // Lowest iPad on OSX (simulator)
                    browserName: 'ipad',
                    platform: 'Mac 10.6',
                    version: '4.3'
                },
                { // Highest iPad on OSX (simulator)
                  // NOTE: iOS 6 is available, but it hangs on SauceLabs...
                    browserName: 'ipad',
                    platform: 'Mac 10.6',
                    version: '5'
                },
                { // Lowest iPhone on OSX (simulator)
                    browserName: 'iphone',
                    platform: 'Mac 10.6',
                    version: '4.3'
                },
                { // Highest iPhone on OSX (simulator)
                  // NOTE: iOS 6 is available, but it hangs on SauceLabs...
                    browserName: 'iphone',
                    platform: 'Mac 10.6',
                    version: '5'
                },
                { // Android 4.0 (simulator)
                    browserName: 'android',
                    platform: 'Linux',
                    version: '4'
                }
                ], // https://saucelabs.com/docs/browsers
                onTestComplete: function(){
                    // Called after a qunit unit is done, per page, per browser
                    // Return true or false, passes or fails the test
                    // Returning undefined does not alter the test result

                    // For async return, call
                    var done = this.async();
                    setTimeout(function(){
                        // Return to this test after 1000 milliseconds
                        done(/*true or false changes the test result, undefined does not alter the result*/);
                    }, 1000);
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-requirejs');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-saucelabs');

    // Default task.
    grunt.registerTask('default', ['requirejs:capture',
                                   'requirejs:full',
                                   'requirejs:fullOptimized']);
    grunt.registerTask('build', 'default');
    grunt.registerTask('test', ['connect', 'qunit']);
    grunt.registerTask('saucelabs', ['test', 'saucelabs-qunit']);
    grunt.registerTask('preview', ['connect', 'watch']);
};
<commit_msg>Only attempt to build custom mobify build if the file exists<commit_after>// http://stackoverflow.com/questions/13567312/working-project-structure-that-uses-grunt-js-to-combine-javascript-files-using-r

/*global module:false*/
module.exports = function(grunt) {

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        localConfig: (function(){
                        try {
                            return grunt.file.readJSON('localConfig.json')
                        } catch(e) {
                            return {};
                        }
                    })(),
        lint: {
            files: ['grunt.js', 'src/**/*.js', 'tests/**/*.js']
        },
        qunit: {
            all: {
              options: {
                urls: [
                  'http://localhost:3000/tests/capture.html',
                ]
              }
            }
        },
        connect: {
            server: {
                options: {
                    hostname: '0.0.0.0',
                    port: 3000,
                    base: '.'
                }
            }
        },
        requirejs: {
            // Building capturing only
            capture: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    optimize: "none",
                    keepBuildDir: true,
                    name: "mobify-capture",
                    out: "./build/capture-<%= pkg.version %>.js",
                }
            },
            // Building full Mobify.js library
            full: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    optimize: "none",
                    keepBuildDir: true,
                    name: "mobify-full",
                    out: "./build/mobify-<%= pkg.version %>.js",
                }
            },
            fullOptimized: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    keepBuildDir: true,
                    name: "mobify-full",
                    out: "./build/mobify-<%= pkg.version %>.min.js",
                }
            },
            // Building custom Mobify.js library
            custom: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    optimize: "none",
                    keepBuildDir: true,
                    name: "../mobify-custom.js",
                    out: "./build/custom/mobify.js",
                }
            },
            customOptimized: {
                options: {
                    almond: true,
                    mainConfigFile: "./src/config.js",
                    keepBuildDir: true,
                    name: "../mobify-custom.js",
                    out: "./build/custom/mobify.min.js",
                }
            }
        },
        watch: {
            files: ["src/**/*.js",
                  "mobify-custom.js"
            ],
            tasks: ['build'],
        },
        'saucelabs-qunit': {
            all: {
                username: '<%= localConfig.saucelabs.username %>', // if not provided it'll default to ENV SAUCE_USERNAME (if applicable)
                key: '<%= localConfig.saucelabs.key %>', // if not provided it'll default to ENV SAUCE_ACCESS_KEY (if applicable)
                urls: ['http://localhost:3000/tests/capture.html'],
                concurrency: 2,
                tunneled: true,
                browsers: [
                { // Only working version of IE compatable
                    browserName: 'internet explorer',
                    platform: 'Windows 2012',
                    version: '10'
                },
                { // Lowest known working version of FF
                    browserName: 'opera',
                    platform: 'Windows 2003',
                    version: '11'
                },
                { // Highest known working version of Opera
                    browserName: 'opera',
                    platform: 'Windows 2008',
                    version: '12'
                },
                { // Latest Chrome on Windows XP
                    browserName: 'chrome',
                    platform: 'Windows 2003'
                },
                { // Latest Chrome on Windows 7
                    browserName: 'chrome',
                    platform: 'Windows 2008'
                },
                { // Latest Chrome on Linux (unknown distro)
                    browserName: 'chrome',
                    platform: 'Linux'
                },
                { // Lowest known working version of FF
                    browserName: 'firefox',
                    version: '4.0'
                },
                { // Highest known working version of FF on Windows
                    browserName: 'firefox',
                    version: '18.0'
                },
                { // Highest FF on OSX
                    browserName: 'firefox',
                    platform: 'Mac 10.6',
                    version: '14.0'
                },
                { // Lowest iPad on OSX (simulator)
                    browserName: 'ipad',
                    platform: 'Mac 10.6',
                    version: '4.3'
                },
                { // Highest iPad on OSX (simulator)
                  // NOTE: iOS 6 is available, but it hangs on SauceLabs...
                    browserName: 'ipad',
                    platform: 'Mac 10.6',
                    version: '5'
                },
                { // Lowest iPhone on OSX (simulator)
                    browserName: 'iphone',
                    platform: 'Mac 10.6',
                    version: '4.3'
                },
                { // Highest iPhone on OSX (simulator)
                  // NOTE: iOS 6 is available, but it hangs on SauceLabs...
                    browserName: 'iphone',
                    platform: 'Mac 10.6',
                    version: '5'
                },
                { // Android 4.0 (simulator)
                    browserName: 'android',
                    platform: 'Linux',
                    version: '4'
                }
                ], // https://saucelabs.com/docs/browsers
                onTestComplete: function(){
                    // Called after a qunit unit is done, per page, per browser
                    // Return true or false, passes or fails the test
                    // Returning undefined does not alter the test result

                    // For async return, call
                    var done = this.async();
                    setTimeout(function(){
                        // Return to this test after 1000 milliseconds
                        done(/*true or false changes the test result, undefined does not alter the result*/);
                    }, 1000);
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-requirejs');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks('grunt-saucelabs');

    // Builds librarys, and custom library if mobify-custom.js is present
    grunt.registerTask('build', function() {
        grunt.task.run("requirejs:capture", "requirejs:full", "requirejs:fullOptimized")
        if (grunt.file.exists("mobify-custom.js")) {
            grunt.task.run("requirejs:custom", "requirejs:customOptimized");
        }
    });
    grunt.registerTask('default', 'build');
    grunt.registerTask('test', ['connect', 'qunit']);
    grunt.registerTask('saucelabs', ['test', 'saucelabs-qunit']);
    grunt.registerTask('preview', ['connect', 'watch']);
};
<|endoftext|>


<commit_before>/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
/* jshint expr: true */
var expect = require('chai').expect;
var fs        = require('fs');

describe('Test package.json and io-package.json', function() {
    it('Test package files', function (done) {
        console.log();

        var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
        var ioPackage = JSON.parse(fileContentIOPackage);

        var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
        var npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
        expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;

        expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);

        if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
            console.log();
        }

        expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
        expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;

        if (ioPackage.common.name.indexOf('template') !== 0) {
            if (Array.isArray(ioPackage.common.authors)) {
                expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
                if (ioPackage.common.authors.length === 1) {
                    expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
                }
            }
            else {
                expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
            }
        }
        else {
            console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
            console.log();
        }
        expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
        expect(fs.existsSync(__dirname + '/../LICENSE'), 'ERROR: LICENSE needs to exist! Please create one.').to.be.true;
        if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
            console.log('WARNING: titleLang is not existing in io-package.json. Please add');
            console.log();
        }
        if (
            ioPackage.common.title.indexOf('iobroker') !== -1 ||
            ioPackage.common.title.indexOf('ioBroker') !== -1 ||
            ioPackage.common.title.indexOf('adapter') !== -1 ||
            ioPackage.common.title.indexOf('Adapter') !== -1
        ) {
            console.log('WARNING: title contains Adapter or ioBroker. It is clear anyway, that it is adapter for ioBroker.');
            console.log();
        }

        if (ioPackage.common.name.indexOf('vis-') !== 0) {
            if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
                console.log('WARNING: Admin3 support is missing! Please add it');
                console.log();
            }
            if (ioPackage.common.materialize) {
                expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
            }
        }

        expect(fs.existsSync(__dirname + '/../LICENSE'), 'A LICENSE must exist');
        var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
        if (fileContentReadme.indexOf('## License') === -1) {
            console.log('Warning: The README.md should have a section ## License');
            console.log();
        }
        if (fileContentReadme.indexOf('## Changelog') === -1) {
            console.log('Warning: The README.md should have a section ## Changelog');
            console.log();
        }
        done();
    });
});
<commit_msg>update basic package-file testing<commit_after>/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
/* jshint expr: true */
var expect = require('chai').expect;
var fs        = require('fs');

describe('Test package.json and io-package.json', function() {
    it('Test package files', function (done) {
        console.log();

        var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
        var ioPackage = JSON.parse(fileContentIOPackage);

        var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
        var npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
        expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;

        expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);

        if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
            console.log();
        }

        expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
        expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;

        if (ioPackage.common.name.indexOf('template') !== 0) {
            if (Array.isArray(ioPackage.common.authors)) {
                expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
                if (ioPackage.common.authors.length === 1) {
                    expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
                }
            }
            else {
                expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
            }
        }
        else {
            console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
            console.log();
        }
        expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
        expect(fs.existsSync(__dirname + '/../LICENSE'), 'ERROR: LICENSE needs to exist! Please create one.').to.be.true;
        if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
            console.log('WARNING: titleLang is not existing in io-package.json. Please add');
            console.log();
        }
        if (
            ioPackage.common.title.indexOf('iobroker') !== -1 ||
            ioPackage.common.title.indexOf('ioBroker') !== -1 ||
            ioPackage.common.title.indexOf('adapter') !== -1 ||
            ioPackage.common.title.indexOf('Adapter') !== -1
        ) {
            console.log('WARNING: title contains Adapter or ioBroker. It is clear anyway, that it is adapter for ioBroker.');
            console.log();
        }

        if (ioPackage.common.name.indexOf('vis-') !== 0) {
            if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
                console.log('WARNING: Admin3 support is missing! Please add it');
                console.log();
            }
            if (ioPackage.common.materialize) {
                expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
            }
        }

        var licenseFileExists = fs.existsSync(__dirname + '/../LICENSE');
        var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
        if (fileContentReadme.indexOf('## Changelog') === -1) {
            console.log('Warning: The README.md should have a section ## Changelog');
            console.log();
        }
        expect((licenseFileExists || fileContentReadme.indexOf('## License') !== -1), 'A LICENSE must exist as LICENSE file or as part of the README.md').to.be.true;
        if (!licenseFileExists) {
            console.log('Warning: The License should also exist as LICENSE file');
            console.log();
        }
        if (fileContentReadme.indexOf('## License') === -1) {
            console.log('Warning: The README.md should also have a section ## License to be shown in Admin3');
            console.log();
        }
        done();
    });
});
<|endoftext|>


<commit_before>module.exports = function (grunt) {
    'use strict';

    require('load-grunt-tasks')(grunt, {
        pattern: ['grunt-*', '!grunt-lib-phantomjs', '!grunt-template-jasmine-istanbul']
    });
    require('time-grunt')(grunt);
    var formatFileList = require('./grunt/format-file-list')(grunt);

    var config = {
        src: 'src',
        spec: 'spec',
        web: 'web',
        pkg: require('./package.json'),
        banner: grunt.file.read('./LICENSE_BANNER'),
        jsFiles: module.exports.jsFiles
    };

    grunt.initConfig({
        conf: config,

        concat: {
            js: {
                src: '<%= conf.jsFiles %>',
                dest: '<%= conf.pkg.name %>.js',
                options: {
                    process: true,
                    sourceMap: true,
                    banner: '<%= conf.banner %>'
                }
            },
            welcome: {
                src: ['docs/welcome.base.md', 'web/img/class-hierarchy.svg'],
                dest: 'welcome.md',
                options: {
                    process: function (src, filepath) {
                        return /svg/.test(filepath) ?
                            src.split('\n').slice(5).join('\n') :
                            src;
                    }
                }
            }
        },
        sass: {
            dist: {
                files: {
                    '<%= conf.pkg.name %>.css': 'style/<%= conf.pkg.name %>.scss'
                }
            }
        },
        uglify: {
            jsmin: {
                options: {
                    mangle: true,
                    compress: true,
                    sourceMap: true,
                    banner: '<%= conf.banner %>'
                },
                src: '<%= conf.pkg.name %>.js',
                dest: '<%= conf.pkg.name %>.min.js'
            }
        },
        cssmin: {
            options: {
                shorthandCompacting: false,
                roundingPrecision: -1
            },
            main: {
                files: {
                    '<%= conf.pkg.name %>.min.css': ['<%= conf.pkg.name %>.css']
                }
            }
        },
        jscs: {
            source: {
                src: [
                    '<%= conf.src %>/**/*.js',
                    '!<%= conf.src %>/{banner,footer}.js',
                    '<%= conf.spec %>/**/*.js',
                    'Gruntfile.js',
                    'grunt/*.js',
                    '<%= conf.web %>/stock.js'],
                options: {
                    config: '.jscsrc'
                }
            }
        },
        jshint: {
            source: {
                src: [
                    '<%= conf.src %>/**/*.js',
                    '!<%= conf.src %>/{banner,footer}.js',
                    '<%= conf.spec %>/**/*.js',
                    'Gruntfile.js',
                    'grunt/*.js',
                    '<%= conf.web %>/stock.js'
                ],
                options: {
                    jshintrc: '.jshintrc'
                }
            }
        },
        watch: {
            jsdoc2md: {
                files: ['welcome.md', '<%= conf.src %>/**/*.js'],
                tasks: ['build', 'jsdoc', 'jsdoc2md']
            },
            scripts: {
                files: ['<%= conf.src %>/**/*.js', '<%= conf.web %>/stock.js'],
                tasks: ['docs']
            },
            sass: {
                files: ['style/<%= conf.pkg.name %>.scss'],
                tasks: ['sass', 'cssmin:main', 'copy:dc-to-gh']
            },
            jasmineRunner: {
                files: ['<%= conf.spec %>/**/*.js'],
                tasks: ['jasmine:specs:build']
            },
            tests: {
                files: ['<%= conf.src %>/**/*.js', '<%= conf.spec %>/**/*.js'],
                tasks: ['test']
            },
            reload: {
                files: ['<%= conf.pkg.name %>.js',
                    '<%= conf.pkg.name %>.css',
                    '<%= conf.web %>/js/<%= conf.pkg.name %>.js',
                    '<%= conf.web %>/css/<%= conf.pkg.name %>.css',
                    '<%= conf.pkg.name %>.min.js'],
                options: {
                    livereload: true
                }
            }
        },
        connect: {
            server: {
                options: {
                    port: 8888,
                    base: '.'
                }
            }
        },
        jasmine: {
            specs: {
                options: {
                    display: 'short',
                    summary: true,
                    specs:  '<%= conf.spec %>/*-spec.js',
                    helpers: [
                        '<%= conf.web %>/js/jasmine-jsreporter.js',
                        '<%= conf.spec %>/helpers/*.js'
                    ],
                    styles: [
                        '<%= conf.web %>/css/dc.css'
                    ],
                    version: '2.0.0',
                    outfile: '<%= conf.spec %>/index.html',
                    keepRunner: true
                },
                src: [
                    '<%= conf.web %>/js/d3.js',
                    '<%= conf.web %>/js/crossfilter.js',
                    '<%= conf.web %>/js/colorbrewer.js',
                    '<%= conf.pkg.name %>.js'
                ]
            },
            coverage: {
                src: '<%= jasmine.specs.src %>',
                options: {
                    specs: '<%= jasmine.specs.options.specs %>',
                    helpers: '<%= jasmine.specs.options.helpers %>',
                    version: '<%= jasmine.specs.options.version %>',
                    template: require('grunt-template-jasmine-istanbul'),
                    templateOptions: {
                        coverage: 'coverage/jasmine/coverage.json',
                        report: [
                            {
                                type: 'html',
                                options: {
                                    dir: 'coverage/jasmine'
                                }
                            }
                        ]
                    }
                }
            },
            browserify: {
                options: {
                    display: 'short',
                    summary: true,
                    specs:  '<%= conf.spec %>/*-spec.js',
                    helpers: [
                        '<%= conf.web %>/js/jasmine-jsreporter.js',
                        '<%= conf.spec %>/helpers/*.js'
                    ],
                    version: '2.0.0',
                    outfile: '<%= conf.spec %>/index-browserify.html',
                    keepRunner: true
                },
                src: [
                    'bundle.js'
                ]
            }
        },
        'saucelabs-jasmine': {
            all: {
                options: {
                    urls: ['http://localhost:8888/spec/'],
                    tunnelTimeout: 5,
                    build: process.env.TRAVIS_JOB_ID,
                    concurrency: 3,
                    browsers: [
                        {
                            browserName: 'firefox',
                            version: '43.0',
                            platform: 'Linux'
                        },
                        {
                            browserName: 'safari',
                            version: '9.0',
                            platform: 'OS X 10.11'
                        },
                        {
                            browserName: 'internet explorer',
                            version: '11.0',
                            platform: 'Windows 10'
                        },
                        {
                            browserName: 'MicrosoftEdge',
                            version: '14',
                            platform: 'Windows 10'
                        }
                    ],
                    testname: '<%= conf.pkg.name %>.js'
                }
            }
        },
        jsdoc: {
            dist: {
                src: ['welcome.md', '<%= conf.src %>/**/*.js', '!<%= conf.src %>/{banner,footer}.js'],
                options: {
                    destination: 'web/docs/html',
                    template: 'node_modules/ink-docstrap/template',
                    configure: 'jsdoc.conf.json'
                }
            }
        },
        jsdoc2md: {
            dist: {
                src: 'dc.js',
                dest: 'web/docs/api-latest.md'
            }
        },
        docco: {
            options: {
                dst: '<%= conf.web %>/docs'
            },
            howto: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= conf.web %>',
                        src: ['stock.js']
                    }
                ]
            }
        },
        copy: {
            'dc-to-gh': {
                files: [
                    {
                        expand: true,
                        flatten: true,
                        nonull: true,
                        src: ['<%= conf.pkg.name %>.css', '<%= conf.pkg.name %>.min.css'],
                        dest: '<%= conf.web %>/css/'
                    },
                    {
                        expand: true,
                        flatten: true,
                        nonull: true,
                        src: [
                            '<%= conf.pkg.name %>.js',
                            '<%= conf.pkg.name %>.js.map',
                            '<%= conf.pkg.name %>.min.js',
                            '<%= conf.pkg.name %>.min.js.map',
                            'node_modules/d3/d3.js',
                            'node_modules/crossfilter2/crossfilter.js',
                            'node_modules/queue-async/build/queue.js',
                            'node_modules/grunt-saucelabs/examples/jasmine/lib/jasmine-jsreporter/jasmine-jsreporter.js',
                            'node_modules/file-saver/FileSaver.js'
                        ],
                        dest: '<%= conf.web %>/js/'
                    }
                ]
            }
        },
        fileindex: {
            'examples-listing': {
                options: {
                    format: formatFileList,
                    absolute: true,
                    title: 'Index of dc.js examples',
                    heading: 'Examples of using dc.js',
                    description: 'An attempt to present a simple example of each chart type.',
                    sourceLink: 'https://github.com/dc-js/dc.js/tree/master/<%= conf.web %>/examples'
                },
                files: [
                    {dest: '<%= conf.web %>/examples/index.html', src: ['<%= conf.web %>/examples/*.html']}
                ]
            },
            'transitions-listing': {
                options: {
                    format: formatFileList,
                    absolute: true,
                    title: 'Index of dc.js transition tests',
                    heading: 'Eyeball tests for dc.js transitions',
                    description: 'Transitions can only be tested by eye. ' +
                        'These pages automate the transitions so they can be visually verified.',
                    sourceLink: 'https://github.com/dc-js/dc.js/tree/master/<%= conf.web %>/transitions'
                },
                files: [
                    {dest: '<%= conf.web %>/transitions/index.html', src: ['<%= conf.web %>/transitions/*.html']}
                ]
            },
            'resizing-listing': {
                options: {
                    format: formatFileList,
                    absolute: true,
                    title: 'Index of dc.js resizing tests',
                    heading: 'Eyeball tests for resizing dc.js charts',
                    description: 'It\'s a lot easier to test resizing behavior by eye. ' +
                        'These pages fit the charts to the browser dynamically so it\'s easier to test.',
                    sourceLink: 'https://github.com/dc-js/dc.js/tree/master/<%= conf.web %>/resizing'
                },
                files: [
                    {dest: '<%= conf.web %>/resizing/index.html', src: ['<%= conf.web %>/resizing/*.html']}
                ]
            },
            'zoom-listing': {
                options: {
                    format: formatFileList,
                    absolute: true,
                    title: 'Index of dc.js zoom tests',
                    heading: 'Interactive test for dc.js chart zoom',
                    description: 'It\'s hard to conceive of a way to test zoom except by trying it. ' +
                        'So this is a substitute for automated tests in this area',
                    sourceLink: 'https://github.com/dc-js/dc.js/tree/master/<%= conf.web %>/zoom'
                },
                files: [
                    {dest: '<%= conf.web %>/zoom/index.html', src: ['<%= conf.web %>/zoom/*.html']}
                ]
            }
        },

        'gh-pages': {
            options: {
                base: '<%= conf.web %>',
                message: 'Synced from from master branch.'
            },
            src: ['**']
        },
        shell: {
            merge: {
                command: function (pr) {
                    return [
                        'git fetch origin',
                        'git checkout master',
                        'git reset --hard origin/master',
                        'git fetch origin',
                        'git merge --no-ff origin/pr/' + pr + ' -m \'Merge pull request #' + pr + '\''
                    ].join('&&');
                },
                options: {
                    stdout: true,
                    failOnError: true
                }
            },
            amend: {
                command: 'git commit -a --amend --no-edit',
                options: {
                    stdout: true,
                    failOnError: true
                }
            },
            hooks: {
                command: 'cp -n scripts/pre-commit.sh .git/hooks/pre-commit' +
                    ' || echo \'Cowardly refusing to overwrite your existing git pre-commit hook.\''
            },
            hierarchy: {
                command: 'dot -Tsvg -o web/img/class-hierarchy.svg class-hierarchy.dot'
            }
        },
        browserify: {
            dev: {
                src: '<%= conf.pkg.name %>.js',
                dest: 'bundle.js',
                options: {
                    browserifyOptions: {
                        standalone: 'dc'
                    }
                }
            }
        }
    });

    grunt.registerTask('merge', 'Merge a github pull request.', function (pr) {
        grunt.log.writeln('Merge Github Pull Request #' + pr);
        grunt.task.run(['shell:merge:' + pr, 'test' , 'shell:amend']);
    });
    grunt.registerTask('test-stock-example', 'Test a new rendering of the stock example web page against a ' +
        'baseline rendering', function (option) {
            require('./regression/stock-regression-test.js').testStockExample(this.async(), option === 'diff');
        });
    grunt.registerTask('update-stock-example', 'Update the baseline stock example web page.', function () {
        require('./regression/stock-regression-test.js').updateStockExample(this.async());
    });
    grunt.registerTask('watch:jasmine-docs', function () {
        grunt.config('watch', {
            options: {
                interrupt: true
            },
            runner: grunt.config('watch').jasmineRunner,
            scripts: grunt.config('watch').scripts,
            sass: grunt.config('watch').sass
        });
        grunt.task.run('watch');
    });

    // task aliases
    grunt.registerTask('build', ['concat', 'sass', 'uglify', 'cssmin']);
    grunt.registerTask('docs', ['build', 'copy', 'jsdoc', 'jsdoc2md', 'docco', 'fileindex']);
    grunt.registerTask('web', ['docs', 'gh-pages']);
    grunt.registerTask('server', ['docs', 'fileindex', 'jasmine:specs:build', 'connect:server', 'watch:jasmine-docs']);
    grunt.registerTask('test', ['build', 'copy', 'jasmine:specs']);
    grunt.registerTask('test-browserify', ['build', 'copy', 'browserify', 'jasmine:browserify']);
    grunt.registerTask('coverage', ['build', 'copy', 'jasmine:coverage']);
    grunt.registerTask('ci', ['test', 'jasmine:specs:build', 'connect:server', 'saucelabs-jasmine']);
    grunt.registerTask('ci-pull', ['test', 'jasmine:specs:build', 'connect:server']);
    grunt.registerTask('lint', ['jshint', 'jscs']);
    grunt.registerTask('default', ['build', 'shell:hooks']);
    grunt.registerTask('doc-debug', ['build', 'jsdoc', 'jsdoc2md', 'watch:jsdoc2md']);
};

module.exports.jsFiles = [
    'src/banner.js',   // NOTE: keep this first
    'src/core.js',
    'src/errors.js',
    'src/utils.js',
    'src/logger.js',
    'src/events.js',
    'src/filters.js',
    'src/base-mixin.js',
    'src/margin-mixin.js',
    'src/color-mixin.js',
    'src/coordinate-grid-mixin.js',
    'src/stack-mixin.js',
    'src/cap-mixin.js',
    'src/bubble-mixin.js',
    'src/pie-chart.js',
    'src/bar-chart.js',
    'src/line-chart.js',
    'src/data-count.js',
    'src/data-table.js',
    'src/data-grid.js',
    'src/bubble-chart.js',
    'src/composite-chart.js',
    'src/series-chart.js',
    'src/geo-choropleth-chart.js',
    'src/bubble-overlay.js',
    'src/row-chart.js',
    'src/legend.js',
    'src/scatter-plot.js',
    'src/number-display.js',
    'src/heatmap.js',
    'src/d3.box.js',
    'src/box-plot.js',
    'src/footer.js'  // NOTE: keep this last
];
<commit_msg>bump firefox test to later version<commit_after>module.exports = function (grunt) {
    'use strict';

    require('load-grunt-tasks')(grunt, {
        pattern: ['grunt-*', '!grunt-lib-phantomjs', '!grunt-template-jasmine-istanbul']
    });
    require('time-grunt')(grunt);
    var formatFileList = require('./grunt/format-file-list')(grunt);

    var config = {
        src: 'src',
        spec: 'spec',
        web: 'web',
        pkg: require('./package.json'),
        banner: grunt.file.read('./LICENSE_BANNER'),
        jsFiles: module.exports.jsFiles
    };

    grunt.initConfig({
        conf: config,

        concat: {
            js: {
                src: '<%= conf.jsFiles %>',
                dest: '<%= conf.pkg.name %>.js',
                options: {
                    process: true,
                    sourceMap: true,
                    banner: '<%= conf.banner %>'
                }
            },
            welcome: {
                src: ['docs/welcome.base.md', 'web/img/class-hierarchy.svg'],
                dest: 'welcome.md',
                options: {
                    process: function (src, filepath) {
                        return /svg/.test(filepath) ?
                            src.split('\n').slice(5).join('\n') :
                            src;
                    }
                }
            }
        },
        sass: {
            dist: {
                files: {
                    '<%= conf.pkg.name %>.css': 'style/<%= conf.pkg.name %>.scss'
                }
            }
        },
        uglify: {
            jsmin: {
                options: {
                    mangle: true,
                    compress: true,
                    sourceMap: true,
                    banner: '<%= conf.banner %>'
                },
                src: '<%= conf.pkg.name %>.js',
                dest: '<%= conf.pkg.name %>.min.js'
            }
        },
        cssmin: {
            options: {
                shorthandCompacting: false,
                roundingPrecision: -1
            },
            main: {
                files: {
                    '<%= conf.pkg.name %>.min.css': ['<%= conf.pkg.name %>.css']
                }
            }
        },
        jscs: {
            source: {
                src: [
                    '<%= conf.src %>/**/*.js',
                    '!<%= conf.src %>/{banner,footer}.js',
                    '<%= conf.spec %>/**/*.js',
                    'Gruntfile.js',
                    'grunt/*.js',
                    '<%= conf.web %>/stock.js'],
                options: {
                    config: '.jscsrc'
                }
            }
        },
        jshint: {
            source: {
                src: [
                    '<%= conf.src %>/**/*.js',
                    '!<%= conf.src %>/{banner,footer}.js',
                    '<%= conf.spec %>/**/*.js',
                    'Gruntfile.js',
                    'grunt/*.js',
                    '<%= conf.web %>/stock.js'
                ],
                options: {
                    jshintrc: '.jshintrc'
                }
            }
        },
        watch: {
            jsdoc2md: {
                files: ['welcome.md', '<%= conf.src %>/**/*.js'],
                tasks: ['build', 'jsdoc', 'jsdoc2md']
            },
            scripts: {
                files: ['<%= conf.src %>/**/*.js', '<%= conf.web %>/stock.js'],
                tasks: ['docs']
            },
            sass: {
                files: ['style/<%= conf.pkg.name %>.scss'],
                tasks: ['sass', 'cssmin:main', 'copy:dc-to-gh']
            },
            jasmineRunner: {
                files: ['<%= conf.spec %>/**/*.js'],
                tasks: ['jasmine:specs:build']
            },
            tests: {
                files: ['<%= conf.src %>/**/*.js', '<%= conf.spec %>/**/*.js'],
                tasks: ['test']
            },
            reload: {
                files: ['<%= conf.pkg.name %>.js',
                    '<%= conf.pkg.name %>.css',
                    '<%= conf.web %>/js/<%= conf.pkg.name %>.js',
                    '<%= conf.web %>/css/<%= conf.pkg.name %>.css',
                    '<%= conf.pkg.name %>.min.js'],
                options: {
                    livereload: true
                }
            }
        },
        connect: {
            server: {
                options: {
                    port: 8888,
                    base: '.'
                }
            }
        },
        jasmine: {
            specs: {
                options: {
                    display: 'short',
                    summary: true,
                    specs:  '<%= conf.spec %>/*-spec.js',
                    helpers: [
                        '<%= conf.web %>/js/jasmine-jsreporter.js',
                        '<%= conf.spec %>/helpers/*.js'
                    ],
                    styles: [
                        '<%= conf.web %>/css/dc.css'
                    ],
                    version: '2.0.0',
                    outfile: '<%= conf.spec %>/index.html',
                    keepRunner: true
                },
                src: [
                    '<%= conf.web %>/js/d3.js',
                    '<%= conf.web %>/js/crossfilter.js',
                    '<%= conf.web %>/js/colorbrewer.js',
                    '<%= conf.pkg.name %>.js'
                ]
            },
            coverage: {
                src: '<%= jasmine.specs.src %>',
                options: {
                    specs: '<%= jasmine.specs.options.specs %>',
                    helpers: '<%= jasmine.specs.options.helpers %>',
                    version: '<%= jasmine.specs.options.version %>',
                    template: require('grunt-template-jasmine-istanbul'),
                    templateOptions: {
                        coverage: 'coverage/jasmine/coverage.json',
                        report: [
                            {
                                type: 'html',
                                options: {
                                    dir: 'coverage/jasmine'
                                }
                            }
                        ]
                    }
                }
            },
            browserify: {
                options: {
                    display: 'short',
                    summary: true,
                    specs:  '<%= conf.spec %>/*-spec.js',
                    helpers: [
                        '<%= conf.web %>/js/jasmine-jsreporter.js',
                        '<%= conf.spec %>/helpers/*.js'
                    ],
                    version: '2.0.0',
                    outfile: '<%= conf.spec %>/index-browserify.html',
                    keepRunner: true
                },
                src: [
                    'bundle.js'
                ]
            }
        },
        'saucelabs-jasmine': {
            all: {
                options: {
                    urls: ['http://localhost:8888/spec/'],
                    tunnelTimeout: 5,
                    build: process.env.TRAVIS_JOB_ID,
                    concurrency: 3,
                    browsers: [
                        {
                            browserName: 'firefox',
                            version: '54.0',
                            platform: 'Linux'
                        },
                        {
                            browserName: 'safari',
                            version: '9.0',
                            platform: 'OS X 10.11'
                        },
                        {
                            browserName: 'internet explorer',
                            version: '11.0',
                            platform: 'Windows 10'
                        },
                        {
                            browserName: 'MicrosoftEdge',
                            version: '14',
                            platform: 'Windows 10'
                        }
                    ],
                    testname: '<%= conf.pkg.name %>.js'
                }
            }
        },
        jsdoc: {
            dist: {
                src: ['welcome.md', '<%= conf.src %>/**/*.js', '!<%= conf.src %>/{banner,footer}.js'],
                options: {
                    destination: 'web/docs/html',
                    template: 'node_modules/ink-docstrap/template',
                    configure: 'jsdoc.conf.json'
                }
            }
        },
        jsdoc2md: {
            dist: {
                src: 'dc.js',
                dest: 'web/docs/api-latest.md'
            }
        },
        docco: {
            options: {
                dst: '<%= conf.web %>/docs'
            },
            howto: {
                files: [
                    {
                        expand: true,
                        cwd: '<%= conf.web %>',
                        src: ['stock.js']
                    }
                ]
            }
        },
        copy: {
            'dc-to-gh': {
                files: [
                    {
                        expand: true,
                        flatten: true,
                        nonull: true,
                        src: ['<%= conf.pkg.name %>.css', '<%= conf.pkg.name %>.min.css'],
                        dest: '<%= conf.web %>/css/'
                    },
                    {
                        expand: true,
                        flatten: true,
                        nonull: true,
                        src: [
                            '<%= conf.pkg.name %>.js',
                            '<%= conf.pkg.name %>.js.map',
                            '<%= conf.pkg.name %>.min.js',
                            '<%= conf.pkg.name %>.min.js.map',
                            'node_modules/d3/d3.js',
                            'node_modules/crossfilter2/crossfilter.js',
                            'node_modules/queue-async/build/queue.js',
                            'node_modules/grunt-saucelabs/examples/jasmine/lib/jasmine-jsreporter/jasmine-jsreporter.js',
                            'node_modules/file-saver/FileSaver.js'
                        ],
                        dest: '<%= conf.web %>/js/'
                    }
                ]
            }
        },
        fileindex: {
            'examples-listing': {
                options: {
                    format: formatFileList,
                    absolute: true,
                    title: 'Index of dc.js examples',
                    heading: 'Examples of using dc.js',
                    description: 'An attempt to present a simple example of each chart type.',
                    sourceLink: 'https://github.com/dc-js/dc.js/tree/master/<%= conf.web %>/examples'
                },
                files: [
                    {dest: '<%= conf.web %>/examples/index.html', src: ['<%= conf.web %>/examples/*.html']}
                ]
            },
            'transitions-listing': {
                options: {
                    format: formatFileList,
                    absolute: true,
                    title: 'Index of dc.js transition tests',
                    heading: 'Eyeball tests for dc.js transitions',
                    description: 'Transitions can only be tested by eye. ' +
                        'These pages automate the transitions so they can be visually verified.',
                    sourceLink: 'https://github.com/dc-js/dc.js/tree/master/<%= conf.web %>/transitions'
                },
                files: [
                    {dest: '<%= conf.web %>/transitions/index.html', src: ['<%= conf.web %>/transitions/*.html']}
                ]
            },
            'resizing-listing': {
                options: {
                    format: formatFileList,
                    absolute: true,
                    title: 'Index of dc.js resizing tests',
                    heading: 'Eyeball tests for resizing dc.js charts',
                    description: 'It\'s a lot easier to test resizing behavior by eye. ' +
                        'These pages fit the charts to the browser dynamically so it\'s easier to test.',
                    sourceLink: 'https://github.com/dc-js/dc.js/tree/master/<%= conf.web %>/resizing'
                },
                files: [
                    {dest: '<%= conf.web %>/resizing/index.html', src: ['<%= conf.web %>/resizing/*.html']}
                ]
            },
            'zoom-listing': {
                options: {
                    format: formatFileList,
                    absolute: true,
                    title: 'Index of dc.js zoom tests',
                    heading: 'Interactive test for dc.js chart zoom',
                    description: 'It\'s hard to conceive of a way to test zoom except by trying it. ' +
                        'So this is a substitute for automated tests in this area',
                    sourceLink: 'https://github.com/dc-js/dc.js/tree/master/<%= conf.web %>/zoom'
                },
                files: [
                    {dest: '<%= conf.web %>/zoom/index.html', src: ['<%= conf.web %>/zoom/*.html']}
                ]
            }
        },

        'gh-pages': {
            options: {
                base: '<%= conf.web %>',
                message: 'Synced from from master branch.'
            },
            src: ['**']
        },
        shell: {
            merge: {
                command: function (pr) {
                    return [
                        'git fetch origin',
                        'git checkout master',
                        'git reset --hard origin/master',
                        'git fetch origin',
                        'git merge --no-ff origin/pr/' + pr + ' -m \'Merge pull request #' + pr + '\''
                    ].join('&&');
                },
                options: {
                    stdout: true,
                    failOnError: true
                }
            },
            amend: {
                command: 'git commit -a --amend --no-edit',
                options: {
                    stdout: true,
                    failOnError: true
                }
            },
            hooks: {
                command: 'cp -n scripts/pre-commit.sh .git/hooks/pre-commit' +
                    ' || echo \'Cowardly refusing to overwrite your existing git pre-commit hook.\''
            },
            hierarchy: {
                command: 'dot -Tsvg -o web/img/class-hierarchy.svg class-hierarchy.dot'
            }
        },
        browserify: {
            dev: {
                src: '<%= conf.pkg.name %>.js',
                dest: 'bundle.js',
                options: {
                    browserifyOptions: {
                        standalone: 'dc'
                    }
                }
            }
        }
    });

    grunt.registerTask('merge', 'Merge a github pull request.', function (pr) {
        grunt.log.writeln('Merge Github Pull Request #' + pr);
        grunt.task.run(['shell:merge:' + pr, 'test' , 'shell:amend']);
    });
    grunt.registerTask('test-stock-example', 'Test a new rendering of the stock example web page against a ' +
        'baseline rendering', function (option) {
            require('./regression/stock-regression-test.js').testStockExample(this.async(), option === 'diff');
        });
    grunt.registerTask('update-stock-example', 'Update the baseline stock example web page.', function () {
        require('./regression/stock-regression-test.js').updateStockExample(this.async());
    });
    grunt.registerTask('watch:jasmine-docs', function () {
        grunt.config('watch', {
            options: {
                interrupt: true
            },
            runner: grunt.config('watch').jasmineRunner,
            scripts: grunt.config('watch').scripts,
            sass: grunt.config('watch').sass
        });
        grunt.task.run('watch');
    });

    // task aliases
    grunt.registerTask('build', ['concat', 'sass', 'uglify', 'cssmin']);
    grunt.registerTask('docs', ['build', 'copy', 'jsdoc', 'jsdoc2md', 'docco', 'fileindex']);
    grunt.registerTask('web', ['docs', 'gh-pages']);
    grunt.registerTask('server', ['docs', 'fileindex', 'jasmine:specs:build', 'connect:server', 'watch:jasmine-docs']);
    grunt.registerTask('test', ['build', 'copy', 'jasmine:specs']);
    grunt.registerTask('test-browserify', ['build', 'copy', 'browserify', 'jasmine:browserify']);
    grunt.registerTask('coverage', ['build', 'copy', 'jasmine:coverage']);
    grunt.registerTask('ci', ['test', 'jasmine:specs:build', 'connect:server', 'saucelabs-jasmine']);
    grunt.registerTask('ci-pull', ['test', 'jasmine:specs:build', 'connect:server']);
    grunt.registerTask('lint', ['jshint', 'jscs']);
    grunt.registerTask('default', ['build', 'shell:hooks']);
    grunt.registerTask('doc-debug', ['build', 'jsdoc', 'jsdoc2md', 'watch:jsdoc2md']);
};

module.exports.jsFiles = [
    'src/banner.js',   // NOTE: keep this first
    'src/core.js',
    'src/errors.js',
    'src/utils.js',
    'src/logger.js',
    'src/events.js',
    'src/filters.js',
    'src/base-mixin.js',
    'src/margin-mixin.js',
    'src/color-mixin.js',
    'src/coordinate-grid-mixin.js',
    'src/stack-mixin.js',
    'src/cap-mixin.js',
    'src/bubble-mixin.js',
    'src/pie-chart.js',
    'src/bar-chart.js',
    'src/line-chart.js',
    'src/data-count.js',
    'src/data-table.js',
    'src/data-grid.js',
    'src/bubble-chart.js',
    'src/composite-chart.js',
    'src/series-chart.js',
    'src/geo-choropleth-chart.js',
    'src/bubble-overlay.js',
    'src/row-chart.js',
    'src/legend.js',
    'src/scatter-plot.js',
    'src/number-display.js',
    'src/heatmap.js',
    'src/d3.box.js',
    'src/box-plot.js',
    'src/footer.js'  // NOTE: keep this last
];
<|endoftext|>


<commit_before>'use strict';
require('coffee-script').register();

var gulp = require('gulp'),
    autoprefixer = require('gulp-autoprefixer'),
    browserify = require('browserify'),
    clean = require('gulp-clean'),
    concat = require('gulp-concat'),
    coffee = require('coffee-script'),
    debug = require('debug')('debug'),
    debugError = require('debug')('error'),
    env = require('node-env-file'),
    es = require('event-stream'),
    order = require('gulp-order'),
    path = require('path'),
    refresh = require('gulp-livereload'),
    rename = require('gulp-rename'),
    spawn = require('child_process').spawn,
    stylus = require('gulp-stylus'),
    through = require('through'),
    transform = require('vinyl-transform');

env(path.join(__dirname, '/.env'));

gulp.task('clean-css', function() {
    debug('clean-css');
    gulp.src(['public/assets/*.css'], {read: false})
        .pipe(clean());
});

gulp.task('compile-css', ['clean-css'], function() {
    debug('stylus');

    var deps = gulp.src([
        'node_modules/bootstrap/dist/css/bootstrap.min.css'
        ]);

    var assets = gulp.src('assets/index.styl')
            .pipe(stylus())
            .pipe(autoprefixer(['> 1%', 'last 2 versions']));

    // Merge both streams
    var bundle = es.merge(deps, assets)
        .pipe(order([
            'node_modules/bootstrap/dist/css/bootstrap.min.css',
            'assets/index.styl'
            ]))
        .pipe(concat('bundle.css'))
        .pipe(gulp.dest('./public/assets/'));
});

gulp.task('clean-js', function() {
    debug('clean-js');
    gulp.src(['public/assets/*.js'], {read: false})
        .pipe(clean());
});

gulp.task('compile-js', ['clean-js'], function(done) {
    debug('compile-js');
    var browserified = transform(function(filename) {
        var b = browserify(filename);
        b.transform(function (file) {
            var data = '';
            return through(write, end);

            function write (buf) { data += buf }
            function end () {
                this.queue(coffee.compile(data));
                this.queue(null);
            }
        });

        return b.bundle()
            .on('error', function(err){
                debugError(err.message);
                // end this stream
                this.end();
            });
    });

    // Compile vendor dependencies to vendor.js
    var vendor = gulp.src([
        './node_modules/jquery/dist/jquery.js',
        './node_modules/underscore/underscore.js',
        './node_modules/backbone/backbone.js',
        './node_modules/bootstrap/dist/js/bootstrap.js',
        './lib/jquery/*.*',
        ])
        .pipe(concat('vendor.js'))
        .pipe(gulp.dest('./public/assets'));

    // bundle.js
    var bundle = gulp.src(['./assets/index.coffee'])
        .pipe(browserified)
        .pipe(rename('bundle.js'))
        .pipe(gulp.dest('./public/assets'));

    bundle.on('end', function() {
            // There's some weird timing issue where the file isn't fully written
            setTimeout(done, 500);
        });
});

gulp.task('compile', ['compile-css', 'compile-js']);

gulp.task('watch', ['compile'], function() {
    refresh.listen(process.env.NODE_LIVERELOAD_PORT);

    // Watch our scripts, and when they change run browserify
    gulp.watch([
        'apps/**/client.coffee',
        'apps/**/client/*.coffee',
        'apps/**/*.styl',
        'assets/**/*.coffee',
        'assets/**/*.styl',
        'components/**/*.coffee',
        'collections/**/*.coffee',
        'components/**/*.styl',
        'models/**/*.coffee'
        ], ['compile']);

    // Watch bundled assets
    gulp.watch('public/assets/bundle.*').on('change', refresh.changed);
});

gulp.task('default', ['watch'], function() {
    // Start server
    spawn('bin/www', [], {
        stdio: 'inherit'
    });
});
<commit_msg>Adding jade extension to files we listen for live reload. There's also bug that is preventing compilation of bundle because jadeify wasn't included.<commit_after>'use strict';
require('coffee-script').register();

var gulp = require('gulp'),
    autoprefixer = require('gulp-autoprefixer'),
    browserify = require('browserify'),
    clean = require('gulp-clean'),
    concat = require('gulp-concat'),
    coffee = require('coffee-script'),
    debug = require('debug')('debug'),
    debugError = require('debug')('error'),
    env = require('node-env-file'),
    es = require('event-stream'),
    jadeify = require('jadeify'),
    order = require('gulp-order'),
    path = require('path'),
    refresh = require('gulp-livereload'),
    rename = require('gulp-rename'),
    spawn = require('child_process').spawn,
    stylus = require('gulp-stylus'),
    through = require('through'),
    transform = require('vinyl-transform');

env(path.join(__dirname, '/.env'));

gulp.task('clean-css', function() {
    debug('clean-css');
    gulp.src(['public/assets/*.css'], {read: false})
        .pipe(clean());
});

gulp.task('compile-css', ['clean-css'], function() {
    debug('stylus');

    var deps = gulp.src([
        'node_modules/bootstrap/dist/css/bootstrap.min.css'
        ]);

    var assets = gulp.src('assets/index.styl')
            .pipe(stylus())
            .pipe(autoprefixer(['> 1%', 'last 2 versions']));

    // Merge both streams
    var bundle = es.merge(deps, assets)
        .pipe(order([
            'node_modules/bootstrap/dist/css/bootstrap.min.css',
            'assets/index.styl'
            ]))
        .pipe(concat('bundle.css'))
        .pipe(gulp.dest('./public/assets/'));
});

gulp.task('clean-js', function() {
    debug('clean-js');
    gulp.src(['public/assets/*.js'], {read: false})
        .pipe(clean());
});

gulp.task('compile-js', ['clean-js'], function(done) {
    debug('compile-js');
    var browserified = transform(function(filename) {
        var b = browserify(filename);
        b.transform(jadeify);
        b.transform(function (file) {
            var data = '';
            return through(write, end);

            function write (buf) { data += buf }
            function end () {
                // Skip parsing jade requires
                // they've already gone through jadeify
                if (/\.jade$/.test(file)) {
                    this.queue(data);
                } else {
                    this.queue(coffee.compile(data));
                }
                this.queue(null);
            }
        });

        return b.bundle()
            .on('error', function(err){
                debugError(err.message);
                // end this stream
                this.end();
            });
    });

    // Compile vendor dependencies to vendor.js
    var vendor = gulp.src([
        './node_modules/jquery/dist/jquery.js',
        './node_modules/underscore/underscore.js',
        './node_modules/backbone/backbone.js',
        './node_modules/bootstrap/dist/js/bootstrap.js',
        './lib/jquery/*.*',
        ])
        .pipe(concat('vendor.js'))
        .pipe(gulp.dest('./public/assets'));

    // bundle.js
    var bundle = gulp.src(['./assets/index.coffee'])
        .pipe(browserified)
        .pipe(rename('bundle.js'))
        .pipe(gulp.dest('./public/assets'));

    bundle.on('end', function() {
            // There's some weird timing issue where the file isn't fully written
            setTimeout(done, 500);
        });
});

gulp.task('compile', ['compile-css', 'compile-js']);

gulp.task('watch', ['compile'], function() {
    refresh.listen(process.env.NODE_LIVERELOAD_PORT);

    // Watch our scripts, and when they change run browserify
    gulp.watch([
        'apps/**/client.coffee',
        'apps/**/client/*.coffee',
        'apps/**/*.styl',
        'apps/**/*.jade',
        'assets/**/*.coffee',
        'assets/**/*.styl',
        'components/**/*.coffee',
        'collections/**/*.coffee',
        'components/**/*.styl',
        'components/**/*.jade',
        'models/**/*.coffee'
        ], ['compile']);

    // Watch bundled assets
    gulp.watch('public/assets/bundle.*').on('change', refresh.changed);
});

gulp.task('default', ['watch'], function() {
    // Start server
    spawn('bin/www', [], {
        stdio: 'inherit'
    });
});
<|endoftext|>