<commit_before>'use strict';

const fs = require('fs');
const path = require('path');
const mime = require('mime');
const isImage = require('is-image');
const readDir = require('recursive-readdir');
const DataURI = require('datauri');

// This task relies on async functionality.
let asyncDone = null;

/**
 * @function testOriginalSrc
 * @param {Object} grunt
 * @param {Array} src
 * @api private
 */

function testOriginalSrc (grunt, src) {
    for (let i = 0, max = src.length; i < max; i++) {
        let item = src[i];

        if (typeof item !== 'string') {
            throwAsyncError(new Error('src must be string.'));
        } else if (!grunt.file.isDir(path.resolve(item))) {
            throwAsyncError(new Error(item + ' must be directory in src.'));
        }
    }
}

/**
 * @function testDest
 * @param {Object} grunt
 * @param {String} dest
 * @api private
 */

function testDest (grunt, dest) {
    if (typeof dest !== 'string') {
        throwAsyncError(new Error('dest must be string.'));
    } else if (grunt.file.isDir(path.resolve(dest))) {
        throwAsyncError(new Error('dest cannot be directory.'));
    }
}

/**
 * Pass error to async done function before throwing error to let
 * grunt know that the task has failed.
 *
 * @function throwAsyncError
 * @param {Error} err
 * @api private
 */

function throwAsyncError (err) {
    asyncDone(err);

    throw err;
}

/**
 * Find all image files in src directories.
 *
 * @function recurseSrcDirectories
 * @param {Object} grunt
 * @param {Object} fileData
 * @param {Object} options
 * @api private
 */

function recurseSrcDirectories (grunt, fileData, options) {
    let src = fileData.orig.src.map((item) => path.resolve(item));
    let promises = [];

    // Ignore everything except directories and image files.
    // Store function in array for recursive-readdir module.
    let ignoreCallback = [(path, stats) => !(stats.isDirectory() || isImage(path))];

    for (let i = 0, max = src.length; i < max; i++) {
        promises.push(readDir(src[i], ignoreCallback).then((value) => value, (err) => err));
    }

    Promise.all(promises)
        .then((values) => {
            streamToDest(grunt, fileData, options, values.flat());
        }, throwAsyncError);
}

/**
 * Stream data URIs from matched image files into dest file with their
 * respective id and MIME.
 *
 * @function streamToDest
 * @param {Object} grunt
 * @param {Object} fileData
 * @param {Object} options
 * @param {Array} matches
 * @api private
 */

function streamToDest (grunt, fileData, options, matches) {
    // Always prepend useObjectURLs invocation before parseBuffer invocation.
    let data = options.useObjectURLs ? 'BLITTER.useObjectURLs();' : '';

    // Start parseBuffer wrap.
    data += 'BLITTER.parseBuffer([';

    let writable = fs.createWriteStream(path.resolve(fileData.dest));

    writable.on('error', throwAsyncError);

    writable.write(data, 'utf8', () => {
        streamBuffer(grunt, matches, writable);
    });
}

/**
 * Stream the buffer recursively inside the parseBuffer invocation.
 *
 * @function streamBuffer
 * @param {Object} grunt
 * @param {Array} matches
 * @param {WriteStream} writable
 * @api private
 */

function streamBuffer (grunt, matches, writable) {
    let match = matches.pop();

    if (match === undefined) {
        // End parseBuffer wrap.
        writable.end(']);', 'utf8', () => {
            asyncDone(true);
        });
    } else {
        // Start DataURI wrap.
        let data = '"' + path.parse(match).name + '","' + mime.getType(match) + '","';

        writable.write(data, 'utf8', () => {
            let data = new DataURI();

            data.on('error', throwAsyncError);

            // Everytime readable stream finishes piping all data to the
            // writable stream move on to next matched file.
            data.on('end', () => {
                // End DataURI wrap.
                let data = matches.length === 0 ? '"' : '",';

                writable.write(data, 'utf8', () => {
                    streamBuffer(grunt, matches, writable);
                });
            });

            data.pipe(writable, { end: false });
            data.encode(match);
        });
    }
}

module.exports = function (grunt) {
    grunt.registerMultiTask('blitter', function () {
        // Execute task asynchronously.
        asyncDone = grunt.task.current.async();

        let options = this.options();

        options.useObjectURLs = options.useObjectURLs === undefined ? true : Boolean(options.useObjectURLs);

        for (let i = 0, max = this.files.length; i < max; i++) {
            let fileData = this.files[i];

            testOriginalSrc(grunt, fileData.orig.src);
            testDest(grunt, fileData.dest);
            recurseSrcDirectories(grunt, fileData, options);
        }
    });
};
<commit_msg>{Fix: blitter.js} Change path parameter name to file.<commit_after>'use strict';

const fs = require('fs');
const path = require('path');
const mime = require('mime');
const isImage = require('is-image');
const readDir = require('recursive-readdir');
const DataURI = require('datauri');

// This task relies on async functionality.
let asyncDone = null;

/**
 * @function testOriginalSrc
 * @param {Object} grunt
 * @param {Array} src
 * @api private
 */

function testOriginalSrc (grunt, src) {
    for (let i = 0, max = src.length; i < max; i++) {
        let item = src[i];

        if (typeof item !== 'string') {
            throwAsyncError(new Error('src must be string.'));
        } else if (!grunt.file.isDir(path.resolve(item))) {
            throwAsyncError(new Error(item + ' must be directory in src.'));
        }
    }
}

/**
 * @function testDest
 * @param {Object} grunt
 * @param {String} dest
 * @api private
 */

function testDest (grunt, dest) {
    if (typeof dest !== 'string') {
        throwAsyncError(new Error('dest must be string.'));
    } else if (grunt.file.isDir(path.resolve(dest))) {
        throwAsyncError(new Error('dest cannot be directory.'));
    }
}

/**
 * Pass error to async done function before throwing error to let
 * grunt know that the task has failed.
 *
 * @function throwAsyncError
 * @param {Error} err
 * @api private
 */

function throwAsyncError (err) {
    asyncDone(err);

    throw err;
}

/**
 * Find all image files in src directories.
 *
 * @function recurseSrcDirectories
 * @param {Object} grunt
 * @param {Object} fileData
 * @param {Object} options
 * @api private
 */

function recurseSrcDirectories (grunt, fileData, options) {
    let src = fileData.orig.src.map((item) => path.resolve(item));
    let promises = [];

    // Ignore everything except directories and image files.
    // Store function in array for recursive-readdir module.
    let ignoreCallback = [(file, stats) => !(stats.isDirectory() || isImage(file))];

    for (let i = 0, max = src.length; i < max; i++) {
        promises.push(readDir(src[i], ignoreCallback).then((value) => value, (err) => err));
    }

    Promise.all(promises)
        .then((values) => {
            streamToDest(grunt, fileData, options, values.flat());
        }, throwAsyncError);
}

/**
 * Stream data URIs from matched image files into dest file with their
 * respective id and MIME.
 *
 * @function streamToDest
 * @param {Object} grunt
 * @param {Object} fileData
 * @param {Object} options
 * @param {Array} matches
 * @api private
 */

function streamToDest (grunt, fileData, options, matches) {
    // Always prepend useObjectURLs invocation before parseBuffer invocation.
    let data = options.useObjectURLs ? 'BLITTER.useObjectURLs();' : '';

    // Start parseBuffer wrap.
    data += 'BLITTER.parseBuffer([';

    let writable = fs.createWriteStream(path.resolve(fileData.dest));

    writable.on('error', throwAsyncError);

    writable.write(data, 'utf8', () => {
        streamBuffer(grunt, matches, writable);
    });
}

/**
 * Stream the buffer recursively inside the parseBuffer invocation.
 *
 * @function streamBuffer
 * @param {Object} grunt
 * @param {Array} matches
 * @param {WriteStream} writable
 * @api private
 */

function streamBuffer (grunt, matches, writable) {
    let match = matches.pop();

    if (match === undefined) {
        // End parseBuffer wrap.
        writable.end(']);', 'utf8', () => {
            asyncDone(true);
        });
    } else {
        // Start DataURI wrap.
        let data = '"' + path.parse(match).name + '","' + mime.getType(match) + '","';

        writable.write(data, 'utf8', () => {
            let data = new DataURI();

            data.on('error', throwAsyncError);

            // Everytime readable stream finishes piping all data to the
            // writable stream move on to next matched file.
            data.on('end', () => {
                // End DataURI wrap.
                let data = matches.length === 0 ? '"' : '",';

                writable.write(data, 'utf8', () => {
                    streamBuffer(grunt, matches, writable);
                });
            });

            data.pipe(writable, { end: false });
            data.encode(match);
        });
    }
}

module.exports = function (grunt) {
    grunt.registerMultiTask('blitter', function () {
        // Execute task asynchronously.
        asyncDone = grunt.task.current.async();

        let options = this.options();

        options.useObjectURLs = options.useObjectURLs === undefined ? true : Boolean(options.useObjectURLs);

        for (let i = 0, max = this.files.length; i < max; i++) {
            let fileData = this.files[i];

            testOriginalSrc(grunt, fileData.orig.src);
            testDest(grunt, fileData.dest);
            recurseSrcDirectories(grunt, fileData, options);
        }
    });
};
<|endoftext|>


<commit_before>/*globals CustomEvent*/
import Resolver from 'ember/resolver';

var App = Ember.Application.extend({
  LOG_ACTIVE_GENERATION   : true,
  LOG_MODULE_RESOLVER     : true,
  LOG_TRANSITIONS         : true,
  LOG_TRANSITIONS_INTERNAL: true,
  LOG_VIEW_LOOKUPS        : true,
  modulePrefix            : 'appkit', // TODO: loaded via config
  Resolver                : Resolver['default'],
  init: function () {
    window.ENV.firebaseRoot = new Firebase("https://" + window.ENV.dbName + ".firebaseio.com/");
    this._super.apply(this, arguments);
  }
});

Ember.debouncedObserver = function(func, key, time) {
    return Em.observer(function() {
        Em.run.debounce(this, func, time);
    }, key);
};

Ember.throttledObserver = function(func, key, time) {
    return Em.observer(function() {
        Em.run.throttle(this, func, time);
    }, key);
};

Ember.Application.initializer({
  name: "BuildEnvironmentDetector",
  initialize: function (container, application) {
    application.deferReadiness();

    var self     = this,
        buildEnv = Ember.Object.create();

    application.register('build-environment:environment:current', buildEnv, { instantiate: false, singleton: true });
    Ember.A(['model', 'controller', 'view', 'route', 'helper']).forEach(function (component) {
      application.inject(component, 'buildEnvironment', 'build-environment:environment:current');
    });

    var isLocal     = false;
    var localSocket = null;
    var keepReload  = Ember.$('meta[name="keepReload"]').attr('content');

    var req = new XMLHttpRequest();
    req.open('GET', document.location, false);
    req.send(null);
    var headers = req.getAllResponseHeaders().toLowerCase();

    if (headers.indexOf('x-webhook-local') !== -1)
    {
      isLocal = true;
      localSocket = Ember.Object.create({
        socket        : new window.WebSocket('ws://' + document.location.hostname + ':6557'),
        doneCallback  : null,
        connected     : false,
        lostConnection: false,
        message       : '',
      });

      localSocket.socket.onmessage = function (event) {
        if (event.data === 'done') {
          if (localSocket.get('doneCallback')) {
            localSocket.get('doneCallback')();
          }
          localSocket.set('doneCallback', null); //Reset so done doesn't get called twice
        } else if (event.data.indexOf('done:') === 0) {
          var data = JSON.parse(event.data.replace('done:', ''));
          if (localSocket.get('doneCallback')) {
            localSocket.get('doneCallback')(data);
          }
          localSocket.set('doneCallback', null); //Reset so done doesn't get called twice
        } else if (event.data.indexOf('message:') === 0) {
          var message = JSON.parse(event.data.replce('message:', ''));
          localSocket.set('message', message);
        }
      };

      localSocket.socket.onopen = function () {
        localSocket.set('connected', true);
      };

      if (!$('meta[name=suppressAlert]').attr('content')) {
        localSocket.socket.onclose = function () {
          localSocket.set('connected', false);
          localSocket.set('lostConnection', true);
        };
      }

      // Shut down LiveReload
      if (window.LiveReload && !keepReload) {
        var shutDown = new CustomEvent('LiveReloadShutDown');
        document.addEventListener("LiveReloadConnect", function () {
          document.dispatchEvent(shutDown);
        }, false);
      }
    }

    var siteName = Ember.$('meta[name="siteName"]').attr('content');
    buildEnv.set('local', isLocal);
    buildEnv.set('localSocket', localSocket);
    buildEnv.set('siteName', siteName);
    buildEnv.set('siteUrl', 'http://' + siteName + '.webhook.com/');
    buildEnv.set('building', false);

    window.ENV.siteDNS = siteName + '.webhook.org';
    window.ENV.firebaseRoot.child('/management/sites/' + siteName + '/dns').on('value', function (snap) {
      if (snap.val()) {
        window.ENV.siteDNS = snap.val();
      }
    });

    application.set('buildEnvironment', buildEnv);

    Ember.run(application, application.advanceReadiness);
  }
});

Ember.Application.initializer({
  name: "FirebaseSimpleLogin",
  initialize: function (container, application) {

    application.deferReadiness();

    var self     = this,
        siteName = Ember.$('meta[name="siteName"]').attr('content'),
        session = Ember.Object.create(),
        bucket = '';

    // Add `session` to all the things
    application.register('firebase-simple-login:session:current', session, { instantiate: false, singleton: true });
    Ember.A(['model', 'controller', 'view', 'route']).forEach(function (component) {
      application.inject(component, 'session', 'firebase-simple-login:session:current');
    });

    var managementSiteRef = window.ENV.firebaseRoot.child('management/sites/' + siteName);

    var firebaseAuth = new FirebaseSimpleLogin(window.ENV.firebaseRoot, function (error, user) {

      var initializeUser = function(snapshot) {
        bucket = snapshot.val();

        window.ENV.firebase = window.ENV.firebaseRoot.child('buckets/' + siteName + '/' + bucket + '/dev');

        // if you just logged in, we have to set the firebase property
        DS.FirebaseAdapter.reopen({
          firebase: window.ENV.firebase
        });

        if (application.get('buildEnvironment').local === false) {
          setupMessageListener(siteName, application.get('buildEnvironment'));
        }

        session.set('error', null);
        session.set('site', {
          name : siteName,
          token: bucket
        });

        session.set('isOwner', false);

        Ember.Logger.info('Logged in as ' + user.email);

        managementSiteRef.on('value', function (snapshot) {
          var siteData = snapshot.val();
          var escapedEmail = user.email.replace(/\./g, ',1');

          if (siteData.owners[escapedEmail]) {
            Ember.Logger.info('Logged in user is a site owner.');
            session.set('isOwner', true);
            // Owners get billing vars.
            window.ENV.firebaseRoot.child('billing/sites/' + siteName).on('value', function (snapshot) {
              var billing = snapshot.val();

              session.set('billing', {
                active: billing.active,
                status: billing.status,
                isPaid: billing.status === 'paid',
                isTrial: billing.status === 'trialing',
                url: 'http://billing.webhook.com/site/' + siteName
              });
              Ember.Logger.info('Set billing vars on session for owners.', session.get('billing'));

              session.set('user', user);

              Ember.run(application, application.advanceReadiness);
            });
          } else if (siteData.users[escapedEmail]) {
            Ember.Logger.info('Logged in user is a site user.');
            session.set('isOwner', false);
            session.set('user', user);
            Ember.run(application, application.advanceReadiness);
          } else {
            session.set('isOwner', false);
            session.set('user', user);
            Ember.Logger.error('Logged in user is neither a site owner or site user.');
            Ember.run(application, application.advanceReadiness);
          }

        });
      };

      if (error) {
        // an error occurred while attempting login
        session.set('error', error);
        Ember.run(application, application.advanceReadiness);
      } else if (user) {

        managementSiteRef.child('key').once('value', initializeUser, function (error) {

          if (error.code === 'PERMISSION_DENIED') {
            var escapedEmail = user.email.replace(/\./g, ',1');
            // Try to add to user list, if this is allowed they were a potential user
            managementSiteRef.child('users').child(escapedEmail).set(user.email, function (error) {
              if (error) {
                session.get('auth').logout();
                session.set('error', error);
                Ember.run(application, application.advanceReadiness);
              } else {
                // Try to delete self from potential user list
                managementSiteRef.child('potential_users').child(escapedEmail).remove(function (error) {
                  if (error) {
                    session.get('auth').logout();
                    session.set('error', error);
                    Ember.run(application, application.advanceReadiness);
                  } else {
                    // Redo original authorization call
                    managementSiteRef.child('key').once('value', initializeUser, function (error) {
                      if (error) {
                        session.get('auth').logout();
                        session.set('error', error);
                      }
                      Ember.run(application, application.advanceReadiness);
                    });
                  }
                });
              }
            });
            // User may be a potential, try and elevate to user
          } else {
            session.get('auth').logout();
            session.set('error', error);
            Ember.run(application, application.advanceReadiness);
          }

        });

      } else {
        // user is logged out
        session.set('user', null);
        session.set('site', null);
        Ember.run(application, application.advanceReadiness);
      }
    });

    session.set('auth', firebaseAuth);

    window.ENV.search = function(query, page, typeName, callback) {
      var site = siteName;
      var key = bucket;

      if(typeof typeName === 'function') {
        callback = typeName;
        typeName = null;
      }

      Ember.$.ajax({
        url: 'http://server.webhook.com:3000/search/',
        type: 'POST',
        data: {
          token: key,
          site: site,
          query: query,
          page: page,
          typeName: typeName
        },
        success: function(data, status, xhr) {

          if(data.error) {
            callback(data.error, []);
          } else if (!data.hits) {
            callback('NO IDEA', []);
          } else {
            var items = [];
            Ember.$.each(data.hits, function(index, value) {
              var highlights = [];

              var name = value.fields.name ? value.fields.name[0] : '';

              if(value.highlight) {
                for(var key in value.highlight) {
                  if(key === 'name') {
                    name = value.highlight[key][0];
                  } else {
                    highlights.push({ key: key, highlight: value.highlight[key][0] });
                  }
                }
              }

              items.push({
                name: name,
                oneOff: value.fields.__oneOff ? (value.fields.__oneOff[0] === "true" ? true : false ): false,
                id: value._id,
                type: value._type,
                highlights: highlights
              });
            });

            callback(null, items);
          }
        },
        error: function(xhr, status, error) {
          callback(error, []);
        }
      });
    };

    window.ENV.indexItem = function(id, data, oneOff, typeName) {
      var site = siteName;
      var key = bucket;

      Ember.Logger.info('Updating search index for', typeName, id);

      Ember.$.ajax({
        url: 'http://server.webhook.com:3000/search/index/',
        type: 'POST',
        data: {
          id: id,
          token: key,
          site: site,
          data: JSON.stringify(data),
          typeName: typeName,
          oneOff: oneOff
        }
      }).done(function () {
        Ember.Logger.info('Search index updated for', typeName, id);
      }).fail(function (jqXHR, textStatus, error) {
        Ember.Logger.error(error);
      });
    };

    window.ENV.deleteIndex = function(id, typeName) {
      var site = siteName;
      var key = bucket;

      Ember.$.ajax({
        url: 'http://server.webhook.com:3000/search/delete/',
        type: 'POST',
        data: {
          id: id,
          token: key,
          site: site,
          typeName: typeName
        },
        success: function(data, status, xhr) {
        }
      });
    };

    window.ENV.deleteTypeIndex = function(typeName) {
      var site = siteName;
      var key = bucket;

      Ember.$.ajax({
        url: 'http://server.webhook.com:3000/search/delete/type/',
        type: 'POST',
        data: {
          token: key,
          site: site,
          typeName: typeName
        },
        success: function(data, status, xhr) {
        }
      });
    };

    // just passes on args to notify action
    window.ENV.notify = function() {
      var route = application.__container__.lookup('route:application');
      var args = Array.prototype.slice.call(arguments);
      args.unshift('notify');

      route.send.apply(route, args);
    };

    function uniqueId() {
      return Date.now() + 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
      });
    }

    window.ENV.sendBuildSignal = function (publish_date) {

      var user = session.get('user.email');

      if (application.get('buildEnvironment').local === false) {

        var data = {
          'userid': user,
          'sitename': siteName,
          'id': uniqueId()
        };

        if (publish_date) {
          data.build_time = publish_date;
        }

        window.ENV.firebase.root().child('management/commands/build/' + siteName).set(data, function () {});
        application.get('buildEnvironment').set('building', true);
      } else {
        window.ENV.sendGruntCommand('build');
      }
    };

    window.ENV.sendGruntCommand = function (command, callback) {
      var localSocket = application.get('buildEnvironment').localSocket;
      if (localSocket && localSocket.connected) {
        localSocket.socket.send(command);
        if (callback) {
          localSocket.doneCallback = callback;
        }
      }
    };
  }
});

var listener = null;
var setupMessageListener = function(siteName, buildEnv) {
  var ref = window.ENV.firebase.root().child('management/sites/' + siteName + '/messages');
  if(listener) {
    ref.off('child_added', listener);
    listener = null;
  }

  var initialIds = {};
  ref.once('value', function(totalData) {
    var val = totalData.val();

    for(var key in val) {
      initialIds[key] = true;
    }

    listener = ref.on('child_added', function(snap) {
      var now = Date.now();
      var message = snap.val();
      var id = snap.name();

      if(!initialIds[id]) {
        if(message.code === 'BUILD') {
          if(message.status === 0) {
            window.ENV.notify('success', 'Site build complete', { icon: 'refresh' });
          } else {
            window.ENV.notify('danger', 'Site build failed', { icon: 'remove' });
          }
          buildEnv.set('building', false);
        }
      }
    });
  });
};

// Before any route, kick user to login if they aren't logged in
Ember.Route.reopen({
  beforeModel: function (transition) {
    var openRoutes = ['login', 'password-reset', 'create-user', 'confirm-email', 'resend-email', 'expired'];

    if (this.get('session.user') && !this.get('session.billing.active') && transition.targetName !== 'expired') {
      transition.abort();
      this.transitionTo('expired');
    }

    else if (Ember.$.inArray(transition.targetName, openRoutes) === -1 && !this.get('session.user')) {
      Ember.Logger.info('Attempting to access protected route when not logged in. Aborting.');
      this.set('session.transition', transition);
      transition.abort();
      this.transitionTo('login');
    }

    else {

      // Only executed if you are logged in
      var ownerRoutes = ['wh.settings.team', 'wh.settings.general', 'wh.settings.billing', 'wh.settings.domain', 'wh.settings.data'];
      if (Ember.$.inArray(transition.targetName, ownerRoutes) !== -1 && !this.get('session.isOwner')) {
        Ember.Logger.info('Attempting to access protected route without permission. Aborting.');
        this.set('session.transition', transition);
        transition.abort();
        this.transitionTo('wh.index');
      }

    }

  }
});

Ember.TextField.reopen({
  attributeBindings: [ 'required' ]
});

// Ian doesn't like pluralizing, singularizing
Ember.Inflector.inflector.pluralize = function (string ) { return string; };
Ember.Inflector.inflector.singularize = function (string ) { return string; };

export default App;
<commit_msg>handle the null case<commit_after>/*globals CustomEvent*/
import Resolver from 'ember/resolver';

var App = Ember.Application.extend({
  LOG_ACTIVE_GENERATION   : true,
  LOG_MODULE_RESOLVER     : true,
  LOG_TRANSITIONS         : true,
  LOG_TRANSITIONS_INTERNAL: true,
  LOG_VIEW_LOOKUPS        : true,
  modulePrefix            : 'appkit', // TODO: loaded via config
  Resolver                : Resolver['default'],
  init: function () {
    window.ENV.firebaseRoot = new Firebase("https://" + window.ENV.dbName + ".firebaseio.com/");
    this._super.apply(this, arguments);
  }
});

Ember.debouncedObserver = function(func, key, time) {
    return Em.observer(function() {
        Em.run.debounce(this, func, time);
    }, key);
};

Ember.throttledObserver = function(func, key, time) {
    return Em.observer(function() {
        Em.run.throttle(this, func, time);
    }, key);
};

Ember.Application.initializer({
  name: "BuildEnvironmentDetector",
  initialize: function (container, application) {
    application.deferReadiness();

    var self     = this,
        buildEnv = Ember.Object.create();

    application.register('build-environment:environment:current', buildEnv, { instantiate: false, singleton: true });
    Ember.A(['model', 'controller', 'view', 'route', 'helper']).forEach(function (component) {
      application.inject(component, 'buildEnvironment', 'build-environment:environment:current');
    });

    var isLocal     = false;
    var localSocket = null;
    var keepReload  = Ember.$('meta[name="keepReload"]').attr('content');

    var req = new XMLHttpRequest();
    req.open('GET', document.location, false);
    req.send(null);
    var headers = req.getAllResponseHeaders().toLowerCase();

    if (headers.indexOf('x-webhook-local') !== -1)
    {
      isLocal = true;
      localSocket = Ember.Object.create({
        socket        : new window.WebSocket('ws://' + document.location.hostname + ':6557'),
        doneCallback  : null,
        connected     : false,
        lostConnection: false,
        message       : '',
      });

      localSocket.socket.onmessage = function (event) {
        if (event.data === 'done') {
          if (localSocket.get('doneCallback')) {
            localSocket.get('doneCallback')();
          }
          localSocket.set('doneCallback', null); //Reset so done doesn't get called twice
        } else if (event.data.indexOf('done:') === 0) {
          var data = JSON.parse(event.data.replace('done:', ''));
          if (localSocket.get('doneCallback')) {
            localSocket.get('doneCallback')(data);
          }
          localSocket.set('doneCallback', null); //Reset so done doesn't get called twice
        } else if (event.data.indexOf('message:') === 0) {
          var message = JSON.parse(event.data.replce('message:', ''));
          localSocket.set('message', message);
        }
      };

      localSocket.socket.onopen = function () {
        localSocket.set('connected', true);
      };

      if (!$('meta[name=suppressAlert]').attr('content')) {
        localSocket.socket.onclose = function () {
          localSocket.set('connected', false);
          localSocket.set('lostConnection', true);
        };
      }

      // Shut down LiveReload
      if (window.LiveReload && !keepReload) {
        var shutDown = new CustomEvent('LiveReloadShutDown');
        document.addEventListener("LiveReloadConnect", function () {
          document.dispatchEvent(shutDown);
        }, false);
      }
    }

    var siteName = Ember.$('meta[name="siteName"]').attr('content');
    buildEnv.set('local', isLocal);
    buildEnv.set('localSocket', localSocket);
    buildEnv.set('siteName', siteName);
    buildEnv.set('siteUrl', 'http://' + siteName + '.webhook.com/');
    buildEnv.set('building', false);

    window.ENV.siteDNS = siteName + '.webhook.org';
    window.ENV.firebaseRoot.child('/management/sites/' + siteName + '/dns').on('value', function (snap) {
      if (snap.val()) {
        window.ENV.siteDNS = snap.val();
      }
    });

    application.set('buildEnvironment', buildEnv);

    Ember.run(application, application.advanceReadiness);
  }
});

Ember.Application.initializer({
  name: "FirebaseSimpleLogin",
  initialize: function (container, application) {

    application.deferReadiness();

    var self     = this,
        siteName = Ember.$('meta[name="siteName"]').attr('content'),
        session = Ember.Object.create(),
        bucket = '';

    // Add `session` to all the things
    application.register('firebase-simple-login:session:current', session, { instantiate: false, singleton: true });
    Ember.A(['model', 'controller', 'view', 'route']).forEach(function (component) {
      application.inject(component, 'session', 'firebase-simple-login:session:current');
    });

    var managementSiteRef = window.ENV.firebaseRoot.child('management/sites/' + siteName);

    var firebaseAuth = new FirebaseSimpleLogin(window.ENV.firebaseRoot, function (error, user) {

      var initializeUser = function(snapshot) {
        bucket = snapshot.val();

        window.ENV.firebase = window.ENV.firebaseRoot.child('buckets/' + siteName + '/' + bucket + '/dev');

        // if you just logged in, we have to set the firebase property
        DS.FirebaseAdapter.reopen({
          firebase: window.ENV.firebase
        });

        if (application.get('buildEnvironment').local === false) {
          setupMessageListener(siteName, application.get('buildEnvironment'));
        }

        session.set('error', null);
        session.set('site', {
          name : siteName,
          token: bucket
        });

        session.set('isOwner', false);

        Ember.Logger.info('Logged in as ' + user.email);

        managementSiteRef.on('value', function (snapshot) {
          var siteData = snapshot.val();
          var escapedEmail = user.email.replace(/\./g, ',1');

          if (siteData.owners[escapedEmail]) {
            Ember.Logger.info('Logged in user is a site owner.');
            session.set('isOwner', true);
            // Owners get billing vars.
            window.ENV.firebaseRoot.child('billing/sites/' + siteName).on('value', function (snapshot) {
              var billing = snapshot.val();

              if(billing !== null) {
                session.set('billing', {
                  active: billing.active,
                  status: billing.status,
                  isPaid: billing.status === 'paid',
                  isTrial: billing.status === 'trialing',
                  url: 'http://billing.webhook.com/site/' + siteName
                });
              } else {
                session.set('billing', {
                  active: true,
                  status: 'paid',
                  isPaid: true,
                  isTrial: false,
                  url: 'http://billing.webhook.com/site/' + siteName
                });
              }

              Ember.Logger.info('Set billing vars on session for owners.', session.get('billing'));

              session.set('user', user);

              Ember.run(application, application.advanceReadiness);
            });
          } else if (siteData.users[escapedEmail]) {
            Ember.Logger.info('Logged in user is a site user.');
            session.set('isOwner', false);
            session.set('user', user);
            Ember.run(application, application.advanceReadiness);
          } else {
            session.set('isOwner', false);
            session.set('user', user);
            Ember.Logger.error('Logged in user is neither a site owner or site user.');
            Ember.run(application, application.advanceReadiness);
          }

        });
      };

      if (error) {
        // an error occurred while attempting login
        session.set('error', error);
        Ember.run(application, application.advanceReadiness);
      } else if (user) {

        managementSiteRef.child('key').once('value', initializeUser, function (error) {

          if (error.code === 'PERMISSION_DENIED') {
            var escapedEmail = user.email.replace(/\./g, ',1');
            // Try to add to user list, if this is allowed they were a potential user
            managementSiteRef.child('users').child(escapedEmail).set(user.email, function (error) {
              if (error) {
                session.get('auth').logout();
                session.set('error', error);
                Ember.run(application, application.advanceReadiness);
              } else {
                // Try to delete self from potential user list
                managementSiteRef.child('potential_users').child(escapedEmail).remove(function (error) {
                  if (error) {
                    session.get('auth').logout();
                    session.set('error', error);
                    Ember.run(application, application.advanceReadiness);
                  } else {
                    // Redo original authorization call
                    managementSiteRef.child('key').once('value', initializeUser, function (error) {
                      if (error) {
                        session.get('auth').logout();
                        session.set('error', error);
                      }
                      Ember.run(application, application.advanceReadiness);
                    });
                  }
                });
              }
            });
            // User may be a potential, try and elevate to user
          } else {
            session.get('auth').logout();
            session.set('error', error);
            Ember.run(application, application.advanceReadiness);
          }

        });

      } else {
        // user is logged out
        session.set('user', null);
        session.set('site', null);
        Ember.run(application, application.advanceReadiness);
      }
    });

    session.set('auth', firebaseAuth);

    window.ENV.search = function(query, page, typeName, callback) {
      var site = siteName;
      var key = bucket;

      if(typeof typeName === 'function') {
        callback = typeName;
        typeName = null;
      }

      Ember.$.ajax({
        url: 'http://server.webhook.com:3000/search/',
        type: 'POST',
        data: {
          token: key,
          site: site,
          query: query,
          page: page,
          typeName: typeName
        },
        success: function(data, status, xhr) {

          if(data.error) {
            callback(data.error, []);
          } else if (!data.hits) {
            callback('NO IDEA', []);
          } else {
            var items = [];
            Ember.$.each(data.hits, function(index, value) {
              var highlights = [];

              var name = value.fields.name ? value.fields.name[0] : '';

              if(value.highlight) {
                for(var key in value.highlight) {
                  if(key === 'name') {
                    name = value.highlight[key][0];
                  } else {
                    highlights.push({ key: key, highlight: value.highlight[key][0] });
                  }
                }
              }

              items.push({
                name: name,
                oneOff: value.fields.__oneOff ? (value.fields.__oneOff[0] === "true" ? true : false ): false,
                id: value._id,
                type: value._type,
                highlights: highlights
              });
            });

            callback(null, items);
          }
        },
        error: function(xhr, status, error) {
          callback(error, []);
        }
      });
    };

    window.ENV.indexItem = function(id, data, oneOff, typeName) {
      var site = siteName;
      var key = bucket;

      Ember.Logger.info('Updating search index for', typeName, id);

      Ember.$.ajax({
        url: 'http://server.webhook.com:3000/search/index/',
        type: 'POST',
        data: {
          id: id,
          token: key,
          site: site,
          data: JSON.stringify(data),
          typeName: typeName,
          oneOff: oneOff
        }
      }).done(function () {
        Ember.Logger.info('Search index updated for', typeName, id);
      }).fail(function (jqXHR, textStatus, error) {
        Ember.Logger.error(error);
      });
    };

    window.ENV.deleteIndex = function(id, typeName) {
      var site = siteName;
      var key = bucket;

      Ember.$.ajax({
        url: 'http://server.webhook.com:3000/search/delete/',
        type: 'POST',
        data: {
          id: id,
          token: key,
          site: site,
          typeName: typeName
        },
        success: function(data, status, xhr) {
        }
      });
    };

    window.ENV.deleteTypeIndex = function(typeName) {
      var site = siteName;
      var key = bucket;

      Ember.$.ajax({
        url: 'http://server.webhook.com:3000/search/delete/type/',
        type: 'POST',
        data: {
          token: key,
          site: site,
          typeName: typeName
        },
        success: function(data, status, xhr) {
        }
      });
    };

    // just passes on args to notify action
    window.ENV.notify = function() {
      var route = application.__container__.lookup('route:application');
      var args = Array.prototype.slice.call(arguments);
      args.unshift('notify');

      route.send.apply(route, args);
    };

    function uniqueId() {
      return Date.now() + 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
      });
    }

    window.ENV.sendBuildSignal = function (publish_date) {

      var user = session.get('user.email');

      if (application.get('buildEnvironment').local === false) {

        var data = {
          'userid': user,
          'sitename': siteName,
          'id': uniqueId()
        };

        if (publish_date) {
          data.build_time = publish_date;
        }

        window.ENV.firebase.root().child('management/commands/build/' + siteName).set(data, function () {});
        application.get('buildEnvironment').set('building', true);
      } else {
        window.ENV.sendGruntCommand('build');
      }
    };

    window.ENV.sendGruntCommand = function (command, callback) {
      var localSocket = application.get('buildEnvironment').localSocket;
      if (localSocket && localSocket.connected) {
        localSocket.socket.send(command);
        if (callback) {
          localSocket.doneCallback = callback;
        }
      }
    };
  }
});

var listener = null;
var setupMessageListener = function(siteName, buildEnv) {
  var ref = window.ENV.firebase.root().child('management/sites/' + siteName + '/messages');
  if(listener) {
    ref.off('child_added', listener);
    listener = null;
  }

  var initialIds = {};
  ref.once('value', function(totalData) {
    var val = totalData.val();

    for(var key in val) {
      initialIds[key] = true;
    }

    listener = ref.on('child_added', function(snap) {
      var now = Date.now();
      var message = snap.val();
      var id = snap.name();

      if(!initialIds[id]) {
        if(message.code === 'BUILD') {
          if(message.status === 0) {
            window.ENV.notify('success', 'Site build complete', { icon: 'refresh' });
          } else {
            window.ENV.notify('danger', 'Site build failed', { icon: 'remove' });
          }
          buildEnv.set('building', false);
        }
      }
    });
  });
};

// Before any route, kick user to login if they aren't logged in
Ember.Route.reopen({
  beforeModel: function (transition) {
    var openRoutes = ['login', 'password-reset', 'create-user', 'confirm-email', 'resend-email', 'expired'];

    if (this.get('session.user') && !this.get('session.billing.active') && transition.targetName !== 'expired') {
      transition.abort();
      this.transitionTo('expired');
    }

    else if (Ember.$.inArray(transition.targetName, openRoutes) === -1 && !this.get('session.user')) {
      Ember.Logger.info('Attempting to access protected route when not logged in. Aborting.');
      this.set('session.transition', transition);
      transition.abort();
      this.transitionTo('login');
    }

    else {

      // Only executed if you are logged in
      var ownerRoutes = ['wh.settings.team', 'wh.settings.general', 'wh.settings.billing', 'wh.settings.domain', 'wh.settings.data'];
      if (Ember.$.inArray(transition.targetName, ownerRoutes) !== -1 && !this.get('session.isOwner')) {
        Ember.Logger.info('Attempting to access protected route without permission. Aborting.');
        this.set('session.transition', transition);
        transition.abort();
        this.transitionTo('wh.index');
      }

    }

  }
});

Ember.TextField.reopen({
  attributeBindings: [ 'required' ]
});

// Ian doesn't like pluralizing, singularizing
Ember.Inflector.inflector.pluralize = function (string ) { return string; };
Ember.Inflector.inflector.singularize = function (string ) { return string; };

export default App;
<|endoftext|>


<commit_before>/**
 * app.js
 *
 * This is the entry file for the application, only setup and boilerplate
 * code.
 */

// Needed for redux-saga es6 generator support
import 'babel-polyfill';

/* eslint-disable import/no-unresolved */
// Load the favicon, the manifest.json file and the .htaccess file
import 'file?name=[name].[ext]!./favicon.ico';
import '!file?name=[name].[ext]!./manifest.json';
import 'file?name=[name].[ext]!./.htaccess';
/* eslint-enable import/no-unresolved */

// Import all the third party stuff
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { applyRouterMiddleware, Router, browserHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import FontFaceObserver from 'fontfaceobserver';
import useScroll from 'react-router-scroll';
import configureStore from './store';

// Observe loading of Open Sans (to remove open sans, remove the <link> tag in
// the index.html file and this observer)
import styles from 'containers/App/styles.css';
const openSansObserver = new FontFaceObserver('Open Sans', {});

// When Open Sans is loaded, add a font-family using Open Sans to the body
openSansObserver.load().then(() => {
  document.body.classList.add(styles.fontLoaded);
}, () => {
  document.body.classList.remove(styles.fontLoaded);
});

// Import i18n messages
import { translationMessages } from './i18n';

// Create redux store with history
// this uses the singleton browserHistory provided by react-router
// Optionally, this could be changed to leverage a created history
// e.g. `const browserHistory = useRouterHistory(createBrowserHistory)();`
const initialState = {};
const store = configureStore(initialState, browserHistory);

// If you use Redux devTools extension, since v2.0.1, they added an
// `updateStore`, so any enhancers that change the store object
// could be used with the devTools' store.
// As this boilerplate uses Redux & Redux-Saga, the `updateStore` is needed
// if you want to `take` actions in your Sagas, dispatched from devTools.
if (window.devToolsExtension) {
  window.devToolsExtension.updateStore(store);
}

// Sync history and store, as the react-router-redux reducer
// is under the non-default key ("routing"), selectLocationState
// must be provided for resolving how to retrieve the "route" in the state
import { selectLocationState } from 'containers/App/selectors';
const history = syncHistoryWithStore(browserHistory, store, {
  selectLocationState: selectLocationState(),
});

// Set up the router, wrapping all Routes in the App component
import App from 'containers/App';
import createRoutes from './routes';
const rootRoute = {
  component: App,
  childRoutes: createRoutes(store),
};

const render = (translatedMessages) => {
  ReactDOM.render(
    <Provider store={store}>
      <Router
        history={history}
        routes={rootRoute}
        render={
          // Scroll to top when going to a new page, imitating default browser
          // behaviour
          applyRouterMiddleware(useScroll())
        }
      />
    </Provider>,
    document.getElementById('app')
  );
};

// Hot reloadable translation json files
if (module.hot) {
  // modules.hot.accept does not accept dynamic dependencies,
  // have to be constants at compile-time
  module.hot.accept('./i18n', () => {
    render(translationMessages);
  });
}

// Chunked polyfill for browsers without Intl support
if (!window.Intl) {
  (new Promise((resolve) => {
    resolve(System.import('intl'));
  }))
    .then(() => Promise.all([
      System.import('intl/locale-data/jsonp/en.js'),
      System.import('intl/locale-data/jsonp/de.js'),
    ]))
    .then(() => render(translationMessages))
    .catch((err) => {
      throw err;
    });
} else {
  render(translationMessages);
}

// Install ServiceWorker and AppCache in the end since
// it's not most important operation and if main code fails,
// we do not want it installed
import { install } from 'offline-plugin/runtime';
install();
<commit_msg>Small fix<commit_after>/**
 * app.js
 *
 * This is the entry file for the application, only setup and boilerplate
 * code.
 */

// Needed for redux-saga es6 generator support
import 'babel-polyfill';

/* eslint-disable import/no-unresolved */
// Load the favicon, the manifest.json file and the .htaccess file
import 'file?name=[name].[ext]!./favicon.ico';
import '!file?name=[name].[ext]!./manifest.json';
import 'file?name=[name].[ext]!./.htaccess';
/* eslint-enable import/no-unresolved */

// Import all the third party stuff
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { applyRouterMiddleware, Router, browserHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
import FontFaceObserver from 'fontfaceobserver';
import useScroll from 'react-router-scroll';
import configureStore from './store';

// Observe loading of Open Sans (to remove open sans, remove the <link> tag in
// the index.html file and this observer)
import styles from 'containers/App/styles.css';
const openSansObserver = new FontFaceObserver('Open Sans', {});

// When Open Sans is loaded, add a font-family using Open Sans to the body
openSansObserver.load().then(() => {
  document.body.classList.add(styles.fontLoaded);
}, () => {
  document.body.classList.remove(styles.fontLoaded);
});

// Import i18n messages
import { translationMessages } from './i18n';

// Create redux store with history
// this uses the singleton browserHistory provided by react-router
// Optionally, this could be changed to leverage a created history
// e.g. `const browserHistory = useRouterHistory(createBrowserHistory)();`
const initialState = {};
const store = configureStore(initialState, browserHistory);

// If you use Redux devTools extension, since v2.0.1, they added an
// `updateStore`, so any enhancers that change the store object
// could be used with the devTools' store.
// As this boilerplate uses Redux & Redux-Saga, the `updateStore` is needed
// if you want to `take` actions in your Sagas, dispatched from devTools.
if (window.devToolsExtension) {
  window.devToolsExtension.updateStore(store);
}

// Sync history and store, as the react-router-redux reducer
// is under the non-default key ("routing"), selectLocationState
// must be provided for resolving how to retrieve the "route" in the state
import { selectLocationState } from 'containers/App/selectors';
const history = syncHistoryWithStore(browserHistory, store, {
  selectLocationState: selectLocationState(),
});

// Set up the router, wrapping all Routes in the App component
import App from 'containers/App';
import createRoutes from './routes';
const rootRoute = {
  component: App,
  childRoutes: createRoutes(store),
};

const render = () => {
  ReactDOM.render(
    <Provider store={store}>
      <Router
        history={history}
        routes={rootRoute}
        render={
          // Scroll to top when going to a new page, imitating default browser
          // behaviour
          applyRouterMiddleware(useScroll())
        }
      />
    </Provider>,
    document.getElementById('app')
  );
};

// Hot reloadable translation json files
if (module.hot) {
  // modules.hot.accept does not accept dynamic dependencies,
  // have to be constants at compile-time
  module.hot.accept('./i18n', () => {
    render(translationMessages);
  });
}

// Chunked polyfill for browsers without Intl support
if (!window.Intl) {
  (new Promise((resolve) => {
    resolve(System.import('intl'));
  }))
    .then(() => Promise.all([
      System.import('intl/locale-data/jsonp/en.js'),
      System.import('intl/locale-data/jsonp/de.js'),
    ]))
    .then(() => render(translationMessages))
    .catch((err) => {
      throw err;
    });
} else {
  render(translationMessages);
}

// Install ServiceWorker and AppCache in the end since
// it's not most important operation and if main code fails,
// we do not want it installed
import { install } from 'offline-plugin/runtime';
install();
<|endoftext|>


<commit_before>/*
 * grunt-deps-ok
 * https://github.com/bahmutov/grunt-deps-ok
 *
 * Copyright (c) 2013 Gleb Bahmutov
 * Licensed under the MIT license.
 */

'use strict';

var taskName = 'deps-ok';
var taskDescription = 'Quickly checks if top level dependencies' +
  ' are missing or out of date';
var depsOk = require('deps-ok');

function isVerbose(option) {
  return option === '--verbose' || option === '-v';
}

function isForce(option) {
  return option === '--force' || option === '-f';
}

module.exports = function(grunt) {

  function checkDeps(opts) {
    opts = opts || {};
    var verbose = opts.verbose || false;
    var force = opts.force || false;
    var folder = opts.folder || process.cwd();

    var ok = depsOk(folder, verbose);

    if (ok) {
      grunt.log.writeln('dependencies are ok');
      return true;
    }

    grunt.log.error('problem with dependencies, probably run `npm install`');
    if (opts.force) {
      return true;
    }
    return false;
  }

  if (grunt.config.data[taskName]) {
    grunt.registerMultiTask(taskName, taskDescription, function configuredCheckDeps() {
      grunt.verbose.writeln('deps-ok multi task mode');
      var options = this.options({
        verbose: false,
        force: false,
        folder: process.cwd()
      });
      return checkDeps(options);
    });
  } else {
    grunt.registerTask(taskName, taskDescription, function depsOk() {
      grunt.verbose.writeln('deps-ok default task');
      // get arguments from command line manually
      var verbose = process.argv.some(isVerbose);
      var force = process.argv.some(isForce);
      checkDeps({
        verbose: verbose,
        force: force
      });
    });
  }
};
<commit_msg>[FIX] Return the result check in case of non multi task as well<commit_after>/*
 * grunt-deps-ok
 * https://github.com/bahmutov/grunt-deps-ok
 *
 * Copyright (c) 2013 Gleb Bahmutov
 * Licensed under the MIT license.
 */

'use strict';

var taskName = 'deps-ok';
var taskDescription = 'Quickly checks if top level dependencies' +
  ' are missing or out of date';
var depsOk = require('deps-ok');

function isVerbose(option) {
  return option === '--verbose' || option === '-v';
}

function isForce(option) {
  return option === '--force' || option === '-f';
}

module.exports = function(grunt) {

  function checkDeps(opts) {
    opts = opts || {};
    var verbose = opts.verbose || false;
    var force = opts.force || false;
    var folder = opts.folder || process.cwd();

    var ok = depsOk(folder, verbose);

    if (ok) {
      grunt.log.writeln('dependencies are ok');
      return true;
    }

    grunt.log.error('problem with dependencies, probably run `npm install`');
    if (opts.force) {
      return true;
    }
    return false;
  }

  if (grunt.config.data[taskName]) {
    grunt.registerMultiTask(taskName, taskDescription, function configuredCheckDeps() {
      grunt.verbose.writeln('deps-ok multi task mode');
      var options = this.options({
        verbose: false,
        force: false,
        folder: process.cwd()
      });
      return checkDeps(options);
    });
  } else {
    grunt.registerTask(taskName, taskDescription, function depsOk() {
      grunt.verbose.writeln('deps-ok default task');
      // get arguments from command line manually
      var verbose = process.argv.some(isVerbose);
      var force = process.argv.some(isForce);
      return checkDeps({
        verbose: verbose,
        force: force
      });
    });
  }
};
<|endoftext|>


<commit_before>
var errorSound = "http://www.soundjay.com/button/sounds/button-10.mp3";
var startSound = "http://www.soundjay.com/misc/bell-ringing-05.mp3";
var victoryCount = 3;
var victorySeq = [0, 1, 2, 3, 0, 1, 2, 3];

// n: number, z: 0
function pad(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}

function isPrefix(a, b) {
    var p = b.slice(0, a.length);
    var isSame = (a.length == p.length) && a.every(function(element, index) {
        return element === p[index];
    });
    return isSame;
}

function genSeq(len, min, max) {
    var seq = [];
    for (var i = 0; i < len; i++) {
        seq.push(Math.floor(Math.random() * max));
    }
    return seq;
}

function sleepPromise(ms) {
    return new Promise(function(resolve) {
        setTimeout(resolve, ms);
    });
}

function playSoundPromise(url) {
    return new Promise(function(resolve, reject) { // return a promise
        var audio = new Audio();                     // create audio wo/ src
        audio.preload = "auto";                      // intend to play through
        audio.autoplay = true;                       // autoplay when loaded
        audio.onerror = reject;                      // on error, reject
        audio.onended = resolve;                     // when done, resolve

        audio.src = url
    });
}

var quad = Vue.extend({
    template: '

',
    props: ['qid', 'soundUrl'],
    data: function() {
        var p = document.createElement('audio');
        p.src = this.soundUrl;
        return {
            lightened: false,
            player: p
        }
    },
    methods: {
        play: function() {
            if (this.$parent.isOn) {
                this.lighten();
                this.$parent.playedSeq.push(this.qid);
                // check array contains
                console.log(this.$parent.playedSeq);
                if (isPrefix(this.$parent.playedSeq, this.$parent.showedSeq)) {
                    if (this.$parent.playedSeq.length === this.$parent.showedSeq.length) {
                        var parent = this.$parent;
                        if (parent.count === victoryCount) {
                            parent.generatedSeq = victorySeq;
                            parent.blink = true;
                            parent.latency = 500;
                            setTimeout(function() {
                                parent.$options.methods.showSeq.apply(parent);
                            }, 500);
                            setTimeout(function() {
                                parent.$options.methods.start.apply(parent);
                            }, 8000);
                        } else {
                            setTimeout(function() {
                                parent.$options.methods.nextSeq.apply(parent);
                            }, 2000);
                        }
                    }
                } else {
                    console.log("Error!");
                    var parent = this.$parent;
                    parent.blink = true;
                    parent.playedSeq = [];
                    parent.showedSeq = [];
                    parent.countDisplay = '!!';
                    sleepPromise(300)
                        .then(playSoundPromise.bind(null, errorSound))
                        .then(sleepPromise.bind(null, 2000))
                        .then(function(){
                            parent.blink = false;
                            if (parent.isStrict) {
                                parent.$options.methods.start.apply(parent);
                            } else {
                                parent.$options.methods.showSeq.apply(parent);
                            }
                        });
                }
            }
        },
        lighten: function() {
            this.lightened = true
            this.$parent.countDisplay = pad(this.$parent.count, 2);
            this.player.play();
            this.player.onended = this.darken;
        },
        darken: function() {
            this.lightened = false
        }
    }
});

var main = new Vue({
    el: '#main',
    data: {
        'isStrict': false,
        'isOn': false,
        'count': 0,
        'latency': 500,
        'countDisplay': '--',
        'blink': false,
        'showedSeq': [],
        'playedSeq': [],
        'generatedSeq': []
    },
    components: {
        'quad': quad
    },
    methods: {
        showSeq: function() {
            console.log("showSeq");
            var seq = this.generatedSeq;
            var quad = this.$children;
            var showedSeq = this.showedSeq;
            var latency = this.latency;
            for (var i = 0; i < seq.length; i++) {
                (function(ind, child) {
                    setTimeout(function(){
                        child.lighten();
                        showedSeq.push(child.qid);
                    }, latency * ind);
                })(i, quad[seq[i]]);
            }
        },
        nextSeq: function() {
            console.log("nextSeq");
            if (this.isOn) {
                this.count ++;
                this.countDisplay = pad(this.count, 2);
                this.showedSeq = [];
                this.playedSeq = [];
                this.generatedSeq = genSeq(this.count, 0, this.$children.length);
                this.showSeq();
                console.log(this.showedSeq);
            }
        },
        toggleStrict: function() {
            if (this.isOn) {
                this.isStrict = !this.isStrict;
            }
        },
        reset: function() {
            if (this.isOn) {
                this.count = 0;
                this.countDisplay = '--';
                this.showedSeq = [];
                this.playedSeq = [];
                this.generatedSeq = [];
                this.blink = false;
                this.latency = 1000;
            }
        },
        start: function() {
            if (this.isOn) {
                this.reset();
                playSoundPromise(startSound).then(this.nextSeq);
            }
        },
        toggleOn: function() {
            this.reset();
            this.isStrict = false;
            this.isOn = !this.isOn;
        }
    }
});
<commit_msg>Remove comments<commit_after>
var errorSound = "http://www.soundjay.com/button/sounds/button-10.mp3";
var startSound = "http://www.soundjay.com/misc/bell-ringing-05.mp3";
var victoryCount = 3;
var victorySeq = [0, 1, 2, 3, 0, 1, 2, 3];

// n: number, z: 0
function pad(n, width, z) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}

function isPrefix(a, b) {
    var p = b.slice(0, a.length);
    var isSame = (a.length == p.length) && a.every(function(element, index) {
        return element === p[index];
    });
    return isSame;
}

function genSeq(len, min, max) {
    var seq = [];
    for (var i = 0; i < len; i++) {
        seq.push(Math.floor(Math.random() * max));
    }
    return seq;
}

function sleepPromise(ms) {
    return new Promise(function(resolve) {
        setTimeout(resolve, ms);
    });
}

function playSoundPromise(url) {
    return new Promise(function(resolve, reject) {
        var audio = new Audio();
        audio.preload = "auto";
        audio.autoplay = true;
        audio.onerror = reject;
        audio.onended = resolve;

        audio.src = url
    });
}

var quad = Vue.extend({
    template: '

',
    props: ['qid', 'soundUrl'],
    data: function() {
        var p = document.createElement('audio');
        p.src = this.soundUrl;
        return {
            lightened: false,
            player: p
        }
    },
    methods: {
        play: function() {
            if (this.$parent.isOn) {
                this.lighten();
                this.$parent.playedSeq.push(this.qid);
                // check array contains
                console.log(this.$parent.playedSeq);
                if (isPrefix(this.$parent.playedSeq, this.$parent.showedSeq)) {
                    if (this.$parent.playedSeq.length === this.$parent.showedSeq.length) {
                        var parent = this.$parent;
                        if (parent.count === victoryCount) {
                            parent.generatedSeq = victorySeq;
                            parent.blink = true;
                            parent.latency = 500;
                            setTimeout(function() {
                                parent.$options.methods.showSeq.apply(parent);
                            }, 500);
                            setTimeout(function() {
                                parent.$options.methods.start.apply(parent);
                            }, 8000);
                        } else {
                            setTimeout(function() {
                                parent.$options.methods.nextSeq.apply(parent);
                            }, 2000);
                        }
                    }
                } else {
                    console.log("Error!");
                    var parent = this.$parent;
                    parent.blink = true;
                    parent.playedSeq = [];
                    parent.showedSeq = [];
                    parent.countDisplay = '!!';
                    sleepPromise(300)
                        .then(playSoundPromise.bind(null, errorSound))
                        .then(sleepPromise.bind(null, 2000))
                        .then(function(){
                            parent.blink = false;
                            if (parent.isStrict) {
                                parent.$options.methods.start.apply(parent);
                            } else {
                                parent.$options.methods.showSeq.apply(parent);
                            }
                        });
                }
            }
        },
        lighten: function() {
            this.lightened = true
            this.$parent.countDisplay = pad(this.$parent.count, 2);
            this.player.play();
            this.player.onended = this.darken;
        },
        darken: function() {
            this.lightened = false
        }
    }
});

var main = new Vue({
    el: '#main',
    data: {
        'isStrict': false,
        'isOn': false,
        'count': 0,
        'latency': 500,
        'countDisplay': '--',
        'blink': false,
        'showedSeq': [],
        'playedSeq': [],
        'generatedSeq': []
    },
    components: {
        'quad': quad
    },
    methods: {
        showSeq: function() {
            console.log("showSeq");
            var seq = this.generatedSeq;
            var quad = this.$children;
            var showedSeq = this.showedSeq;
            var latency = this.latency;
            for (var i = 0; i < seq.length; i++) {
                (function(ind, child) {
                    setTimeout(function(){
                        child.lighten();
                        showedSeq.push(child.qid);
                    }, latency * ind);
                })(i, quad[seq[i]]);
            }
        },
        nextSeq: function() {
            console.log("nextSeq");
            if (this.isOn) {
                this.count ++;
                this.countDisplay = pad(this.count, 2);
                this.showedSeq = [];
                this.playedSeq = [];
                this.generatedSeq = genSeq(this.count, 0, this.$children.length);
                this.showSeq();
                console.log(this.showedSeq);
            }
        },
        toggleStrict: function() {
            if (this.isOn) {
                this.isStrict = !this.isStrict;
            }
        },
        reset: function() {
            if (this.isOn) {
                this.count = 0;
                this.countDisplay = '--';
                this.showedSeq = [];
                this.playedSeq = [];
                this.generatedSeq = [];
                this.blink = false;
                this.latency = 1000;
            }
        },
        start: function() {
            if (this.isOn) {
                this.reset();
                playSoundPromise(startSound).then(this.nextSeq);
            }
        },
        toggleOn: function() {
            this.reset();
            this.isStrict = false;
            this.isOn = !this.isOn;
        }
    }
});
<|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 folderName = sanitizeFolderName(url);

      var page = {
        url : url,
        timingsHistory : [],
        gruntPhantomasReport : folderName + '/index.html'
      };

      var pageDataFolder = dataRoot + '/' + folderName + '/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);

          // Avoid problems with the old json file format of grunt-phantomas (before v0.7.0) by ignoring them
          if (json.metrics) {

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

            // Get history for each
            page.timingsHistory.push({
              'timestamp': timestamp,
              'timeToFirstByte': json.metrics.timeToFirstByte.average,
              'onDOMReadyTime': json.metrics.onDOMReadyTime.average,
              'windowOnLoadTime': json.metrics.windowOnLoadTime.average,
              'httpTrafficCompleted': json.metrics.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));
    var indexPath = dataRoot + '/index.html';
    grunt.file.write(indexPath, indexHtml);

    // Open the index.html file in browser (option)
    if (options.openResults) {
      require('grunt-open/tasks/open')(grunt);

      // Inject the config into devperfAfter task
      grunt.config.set('open.devperf_auto_task', {path: indexPath});
      grunt.task.run('open:devperf_auto_task');
    }
  });

  // 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 : "requests",
          limit : 200,
          message: "Too many requests, i guess your site is slow, isn't it?"
        },
        {
          variable : "cssCount",
          limit : 6,
          message: "Too many CSS files, use concatenation"
        },
        {
          variable : "jsCount",
          limit : 12,
          message: "Too many JS files, use concatenation"
        },
        {
          variable : "imageCount",
          limit : 30,
          message: "Too many images, use lazyloading"
        },
        {
          variable : "webfontCount",
          limit : 4,
          message: "Too many custom fonts, tell the designer you don't want that"
        },
        {
          variable : "notFound",
          limit : 1,
          message: "404 errors number"
        },
        {
          variable : "smallImages",
          limit : 20,
          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,
      openResults: false
    });

    // 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>#3 Add warning when images size is too high<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 folderName = sanitizeFolderName(url);

      var page = {
        url : url,
        timingsHistory : [],
        gruntPhantomasReport : folderName + '/index.html'
      };

      var pageDataFolder = dataRoot + '/' + folderName + '/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);

          // Avoid problems with the old json file format of grunt-phantomas (before v0.7.0) by ignoring them
          if (json.metrics) {

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

            // Get history for each
            page.timingsHistory.push({
              'timestamp': timestamp,
              'timeToFirstByte': json.metrics.timeToFirstByte.average,
              'onDOMReadyTime': json.metrics.onDOMReadyTime.average,
              'windowOnLoadTime': json.metrics.windowOnLoadTime.average,
              'httpTrafficCompleted': json.metrics.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));
    var indexPath = dataRoot + '/index.html';
    grunt.file.write(indexPath, indexHtml);

    // Open the index.html file in browser (option)
    if (options.openResults) {
      require('grunt-open/tasks/open')(grunt);

      // Inject the config into devperfAfter task
      grunt.config.set('open.devperf_auto_task', {path: indexPath});
      grunt.task.run('open:devperf_auto_task');
    }
  });

  // 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 : "requests",
          limit : 200,
          message: "Too many requests, i guess your site is slow, isn't it?"
        },
        {
          variable : "cssCount",
          limit : 6,
          message: "Too many CSS files, use concatenation"
        },
        {
          variable : "jsCount",
          limit : 12,
          message: "Too many JS files, use concatenation"
        },
        {
          variable : "imageCount",
          limit : 30,
          message: "Too many images, use lazyloading"
        },
        {
          variable : "imageSize",
          limit : 512000,
          message: "Total image size (bytes)"
        },
        {
          variable : "webfontCount",
          limit : 4,
          message: "Too many custom fonts, tell the designer you don't want that"
        },
        {
          variable : "notFound",
          limit : 1,
          message: "404 errors number"
        },
        {
          variable : "smallImages",
          limit : 20,
          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,
      openResults: false
    });

    // 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>/*
 * grunt-contrib-htmlmin
 * http://gruntjs.com/
 *
 * Copyright (c) 2014 Sindre Sorhus, contributors
 * Licensed under the MIT license.
 */

'use strict';
var chalk = require('chalk');
var prettyBytes = require('pretty-bytes');
var minify = require('html-minifier').minify;

module.exports = function (grunt) {
  grunt.registerMultiTask('htmlmin', 'Minify HTML', function () {
    var options = this.options();

    this.files.forEach(function (file) {
      var min;
      var src = file.src[0];

      if (!grunt.file.exists(src || ' ')) {
        return grunt.log.warn('Source file "' + chalk.cyan(src) + '" not found.');
      }

      var max = grunt.file.read(src);

      if (max.length === 0) {
        return grunt.log.warn('Destination not written because source file was empty.');
      }

      try {
        min = minify(max, options);
      } catch (err) {
        return grunt.warn(file.src + '\n' + err);
      }

      if (min.length === 0) {
        return grunt.log.warn('Destination not written because minified HTML was empty.');
      }

      grunt.file.write(file.dest, min);
      grunt.log.writeln('Minified ' + chalk.cyan(file.dest) + ' ' + prettyBytes(max.length) + ' → ' + prettyBytes(min.length));
    });
  });
};
<commit_msg>Add input file name on error<commit_after>/*
 * grunt-contrib-htmlmin
 * http://gruntjs.com/
 *
 * Copyright (c) 2014 Sindre Sorhus, contributors
 * Licensed under the MIT license.
 */

'use strict';
var chalk = require('chalk');
var prettyBytes = require('pretty-bytes');
var minify = require('html-minifier').minify;

module.exports = function (grunt) {
  grunt.registerMultiTask('htmlmin', 'Minify HTML', function () {
    var options = this.options();

    this.files.forEach(function (file) {
      var min;
      var src = file.src[0];

      if (!grunt.file.exists(src || ' ')) {
        return grunt.log.warn('Source file "' + chalk.cyan(src) + '" not found.');
      }

      var max = grunt.file.read(src);

      if (max.length === 0) {
        return grunt.log.warn('Destination ' + chalk.cyan(src) + ' not written because source file was empty.');
      }

      try {
        min = minify(max, options);
      } catch (err) {
        return grunt.warn(file.src + '\n' + err);
      }

      if (min.length === 0) {
        return grunt.log.warn('Destination ' + chalk.cyan(src) + ' not written because there was nothing to minify.');
      }

      grunt.file.write(file.dest, min);
      grunt.log.writeln('Minified ' + chalk.cyan(file.dest) + ' ' + prettyBytes(max.length) + ' → ' + prettyBytes(min.length));
    });
  });
};
<|endoftext|>


<commit_before>import STATUS from '../../src/constants';
import faker from 'faker';
import thunk from 'redux-thunk';
import configureMockStore from 'redux-mock-store';

/**
 * Generate a redux store
 * @param {Object} reducers
 * @returns {Object} store
 */
export function mockStore(reducers) {
  const middleware = [thunk];
  const mockStore = configureMockStore(middleware);
  return mockStore(reducers);
}

/**
 * Generate notifications
 * @param {Number} numb number of notifications generated
 * @param {Object} notification a notification base
 * @returns {Array}
 */
export function genNotifications(numb, notification = {}) {
  let notifications = [];
  for (let i = 0; i < numb; i++) {
    notifications.push(genNotification(notification));
  }
  return notifications;
}

/**
 * Generate a notification
 * @param {Object} notification a notification base
 * @returns {Object} notification
 */
export function genNotification(notification = {}) {
  const numb = faker.random.number();
  return Object.assign({}, {
    id: faker.random.number(),
    title: faker.lorem.sentence(),
    message: faker.lorem.sentence(),
    status: faker.random.objectElement(STATUS),
    dismissible: faker.random.boolean(),
    dismissAfter: faker.random.number(),
    actions: [{
      name: faker.lorem.words(),
      onClick: () => {
        return numb * 2;
      }
    }, {
      name: faker.lorem.words(),
      onClick: () => {
        return numb * 3;
      }
    }],
    onAdd: () => {
      return numb;
    },
    onRemove: () => {
      return numb * 2;
    }
  }, notification);
}
<commit_msg>update fixtures<commit_after>import STATUS from '../../src/constants';
import faker from 'faker';
import thunk from 'redux-thunk';
import configureMockStore from 'redux-mock-store';

/**
 * Generate a redux store
 * @param {Object} reducers
 * @returns {Object} store
 */
export function mockStore(reducers) {
  const middleware = [thunk];
  const mockStore = configureMockStore(middleware);
  return mockStore(reducers);
}

/**
 * Generate notifications
 * @param {Number} numb number of notifications generated
 * @param {Object} notification a notification base
 * @returns {Array}
 */
export function genNotifications(numb, notification = {}) {
  let notifications = [];
  for (let i = 0; i < numb; i++) {
    notifications.push(genNotification(notification));
  }
  return notifications;
}

/**
 * Generate a notification
 * @param {Object} notification a notification base
 * @returns {Object} notification
 */
export function genNotification(notification = {}) {
  const numb = faker.random.number();
  return Object.assign({}, {
    id: faker.random.number(),
    title: faker.lorem.sentence(),
    message: faker.lorem.sentence(),
    status: faker.random.objectElement(STATUS),
    dismissible: faker.random.boolean(),
    dismissAfter: faker.random.number(),
    actions: [{
      name: faker.lorem.words(),
      primary: faker.random.boolean(),
      onClick: () => {
        return numb * 2;
      }
    }, {
      name: faker.lorem.words(),
      primary: faker.random.boolean(),
      onClick: () => {
        return numb * 3;
      }
    }],
    onAdd: () => {
      return numb;
    },
    onRemove: () => {
      return numb * 2;
    }
  }, notification);
}
<|endoftext|>


<commit_before>'use strict';

// Declare app level module which depends on views, and components
angular.module('casusMIT3', [
  'ngRoute',
  'casusMIT3.index',
  'casusMIT3.results',
    'ui.bootstrap',
    'AdalAngular'
]).
config(['$routeProvider', '$httpProvider', 'adalAuthenticationServiceProvider', '$sceDelegateProvider', function($routeProvider, $httpProvider, adalAuthenticationServiceProvider, $sceDelegateProvider) {

       $routeProvider.otherwise({
           redirectTo: '/index'
           });

    adalAuthenticationServiceProvider.init(
        {
            tenant: 'vwoudenberg.onmicrosoft.com/',
            clientId: '39596d89-8c4a-49ad-b299-69dbc7a7cd28',

        },
        $httpProvider
    );

}]);
<commit_msg>Added Power BI Data factory<commit_after>'use strict';

// Declare app level module which depends on views, and components
angular.module('casusMIT3', [
  'ngRoute',
  'casusMIT3.index',
  'casusMIT3.results',
    'ui.bootstrap',
    'AdalAngular'
]).
config(['$routeProvider', '$httpProvider', 'adalAuthenticationServiceProvider', '$sceDelegateProvider', function($routeProvider, $httpProvider, adalAuthenticationServiceProvider, $sceDelegateProvider) {

       $routeProvider.otherwise({
           redirectTo: '/index'
           });

    adalAuthenticationServiceProvider.init(
        {
            tenant: 'vwoudenberg.onmicrosoft.com/',
            clientId: '39596d89-8c4a-49ad-b299-69dbc7a7cd28',
            endpoints: {
                'https://api.powerbi.com':'https://analysis.windows.net/powerbi/app'
            }

        },
        $httpProvider
    );

}]);
<|endoftext|>