<commit_before>require('proof')(20, prove)

function prove (assert) {
    var Legislator = require('../../legislator'),
        signal = require('signal')

    signal.subscribe('.bigeasy.paxos.invoke'.split('.'), function (id, method, vargs) {
         if (id == '0') {
            // console.log(JSON.stringify({ method: method, vargs: vargs }))
        }
    })

    function dump (legislator) {
        legislator.log.each(function (entry) { console.log(entry) })
    }

    var time = 0

    var options = { parliamentSize: 5, ping: 1, timeout: 3 }

    assert(! new Legislator(time, '0').checkSchedule(time), 'empty schedule')
    var legislators = [ new Legislator(time, '0', options) ]
    legislators[0].bootstrap(time, '0')

    function receive (legislator, outbox, failures) {
        failures || (failures = {})
        if (outbox.length == 0) {
            return false
        }
        var send = outbox.shift(), responses = {}
        send.route.forEach(function (id) {
            var legislator = legislators[id]
            if (failures[id] != 'request' && failures[id] != 'isolate') {
                responses[id] = legislator.receive(time, send, send.messages)
            }
            if (failures[id] == 'response') {
                delete responses[id]
            }
        })
        legislator.sent(time, send, responses)
        return true
    }

    function send (legislator, failures) {
        failures || (failures = {})
        var sent = false
        var outbox = legislator.synchronize(time)
        if (outbox.length == 0) {
            var consensus = legislator.consensus(time)
            if (consensus) {
                outbox = [ consensus ]
            }
        }
        while (receive(legislator, outbox, failures)) {
            sent = true
        }
        return sent
    }

    function tick (failures) {
        failures || (failures = {})
        var ticked = true
        while (ticked) {
            ticked = false
            legislators.forEach(function (legislator) {
                if (failures[legislator.id] != 'isolate') {
                    while (send(legislator, failures)) {
                        ticked = true
                    }
                }
            })
        }
    }

    tick()

    assert(legislators[0].government, {
        majority: [ '0' ],
        minority: [],
        constituents: [],
        promise: '1/0'
    }, 'bootstrap')

    legislators.push(new Legislator(time, '1', options))

    assert(legislators[0].naturalize(time, '1', legislators[1].cookie, '1').posted, 'naturalize')

    tick({ 1: 'request' })

    time++

    assert(legislators[0].checkSchedule(time), 'ping missed')

    tick({ 1: 'request' })

    time++

    legislators[0].checkSchedule(time)

    tick()

    assert(legislators[0].government, {
        majority: [ '0' ],
        minority: [],
        naturalize: { id: '1', location: '1', cookie: 0 },
        constituents: [ '1' ],
        promise: '2/0'
    }, 'leader and constituent pair')

    assert(legislators[1].log.size, 2, 'synchronized')

    legislators.push(new Legislator(time, '2', options))
    legislators[0].post(time, { type: 'enqueue', value: 1 })
    legislators[0].naturalize(time, '2', legislators[2].cookie, '2')

    tick()

    assert(legislators[0].government, {
        majority: [ '0', '1' ],
        minority: [ '2' ],
        constituents: [],
        promise: '4/0'
    }, 'three member parliament')

    assert(legislators[2].log.size, 4, 'synchronized')

    legislators[0]._whenCollapse()
    legislators[1]._whenCollapse()

    assert(legislators[1].post(time, {}).leader, '0', 'post not leader')
    assert(!legislators[0].post(time, {}).posted, 'post collapsed')

    tick()

    assert(legislators[0].government, {
        majority: [ '0', '1' ],
        minority: [ '2' ],
        constituents: [],
        promise: '5/0'
    }, 'recover from collapse')

    legislators[0]._peers[1].timeout = 1

    legislators[0]._whenPulse(time)

    tick()

    assert(legislators[0]._peers[1].timeout, 0, 'liveness pulse')

    legislators[1]._whenPing(time, { id: '2' })

    assert(legislators[1]._peers[2].timeout, 1, 'liveness ping timeout set')

    tick()

    assert(legislators[1]._peers[2].timeout, 0, 'liveness ping resolved')

    delete legislators[1]._peers[2]

    legislators[1]._whenPing(time, { id: '2' })

    tick()

    assert(legislators[1]._peers[2].timeout, 0, 'liveness ping materialized')

    legislators.push(new Legislator(time, '3', options))
    legislators[0].naturalize(time, '3', legislators[3].cookie, '3')
    legislators.push(new Legislator(time, '4', options))
    legislators[0].naturalize(time, '4', legislators[4].cookie, '4')
    legislators[0].post(time, { type: 'enqueue', value: 2 })

    while (send(legislators[0]));

    assert(legislators[3].log.size, 1, 'log before naturalization')

    tick()

    assert(legislators[3].log.size, 4, 'log after naturalization')

    legislators[0].post(time, { type: 'enqueue', value: 2 })
    legislators[0].post(time, { type: 'enqueue', value: 3 })

    tick()

    // One more post to propagate the pings to the new memebers back to the
    // leader. TODO Do this by advancing clock to test pings.
    legislators[0].post(time, { type: 'enqueue', value: 3 })

    tick()

    // TODO Always include exiles and naturalization empty and null by default.
    assert(legislators[0].government, {
        majority: [ '0', '1', '2' ],
        minority: [ '3', '4' ],
        constituents: [],
        promise: '8/0'
    }, 'five member parliament')

    legislators[0].post(time, { type: 'enqueue', value: 3 })

    legislators[1].collapse()

    send(legislators[1])

    var consensus = legislators[1].consensus(time)

    tick({ 1: 'isolate' })

    assert(legislators[0].government, {
        majority: [ '0', '2', '3' ],
        minority: [ '1', '4' ],
        constituents: [],
        promise: '9/0'
    }, 'recover from isolation')

    time++
    legislators[2].checkSchedule(time)
    tick()

    receive(legislators[1], [ consensus ])

    // Test inability to create new government because of lack of majority.
    legislators[0].collapse()

    assert(legislators[0].consensus(), null, 'cannot choose leaders')

    tick()

    legislators.push(new Legislator(time, '5', options))
    legislators[0].naturalize(time, '5', legislators[5].cookie, '5')

    tick({ 5: 'isolate' })

    time++

    // Test attmepting to naturalize a restarted legislator.
    legislators[1].checkSchedule(time)
    send(legislators[1])
    legislators[5] = new Legislator(time, '5', options)
    tick()

    legislators[0].collapse()
    send(legislators[0])
    send(legislators[0])
    legislators[2].collapse()
    tick({ 0: 'isolate' })
    tick()
}
<commit_msg>Check schedule each time through the loop.<commit_after>require('proof')(20, prove)

function prove (assert) {
    var Legislator = require('../../legislator'),
        signal = require('signal')

    signal.subscribe('.bigeasy.paxos.invoke'.split('.'), function (id, method, vargs) {
         if (id == '0') {
            // console.log(JSON.stringify({ method: method, vargs: vargs }))
        }
    })

    function dump (legislator) {
        legislator.log.each(function (entry) { console.log(entry) })
    }

    var time = 0

    var options = { parliamentSize: 5, ping: 1, timeout: 3 }

    assert(! new Legislator(time, '0').checkSchedule(time), 'empty schedule')
    var legislators = [ new Legislator(time, '0', options) ]
    legislators[0].bootstrap(time, '0')

    function receive (legislator, outbox, failures) {
        failures || (failures = {})
        if (outbox.length == 0) {
            return false
        }
        var send = outbox.shift(), responses = {}
        send.route.forEach(function (id) {
            var legislator = legislators[id]
            if (failures[id] != 'request' && failures[id] != 'isolate') {
                responses[id] = legislator.receive(time, send, send.messages)
            }
            if (failures[id] == 'response') {
                delete responses[id]
            }
        })
        legislator.sent(time, send, responses)
        return true
    }

    function send (legislator, failures) {
        failures || (failures = {})
        var sent = false
        var outbox = legislator.synchronize(time)
        if (outbox.length == 0) {
            var consensus = legislator.consensus(time)
            if (consensus) {
                outbox = [ consensus ]
            }
        }
        while (receive(legislator, outbox, failures)) {
            sent = true
        }
        return sent
    }

    function tick (failures) {
        failures || (failures = {})
        var ticked = true
        while (ticked) {
            ticked = false
            legislators.forEach(function (legislator) {
                if (failures[legislator.id] != 'isolate') {
                    legislator.checkSchedule(time)
                    while (send(legislator, failures)) {
                        ticked = true
                    }
                }
            })
        }
    }

    tick()

    assert(legislators[0].government, {
        majority: [ '0' ],
        minority: [],
        constituents: [],
        promise: '1/0'
    }, 'bootstrap')

    legislators.push(new Legislator(time, '1', options))

    assert(legislators[0].naturalize(time, '1', legislators[1].cookie, '1').posted, 'naturalize')

    tick({ 1: 'request' })

    time++

    assert(legislators[0].checkSchedule(time), 'ping missed')

    tick({ 1: 'request' })

    time++

    legislators[0].checkSchedule(time)

    tick()

    assert(legislators[0].government, {
        majority: [ '0' ],
        minority: [],
        naturalize: { id: '1', location: '1', cookie: 0 },
        constituents: [ '1' ],
        promise: '2/0'
    }, 'leader and constituent pair')

    assert(legislators[1].log.size, 2, 'synchronized')

    legislators.push(new Legislator(time, '2', options))
    legislators[0].post(time, { type: 'enqueue', value: 1 })
    legislators[0].naturalize(time, '2', legislators[2].cookie, '2')

    tick()

    assert(legislators[0].government, {
        majority: [ '0', '1' ],
        minority: [ '2' ],
        constituents: [],
        promise: '4/0'
    }, 'three member parliament')

    assert(legislators[2].log.size, 4, 'synchronized')

    legislators[0]._whenCollapse()
    legislators[1]._whenCollapse()

    assert(legislators[1].post(time, {}).leader, '0', 'post not leader')
    assert(!legislators[0].post(time, {}).posted, 'post collapsed')

    tick()

    assert(legislators[0].government, {
        majority: [ '0', '1' ],
        minority: [ '2' ],
        constituents: [],
        promise: '5/0'
    }, 'recover from collapse')

    legislators[0]._peers[1].timeout = 1

    legislators[0]._whenPulse(time)

    tick()

    assert(legislators[0]._peers[1].timeout, 0, 'liveness pulse')

    legislators[1]._whenPing(time, { id: '2' })

    assert(legislators[1]._peers[2].timeout, 1, 'liveness ping timeout set')

    tick()

    assert(legislators[1]._peers[2].timeout, 0, 'liveness ping resolved')

    delete legislators[1]._peers[2]

    legislators[1]._whenPing(time, { id: '2' })

    tick()

    assert(legislators[1]._peers[2].timeout, 0, 'liveness ping materialized')

    legislators.push(new Legislator(time, '3', options))
    legislators[0].naturalize(time, '3', legislators[3].cookie, '3')
    legislators.push(new Legislator(time, '4', options))
    legislators[0].naturalize(time, '4', legislators[4].cookie, '4')
    legislators[0].post(time, { type: 'enqueue', value: 2 })

    while (send(legislators[0]));

    assert(legislators[3].log.size, 1, 'log before naturalization')

    tick()

    assert(legislators[3].log.size, 4, 'log after naturalization')

    legislators[0].post(time, { type: 'enqueue', value: 2 })
    legislators[0].post(time, { type: 'enqueue', value: 3 })

    tick()

    // One more post to propagate the pings to the new memebers back to the
    // leader. TODO Do this by advancing clock to test pings.
    legislators[0].post(time, { type: 'enqueue', value: 3 })

    tick()

    // TODO Always include exiles and naturalization empty and null by default.
    assert(legislators[0].government, {
        majority: [ '0', '1', '2' ],
        minority: [ '3', '4' ],
        constituents: [],
        promise: '8/0'
    }, 'five member parliament')

    legislators[0].post(time, { type: 'enqueue', value: 3 })

    legislators[1].collapse()

    send(legislators[1])

    var consensus = legislators[1].consensus(time)

    tick({ 1: 'isolate' })

    assert(legislators[0].government, {
        majority: [ '0', '2', '3' ],
        minority: [ '1', '4' ],
        constituents: [],
        promise: '9/0'
    }, 'recover from isolation')

    time++
    legislators[2].checkSchedule(time)
    tick()

    receive(legislators[1], [ consensus ])

    // Test inability to create new government because of lack of majority.
    legislators[0].collapse()

    assert(legislators[0].consensus(), null, 'cannot choose leaders')

    tick()

    legislators.push(new Legislator(time, '5', options))
    legislators[0].naturalize(time, '5', legislators[5].cookie, '5')

    tick({ 5: 'isolate' })

    time++

    // Test attmepting to naturalize a restarted legislator.
    legislators[1].checkSchedule(time)
    send(legislators[1])
    legislators[5] = new Legislator(time, '5', options)
    tick()

    legislators[0].collapse()
    send(legislators[0])
    send(legislators[0])
    legislators[2].collapse()
    tick({ 0: 'isolate' })
    tick()
}
<|endoftext|>


<commit_before>/*
 * grunt-assets-inline
 * https://github.com/sparanoid/assets-inline
 *
 * Copyright (c) 2017 Tunghsiao Liu
 * Licensed under the MIT license.
 */

/*
 * grunt-html-smoosher
 * https://github.com/motherjones/grunt-html-smoosher
 *
 * Copyright (c) 2013 Ben Breedlove
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {

  'use strict';

  var cheerio = require('cheerio');
  var path = require('path');
  var url = require('url');
  var uglifyjs = require('uglify-js');

  grunt.registerMultiTask('assets_inline', 'Inline external resources into HTML', function() {

    var options = this.options({
      jsDir: "",
      cssDir: "",
      assetsDir: "",
      minify: false,
      inlineImg: false,
      inlineSvg: true,
      inlineSvgBase64: false,
      inlineLinkTags: false,
      includeTag: "",
      assetsUrlPrefix: "",
      verbose: false,
      deleteOriginals: false,
      assetsKeep: "assets-keep",
      assetsDelete: "assets-delete"

    });

    options.cssTags = this.options().cssTags || {
      start: '<style>',
      end: '</style>'
    };

    options.jsTags = this.options().jsTags || {
      start: '<script>',
      end: '</script>'
    };

    var uglifyJS = function (i) { return i; };

    if (options.minify) {
      uglifyJS = function (input) {
        return uglifyjs.minify(input, {fromString: true}).code;
      };
    }

    var processSvg = function (i) { return i; };

    processSvg = function(input){
      // replace double quotes with single quotes and remove line breaks for non-base64 SVG inlining.
      return input.replace(/"/g, "'").replace(/(?:\r\n|\r|\n)/g, "");
    };

    var getAttributes = function (el) {
      var attributes = {};
      for (var index in el.attr) {
        var attr = el.attr[index];
        if (options.verbose) {
          grunt.log.writeln(('   attr: ').blue + index + ":" + attr);
        }
        attributes[ index ] = attr;
      }
      return attributes;
    };

    var filesToDelete = [];

    var checkDelete = function (src) {
      if (src.includes(options.assetsDelete)) {
        return true;
      }

      if (options.deleteOriginals) {
        if (src.includes(options.assetsKeep)) {
          return false;
        } else {
          return true;
        }
      } else {
        return false;
      }
    };

    this.files.forEach(function(filePair) {
      // Check that the source file exists
      if(filePair.src.length === 0) { return; }

      // init cheerio
      var $ = cheerio.load(grunt.file.read(filePair.src), {
        decodeEntities: false
      });

      grunt.log.writeln(('Reading: ').green + path.resolve(filePair.src.toString()));

      // Assets inside inline `<style>` => inline assets
      $('style[data-assets-inline]').each(function () {
        var style = $(this).html();
        if(!style) { return; }

        var items = [];
        // https://regex101.com/r/yP1yK0/1
        var regex = /url\(["']?(.*?)["']?\)/ig;
        var item;

        while (item = regex.exec(style)) {
          items.push(item[1]);
        }

        items.forEach(function(v) {
          var src = v;
          if (!src) { return; }
          if (src.match(/^\/\//)) { return; }
          if (!src.match(/.svg$/i)) { return; }
          if (url.parse(src).protocol) { return; }
          var deleteOriginal = checkDelete(src);

          var filePath = (src.substr(0,1) === '/') ? path.resolve(options.assetsDir, src.substr(1)) : path.join(path.dirname(filePair.src.toString()), src);

          if (options.inlineSvgBase64) {
            style = style.replace(src, 'data:image/svg+xml;base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
          } else {
            style = style.replace(src, 'data:image/svg+xml;utf8,' + processSvg(grunt.file.read(filePath)));
          }

          if (deleteOriginal) {
            grunt.log.writeln((' delete: ').gray + filePath);
            filesToDelete.push(filePath);
          } else {
            grunt.log.writeln(('   keep: ').blue + filePath);
          }
        });

        $(this).text(style);
      });

      // External stylesheets => inline stylesheets
      $('link[rel="stylesheet"]').each(function () {
        var style = $(this).attr('href');
        if(!style) { return; }
        if(style.match(/^\/\//)) { return; }
        if(style.indexOf(options.includeTag) === -1) { return; }
        var deleteOriginal = checkDelete(style);
        style = style.replace(/\?.+$/, "");

        //get attributes to keep them on the new element
        var attributes = getAttributes($(this));
        if (attributes.href){
          //don't want to re-include the href
          delete attributes.href;
        }
        if (attributes.rel){
          //don't want to rel
          delete attributes.rel;
        }

        if(url.parse(style).protocol) { return; }
        var filePath = (style.substr(0,1) === "/") ? path.resolve(options.cssDir, style.substr(1)) : path.join(path.dirname(filePair.src.toString()), style);
        $(this).replaceWith(options.cssTags.start + grunt.file.read(filePath) + options.cssTags.end);

        if (deleteOriginal) {
          grunt.log.writeln((' delete: ').gray + filePath);
          filesToDelete.push(filePath);
        } else {
          grunt.log.writeln(('   keep: ').blue + filePath);
        }
      });

      // Scripts inside `<script>` = inlne scripts
      $('script').each(function () {
        var script = $(this).attr('src');
        if(!script) { return; }
        if(script.match(/^\/\//)) { return; }
        if(script.indexOf(options.includeTag) === -1) { return; }
        if(url.parse(script).protocol) { return; }
        var deleteOriginal = checkDelete(script);
        script = script.replace(/\?.+$/, "");

        //get attributes to keep them on the new element
        var attributes = getAttributes($(this));
        if (attributes.src){
          delete attributes.src;
        }

        var filePath = (script.substr(0,1) === "/") ? path.resolve(options.jsDir, script.substr(1)) : path.join(path.dirname(filePair.src.toString()), script);

        //create and replace script with new scipt tag
        $(this).replaceWith(options.jsTags.start + uglifyJS(grunt.file.read(filePath)) + options.jsTags.end);

        if (deleteOriginal) {
          grunt.log.writeln((' delete: ').gray + filePath);
          filesToDelete.push(filePath);
        } else {
          grunt.log.writeln(('   keep: ').blue + filePath);
        }
      });

      // Assets inside `<link>`, most for favicons
      if (options.inlineLinkTags) {
        $('link').each(function () {
          var src = $(this).attr('href');
          if(!src) { return; }
          if(src.match(/^\/\//)) { return; }
          if(src.indexOf(options.includeTag) === -1) { return; }
          if(url.parse(src).protocol) { return; }
          var deleteOriginal = checkDelete(src);
          src = src.replace(/\?.+$/, '');

          var filePath = (src.substr(0,1) === '/') ? path.resolve(options.assetsDir, src.substr(1)) : path.join(path.dirname(filePair.src.toString()), src);

          if (src.match(/.svg$/i)) {
            if (options.inlineSvgBase64) {
              $(this).attr('href', 'data:image/svg+xml;base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
            } else {
              $(this).attr('href', 'data:image/svg+xml;utf8,' + processSvg(grunt.file.read(filePath)));
            }
          }

          if (src.match(/.ico$/i)) {
            $(this).attr('href', 'data:image/x-icon;base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
          }

          if (src.match(/.(?:png|jpg)$/i)) {
            $(this).attr('href', 'data:image/' + src.substr(src.lastIndexOf('.')+1) + ';base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
          }

          if (deleteOriginal) {
            grunt.log.writeln((' delete: ').gray + filePath);
            filesToDelete.push(filePath);
          } else {
            grunt.log.writeln(('   keep: ').blue + filePath);
          }
        });
      }

      if (options.inlineSvg) {
        $('img').each(function () {
          var src = $(this).attr('src');
          if (!src) { return; }
          if (src.match(/^\/\//)) { return; }
          if (!src.match(/.svg$/i)) { return; }
          if (url.parse(src).protocol) { return; }
          var deleteOriginal = checkDelete(src);

          var filePath = (src.substr(0,1) === "/") ? path.resolve(options.assetsDir, src.substr(1)) : path.join(path.dirname(filePair.src.toString()), src);

          if (options.inlineSvgBase64) {
            $(this).attr('src', 'data:image/svg+xml;base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
          } else {
            $(this).attr('src', 'data:image/svg+xml;utf8,' + processSvg(grunt.file.read(filePath)));
          }

          if (deleteOriginal) {
            grunt.log.writeln((' delete: ').gray + filePath);
            filesToDelete.push(filePath);
          } else {
            grunt.log.writeln(('   keep: ').blue + filePath);
          }
        });
      }

      if (options.inlineImg) {
        $('img').each(function () {
          var src = $(this).attr('src');
          if (!src) { return; }
          if (src.match(/^\/\//)) { return; }
          if (src.match(/.svg$/i)) { return; }
          if (url.parse(src).protocol) { return; }
          var deleteOriginal = checkDelete(src);

          var filePath = (src.substr(0,1) === "/") ? path.resolve(options.assetsDir, src.substr(1)) : path.join(path.dirname(filePair.src.toString()), src);

          $(this).attr('src', 'data:image/' + src.substr(src.lastIndexOf('.')+1) + ';base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));

          if (deleteOriginal) {
            grunt.log.writeln((' delete: ').gray + filePath);
            filesToDelete.push(filePath);
          } else {
            grunt.log.writeln(('   keep: ').blue + filePath);
          }
        });
      }

      var html = $.html();
      // replace relative path
      html = html.replace(/[.]{2}\//g, options.assetsUrlPrefix);
      grunt.file.write(path.resolve(filePair.dest), html);
      grunt.log.writeln(('Created: ').green + path.resolve(filePair.dest) + '\n');
    });

    // Delete the original files
    filesToDelete.forEach(function(filename) {
      if (grunt.file.exists(filename)) {
        grunt.file.delete(filename);
        grunt.log.writeln(('Removed: ').green + filename);
      }
    });
  });
};
<commit_msg>chore: reformat<commit_after>/*
 * grunt-assets-inline
 * https://github.com/sparanoid/assets-inline
 *
 * Copyright (c) 2017 Tunghsiao Liu
 * Licensed under the MIT license.
 */

/*
 * grunt-html-smoosher
 * https://github.com/motherjones/grunt-html-smoosher
 *
 * Copyright (c) 2013 Ben Breedlove
 * Licensed under the MIT license.
 */

module.exports = function(grunt) {

  'use strict';

  var cheerio = require('cheerio');
  var path = require('path');
  var url = require('url');
  var uglifyjs = require('uglify-js');

  grunt.registerMultiTask('assets_inline', 'Inline external resources into HTML', function() {

    var options = this.options({
      jsDir: "",
      cssDir: "",
      assetsDir: "",
      minify: false,
      inlineImg: false,
      inlineSvg: true,
      inlineSvgBase64: false,
      inlineLinkTags: false,
      includeTag: "",
      assetsUrlPrefix: "",
      verbose: false,
      deleteOriginals: false,
      assetsKeep: "assets-keep",
      assetsDelete: "assets-delete"

    });

    options.cssTags = this.options().cssTags || {
      start: '<style>',
      end: '</style>'
    };

    options.jsTags = this.options().jsTags || {
      start: '<script>',
      end: '</script>'
    };

    var uglifyJS = function(i) { return i; };

    if (options.minify) {
      uglifyJS = function(input) {
        return uglifyjs.minify(input, { fromString: true }).code;
      };
    }

    var processSvg = function(i) { return i; };

    processSvg = function(input) {
      // replace double quotes with single quotes and remove line breaks for non-base64 SVG inlining.
      return input.replace(/"/g, "'").replace(/(?:\r\n|\r|\n)/g, "");
    };

    var getAttributes = function(el) {
      var attributes = {};
      for (var index in el.attr) {
        var attr = el.attr[index];
        if (options.verbose) {
          grunt.log.writeln(('   attr: ').blue + index + ":" + attr);
        }
        attributes[index] = attr;
      }
      return attributes;
    };

    var filesToDelete = [];

    var checkDelete = function(src) {
      if (src.includes(options.assetsDelete)) {
        return true;
      }

      if (options.deleteOriginals) {
        if (src.includes(options.assetsKeep)) {
          return false;
        } else {
          return true;
        }
      } else {
        return false;
      }
    };

    this.files.forEach(function(filePair) {
      // Check that the source file exists
      if (filePair.src.length === 0) { return; }

      // init cheerio
      var $ = cheerio.load(grunt.file.read(filePair.src), {
        decodeEntities: false
      });

      grunt.log.writeln(('Reading: ').green + path.resolve(filePair.src.toString()));

      // Assets inside inline `<style>` => inline assets
      $('style[data-assets-inline]').each(function() {
        var style = $(this).html();
        if (!style) { return; }

        var items = [];
        // https://regex101.com/r/yP1yK0/1
        var regex = /url\(["']?(.*?)["']?\)/ig;
        var item;

        while (item = regex.exec(style)) {
          items.push(item[1]);
        }

        items.forEach(function(v) {
          var src = v;
          if (!src) { return; }
          if (src.match(/^\/\//)) { return; }
          if (!src.match(/.svg$/i)) { return; }
          if (url.parse(src).protocol) { return; }
          var deleteOriginal = checkDelete(src);

          var filePath = (src.substr(0, 1) === '/') ? path.resolve(options.assetsDir, src.substr(1)) : path.join(path.dirname(filePair.src.toString()), src);

          if (options.inlineSvgBase64) {
            style = style.replace(src, 'data:image/svg+xml;base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
          } else {
            style = style.replace(src, 'data:image/svg+xml;utf8,' + processSvg(grunt.file.read(filePath)));
          }

          if (deleteOriginal) {
            grunt.log.writeln((' delete: ').gray + filePath);
            filesToDelete.push(filePath);
          } else {
            grunt.log.writeln(('   keep: ').blue + filePath);
          }
        });

        $(this).text(style);
      });

      // External stylesheets => inline stylesheets
      $('link[rel="stylesheet"]').each(function() {
        var style = $(this).attr('href');
        if (!style) { return; }
        if (style.match(/^\/\//)) { return; }
        if (style.indexOf(options.includeTag) === -1) { return; }
        var deleteOriginal = checkDelete(style);
        style = style.replace(/\?.+$/, "");

        //get attributes to keep them on the new element
        var attributes = getAttributes($(this));
        if (attributes.href) {
          //don't want to re-include the href
          delete attributes.href;
        }
        if (attributes.rel) {
          //don't want to rel
          delete attributes.rel;
        }

        if (url.parse(style).protocol) { return; }
        var filePath = (style.substr(0, 1) === "/") ? path.resolve(options.cssDir, style.substr(1)) : path.join(path.dirname(filePair.src.toString()), style);
        $(this).replaceWith(options.cssTags.start + grunt.file.read(filePath) + options.cssTags.end);

        if (deleteOriginal) {
          grunt.log.writeln((' delete: ').gray + filePath);
          filesToDelete.push(filePath);
        } else {
          grunt.log.writeln(('   keep: ').blue + filePath);
        }
      });

      // Scripts inside `<script>` = inlne scripts
      $('script').each(function() {
        var script = $(this).attr('src');
        if (!script) { return; }
        if (script.match(/^\/\//)) { return; }
        if (script.indexOf(options.includeTag) === -1) { return; }
        if (url.parse(script).protocol) { return; }
        var deleteOriginal = checkDelete(script);
        script = script.replace(/\?.+$/, "");

        //get attributes to keep them on the new element
        var attributes = getAttributes($(this));
        if (attributes.src) {
          delete attributes.src;
        }

        var filePath = (script.substr(0, 1) === "/") ? path.resolve(options.jsDir, script.substr(1)) : path.join(path.dirname(filePair.src.toString()), script);

        //create and replace script with new scipt tag
        $(this).replaceWith(options.jsTags.start + uglifyJS(grunt.file.read(filePath)) + options.jsTags.end);

        if (deleteOriginal) {
          grunt.log.writeln((' delete: ').gray + filePath);
          filesToDelete.push(filePath);
        } else {
          grunt.log.writeln(('   keep: ').blue + filePath);
        }
      });

      // Assets inside `<link>`, most for favicons
      if (options.inlineLinkTags) {
        $('link').each(function() {
          var src = $(this).attr('href');
          if (!src) { return; }
          if (src.match(/^\/\//)) { return; }
          if (src.indexOf(options.includeTag) === -1) { return; }
          if (url.parse(src).protocol) { return; }
          var deleteOriginal = checkDelete(src);
          src = src.replace(/\?.+$/, '');

          var filePath = (src.substr(0, 1) === '/') ? path.resolve(options.assetsDir, src.substr(1)) : path.join(path.dirname(filePair.src.toString()), src);

          if (src.match(/.svg$/i)) {
            if (options.inlineSvgBase64) {
              $(this).attr('href', 'data:image/svg+xml;base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
            } else {
              $(this).attr('href', 'data:image/svg+xml;utf8,' + processSvg(grunt.file.read(filePath)));
            }
          }

          if (src.match(/.ico$/i)) {
            $(this).attr('href', 'data:image/x-icon;base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
          }

          if (src.match(/.(?:png|jpg)$/i)) {
            $(this).attr('href', 'data:image/' + src.substr(src.lastIndexOf('.') + 1) + ';base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
          }

          if (deleteOriginal) {
            grunt.log.writeln((' delete: ').gray + filePath);
            filesToDelete.push(filePath);
          } else {
            grunt.log.writeln(('   keep: ').blue + filePath);
          }
        });
      }

      if (options.inlineSvg) {
        $('img').each(function() {
          var src = $(this).attr('src');
          if (!src) { return; }
          if (src.match(/^\/\//)) { return; }
          if (!src.match(/.svg$/i)) { return; }
          if (url.parse(src).protocol) { return; }
          var deleteOriginal = checkDelete(src);

          var filePath = (src.substr(0, 1) === "/") ? path.resolve(options.assetsDir, src.substr(1)) : path.join(path.dirname(filePair.src.toString()), src);

          if (options.inlineSvgBase64) {
            $(this).attr('src', 'data:image/svg+xml;base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));
          } else {
            $(this).attr('src', 'data:image/svg+xml;utf8,' + processSvg(grunt.file.read(filePath)));
          }

          if (deleteOriginal) {
            grunt.log.writeln((' delete: ').gray + filePath);
            filesToDelete.push(filePath);
          } else {
            grunt.log.writeln(('   keep: ').blue + filePath);
          }
        });
      }

      if (options.inlineImg) {
        $('img').each(function() {
          var src = $(this).attr('src');
          if (!src) { return; }
          if (src.match(/^\/\//)) { return; }
          if (src.match(/.svg$/i)) { return; }
          if (url.parse(src).protocol) { return; }
          var deleteOriginal = checkDelete(src);

          var filePath = (src.substr(0, 1) === "/") ? path.resolve(options.assetsDir, src.substr(1)) : path.join(path.dirname(filePair.src.toString()), src);

          $(this).attr('src', 'data:image/' + src.substr(src.lastIndexOf('.') + 1) + ';base64,' + new Buffer(grunt.file.read(filePath, { encoding: null })).toString('base64'));

          if (deleteOriginal) {
            grunt.log.writeln((' delete: ').gray + filePath);
            filesToDelete.push(filePath);
          } else {
            grunt.log.writeln(('   keep: ').blue + filePath);
          }
        });
      }

      var html = $.html();
      // replace relative path
      html = html.replace(/[.]{2}\//g, options.assetsUrlPrefix);
      grunt.file.write(path.resolve(filePair.dest), html);
      grunt.log.writeln(('Created: ').green + path.resolve(filePair.dest) + '\n');
    });

    // Delete the original files
    filesToDelete.forEach(function(filename) {
      if (grunt.file.exists(filename)) {
        grunt.file.delete(filename);
        grunt.log.writeln(('Removed: ').green + filename);
      }
    });
  });
};
<|endoftext|>


<commit_before>/*
 * grunt-hashres
 * https://github.com/luismahou/grunt-hashres
 *
 * Copyright (c) 2013 Luismahou
 * Licensed under the MIT license.
 */

'use strict';

var fs    = require('fs'),
    path  = require('path'),
    utils = require('./hashresUtils');

exports.hashAndSub = function(grunt, options) {

  var src              = options.src,
      dest             = options.dest,
      encoding         = options.encoding,
      fileNameFormat   = options.fileNameFormat,
      renameFiles      = options.renameFiles,
      nameToHashedName = {},
      nameToNameSearch = {},
      formatter        = null,
      searchFormatter  = null,
      requireTpl       = '';

  grunt.log.debug('files: ' + options.files);
  grunt.log.debug('Using encoding ' + encoding);
  grunt.log.debug('Using fileNameFormat ' + fileNameFormat);
  grunt.log.debug(renameFiles ? 'Renaming files' : 'Not renaming files');

  formatter = utils.compileFormat(fileNameFormat);
  searchFormatter = utils.compileSearchFormat(fileNameFormat);

  var _src;
  if (options.files) {
    options.files.forEach(function(f) {
      f.src.forEach(function(src) {
        var md5        = utils.md5(src).slice(0, 8),
            fileName   = path.basename(src),
            lastIndex  = fileName.lastIndexOf('.'),
            renamed    = formatter({
              hash: md5,
              name: fileName.slice(0, lastIndex),
              ext : fileName.slice(lastIndex + 1, fileName.length)
            }),
            nameSearch = searchFormatter({
              hash: /[0-9a-f]{8}/,
              name: fileName.slice(0, lastIndex),
              ext: fileName.slice(lastIndex + 1, fileName.length)
            });

        // Mapping the original name with hashed one for later use.
        nameToHashedName[fileName] = renamed;
        nameToNameSearch[fileName] = nameSearch;

        // Renaming the file
        // if (renameFiles) {
          // fs.renameSync(src, path.resolve(path.dirname(src), renamed));
          // require( 'child_process' ).exec( 'cp ' + src + ' ' + path.resolve(path.dirname(src), renamed));
        var hashedPath = path.resolve(path.dirname(src), renamed);
        grunt.file.copy( src, hashedPath );
        // }
        grunt.log.write(src + ' ').ok(renamed);

        var jsDir = src.substring( 0, src.indexOf( '/js/' ) + 4 );
        var requireDependencyName = src.substring( jsDir.length, src.indexOf( '.' ));
        var requireAssetPath = hashedPath.substring( hashedPath.indexOf( '/assets/' ), hashedPath.length - 3 );
        requireTpl += " '"+requireDependencyName+"': '"+requireAssetPath+"',";
        _src = src;
      });

      var tplDir = 'application/views/3/extra/requirejs/';
      var assetCategory = _src.indexOf( '/3/' ) > -1 ? 'website' : 'cms';

      grunt.file.write( tplDir + 'hashed.'+assetCategory+'.tpl', requireTpl );

      // sort by length
      // It is very useful when we have bar.js and foo-bar.js
      // @crodas
      var files = [];
      for (var name in nameToHashedName) {
        files.push([name, nameToHashedName[name]]);
      }
      files.sort(function(a, b) {
        return b[0].length - a[0].length;
      });

      // Substituting references to the given files with the hashed ones.
      grunt.file.expand(f.dest).forEach(function(f) {
        var destContents = fs.readFileSync(f, encoding);
        files.forEach(function(value) {
          grunt.log.debug('Substituting ' + value[0] + ' by ' + value[1])
          destContents = destContents.replace(new RegExp(utils.preg_quote(value[0])+"(\\?[0-9a-z]+)?", "g"), value[1]);

          grunt.log.debug('Substituting ' + nameToNameSearch[value[0]] + ' by ' + value[1])
          destContents = destContents.replace(
                new RegExp(nameToNameSearch[value[0]], "g"),
                value[1]
            );
        });
        grunt.log.debug('Saving the updated contents of the outination file');
        fs.writeFileSync(f, destContents, encoding);
      });
    });
  }
};
<commit_msg>special chat path<commit_after>/*
 * grunt-hashres
 * https://github.com/luismahou/grunt-hashres
 *
 * Copyright (c) 2013 Luismahou
 * Licensed under the MIT license.
 */

'use strict';

var fs    = require('fs'),
    path  = require('path'),
    utils = require('./hashresUtils');

exports.hashAndSub = function(grunt, options) {

  var src              = options.src,
      dest             = options.dest,
      encoding         = options.encoding,
      fileNameFormat   = options.fileNameFormat,
      renameFiles      = options.renameFiles,
      nameToHashedName = {},
      nameToNameSearch = {},
      formatter        = null,
      searchFormatter  = null,
      requireTpl       = '';

  grunt.log.debug('files: ' + options.files);
  grunt.log.debug('Using encoding ' + encoding);
  grunt.log.debug('Using fileNameFormat ' + fileNameFormat);
  grunt.log.debug(renameFiles ? 'Renaming files' : 'Not renaming files');

  formatter = utils.compileFormat(fileNameFormat);
  searchFormatter = utils.compileSearchFormat(fileNameFormat);

  var _src;
  if (options.files) {
    options.files.forEach(function(f) {
      f.src.forEach(function(src) {
        var md5        = utils.md5(src).slice(0, 8),
            fileName   = path.basename(src),
            lastIndex  = fileName.lastIndexOf('.'),
            renamed    = formatter({
              hash: md5,
              name: fileName.slice(0, lastIndex),
              ext : fileName.slice(lastIndex + 1, fileName.length)
            }),
            nameSearch = searchFormatter({
              hash: /[0-9a-f]{8}/,
              name: fileName.slice(0, lastIndex),
              ext: fileName.slice(lastIndex + 1, fileName.length)
            });

        // Mapping the original name with hashed one for later use.
        nameToHashedName[fileName] = renamed;
        nameToNameSearch[fileName] = nameSearch;

        // Renaming the file
        // if (renameFiles) {
          // fs.renameSync(src, path.resolve(path.dirname(src), renamed));
          // require( 'child_process' ).exec( 'cp ' + src + ' ' + path.resolve(path.dirname(src), renamed));
        var hashedPath = path.resolve(path.dirname(src), renamed);
        grunt.file.copy( src, hashedPath );
        // }
        grunt.log.write(src + ' ').ok(renamed);

        var jsDir = src.substring( 0, src.indexOf( '/js/' ) + 4 );
        var requireDependencyName = src.substring( jsDir.length, src.indexOf( '.' ));
        var requireAssetPath = hashedPath.substring( hashedPath.indexOf( '/assets/' ), hashedPath.length - 3 );
        requireTpl += " '"+requireDependencyName+"': '"+requireAssetPath+"',\n";
        if ( requireDependencyName == 'chat/old' )
          requireTpl += " chat: '"+requireAssetPath+"',\n";
        _src = src;
      });

      var tplDir = 'application/views/3/extra/requirejs/';
      var assetCategory = _src.indexOf( '/3/' ) > -1 ? 'website' : 'cms';

      grunt.file.write( tplDir + 'hashed.'+assetCategory+'.tpl', requireTpl );

      // sort by length
      // It is very useful when we have bar.js and foo-bar.js
      // @crodas
      var files = [];
      for (var name in nameToHashedName) {
        files.push([name, nameToHashedName[name]]);
      }
      files.sort(function(a, b) {
        return b[0].length - a[0].length;
      });

      // Substituting references to the given files with the hashed ones.
      grunt.file.expand(f.dest).forEach(function(f) {
        var destContents = fs.readFileSync(f, encoding);
        files.forEach(function(value) {
          grunt.log.debug('Substituting ' + value[0] + ' by ' + value[1])
          destContents = destContents.replace(new RegExp(utils.preg_quote(value[0])+"(\\?[0-9a-z]+)?", "g"), value[1]);

          grunt.log.debug('Substituting ' + nameToNameSearch[value[0]] + ' by ' + value[1])
          destContents = destContents.replace(
                new RegExp(nameToNameSearch[value[0]], "g"),
                value[1]
            );
        });
        grunt.log.debug('Saving the updated contents of the outination file');
        fs.writeFileSync(f, destContents, encoding);
      });
    });
  }
};
<|endoftext|>


<commit_before>/*
 * grunt-include-source
 * https://github.com/jwvdiermen/grunt-include-source
 *
 * Copyright (c) 2013 Jan Willem van Diermen
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {
	var path = require('path');
	var url = require('url');
	var os = require('os');
	var util = require('util');
	var extendr = require('extendr');

	var parseSource = function (name, pattern) {
		return function(source) {
			var matches,
				results = [];

			grunt.log.debug('Parsing ' + name + '...');
			while ((matches = pattern.exec(source)) !== null) {
				if (matches.length <= 1) continue;
				grunt.log.debug('Got match, options are { ' + matches[1] + ' }.');
				var optionsObj = JSON.parse("{" + matches[1] + "}");
				results.push({
					start: matches.index,
					end: matches.index + matches[0].length - 1,
					options: optionsObj
				});
			}

			return results;
		};
	};

	var parsers = {
		'html': parseSource('HTML', /<!---?\s*include:\s+(.*)\s*-?--\s*>/gi),
		'haml': parseSource('HAML', /-#\s+include:\s+(.*)/gi),
		'jade': parseSource('JADE', /\/\/-?\s+include:\s+(.*)/gi),
		'scss': parseSource('SASS', /\/\/\s+include:\s+(.*)/gi),
		'less': parseSource('LESS', /\/\/\s+include:\s+(.*)/gi)
	};

	var templates = {
		'html':
		{
			'js': '<script type="text/javascript" src="{filePath}"></script>',
			'css': '<link href="{filePath}" rel="stylesheet" type="text/css">'
		},
		'haml':
		{
			'js': '%script{src: "{filePath}", type: "text/javascript"}',
			'css': '%link{href: "{filePath}", rel: "stylesheet", type: "text/css"}/'
		},
		'jade':
		{
			'js': 'script(src="{filePath}", type="text/javascript")',
			'css': 'link(href="{filePath}", rel="stylesheet", type="text/css")'
		},
		'scss':
		{
			'scss': '@import "{filePath}";',
			'css': '@import "{filePath}";'
		},
		'less':
		{
			'less': '@import "{filePath}";',
			'css': '@import "{filePath}";'
		}
	};

	var resolveFiles = function (basePath, includeOptions) {
		if (includeOptions.basePath) {
			basePath = includeOptions.basePath;
		}
		grunt.log.debug('Resolving files on base path "' + basePath + '"...');
		grunt.log.debug('Include options: ' + util.inspect(includeOptions));

		var files, sourcePath = '';
		if (includeOptions.bower) {
			grunt.log.debug('Resolving files from Bower component "' + includeOptions.bower + '"...');

			sourcePath =  path.join('bower_components', includeOptions.bower);
			basePath = path.join(basePath, sourcePath);
			grunt.log.debug('Full path is "' + basePath + '".');

			var sources = grunt.file.readJSON(path.join(basePath, 'bower.json')).sources;
			files = sources[includeOptions.type];
		} else {
			grunt.log.debug('Resolving files from include property...');
			files = includeOptions.files;
		}

		if (!files) {
			grunt.log.debug('No files found.');
			return [];
		}

		grunt.log.debug('Expanding files: ' + util.inspect(files));
		var expandedFiles = grunt.file.expand({ cwd: basePath }, files);

		var results = [];
		for (var i = 0; i < expandedFiles.length; ++i) {
			var file = path.join(sourcePath, expandedFiles[i]).replace(/\\/g, '/');
			grunt.log.debug('Found file "' + file + '".');
			results.push(file);
		}

		return results;
	};

	var pathCompareNatural = function (path1, path2) {
		if (path1 > path2) {
			return 1;
		} else if (path1 < path2) {
			return -1;
		} else {
			return 0;
		}
	};

	var pathCompareTopDown = function (path1, path2) {
		var seg1 = path1.split(/[\\/]/);
		var seg2 = path2.split(/[\\/]/);
		var i, j;

		if (seg1.length === seg2.length) {
			return pathCompareNatural(path1, path2);
		} else {
			j = Math.min(seg1.length, seg2.length) - 1;
			for (i = 0; i < j; ++i) {
				if (seg1[i] !== seg2[i]) {
					return pathCompareNatural(path1, path2);
				}
			}
			return seg1.length - seg2.length;
		}
	};

	var orderFiles = function (files, includeOptions) {
		if ('top-down' === includeOptions.ordering) {
			files.sort(pathCompareTopDown);
		}
	};

	// Register the task.
	grunt.registerMultiTask('includeSource', 'Include lists of files into your source files automatically.', function() {
		grunt.log.debug('Starting task "includeSource"...');

		var options = this.options({
			basePath: '',
			baseUrl: '',
			templates: {}
		});

		grunt.log.debug('Base path is "' + options.basePath + '".');

		// Iterate over all specified file groups.
		this.files.forEach(function(file) {
			grunt.log.debug('Handling output file "' + file.dest + "'...");

			// Concatenate the source files.
			var contents = file.src.filter(function(filePath) {
					grunt.log.debug('Using input file "' + filePath + '".');
					// Remove nonexistent files.
					if (!grunt.file.exists(filePath)) {
						grunt.log.warn('Source file "' + filePath + '" not found.');
						return false;
					} else {
						return true;
					}
				}).map(	function(filePath) {
					// Read and return the file's source.
					return grunt.file.read(filePath);
				}).join('\n');

			// Parse the contents, using a parser based on the target file.
			var fileType = path.extname(file.dest).substr(1);
			grunt.log.debug('File type is "' + fileType + '"');

			var parserFn = parsers[fileType];

			if (!parserFn) {
				grunt.log.error('No parser found found file type "' + fileType + '".');
				return false;
			}

			// Get the available templates.
			var localTemplates = extendr.deepClone(templates);
			extendr.safeDeepExtendPlainObjects(localTemplates, options.templates);
			var typeTemplates = localTemplates[fileType];

			// Get the includes and rewrite the contents.
			var includes = parserFn(contents);
			var currentOffset = 0;

			grunt.log.debug('Found ' + includes.length + ' include statement(s).');

			includes.forEach(function(include) {
				var files = resolveFiles(options.basePath, include.options);
				orderFiles(files, include.options);

				var sep = os.EOL,
					lookFor = [ ' ', '\t', '\r', '\n' ],
					i;

				for (i = include.start + currentOffset - 1; i > 0 && lookFor.indexOf(contents[i]) >= 0; --i);
				if (i > 0) {
					++i;
					sep = contents.substr(i, include.start + currentOffset - i);
				}

				var	includeFragments = [];
				files.forEach(function(file) {
					grunt.log.debug('Including file "' + file + '".');
					includeFragments.push(typeTemplates[include.options.type]
						.replace(/\{filePath\}/g, url.resolve(include.options.baseUrl || options.baseUrl, file))
						.replace(/\{filePathDecoded\}/g, decodeURI(url.resolve(include.options.baseUrl || options.baseUrl, file)))
					);
				});

				var includeFragment = includeFragments.join(sep);

				contents =
					contents.substr(0, include.start + currentOffset) +
					includeFragment +
					contents.substr(include.end + 1 + currentOffset);

				var originalLength = include.end - include.start + 1;
				currentOffset += includeFragment.length - originalLength;
			});

			grunt.log.debug('Writing output...');
			grunt.file.write(file.dest, contents);
			grunt.log.writeln('File "' + file.dest + '" created.');
		});
	});
};
<commit_msg>Support end marker <!-- /include --><commit_after>/*
 * grunt-include-source
 * https://github.com/jwvdiermen/grunt-include-source
 *
 * Copyright (c) 2013 Jan Willem van Diermen
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {
	var path = require('path');
	var url = require('url');
	var os = require('os');
	var util = require('util');
	var extendr = require('extendr');

	var parseSource = function (name, pattern) {
		return function(source) {
			var matches,
				results = [];

			grunt.log.debug('Parsing ' + name + '...');
			while ((matches = pattern.exec(source)) !== null) {
				if (matches.length <= 1) continue;
				grunt.log.debug('Got match, options are { ' + matches[1] + ' }.');
				var optionsObj = JSON.parse("{" + matches[1] + "}");
				results.push({
					start: matches.index,
					end: matches.index + matches[0].length - 1,
					options: optionsObj
				});
			}

			return results;
		};
	};

  // Generates function to find end marker, e.g. <!-- /include -->
  var findEndMarker = function(name, pattern){
    /*
      source: Code between the current include and the next one. (Or the end of the file)
      offset: Stat position of the source fragement inside the file.
    */
    return function(source, offset){
      var endMarker = pattern.exec(source);
      if (endMarker === null){
        return null;
      }
      return {
        start: endMarker.index + offset,
        length: endMarker[0].length
      };
    };
  };

	var parsers = {
		'html': parseSource('HTML', /<!---?\s*include:\s+(.*)\s*-?--\s*>/gi),
		'haml': parseSource('HAML', /-#\s+include:\s+(.*)/gi),
		'jade': parseSource('JADE', /\/\/-?\s+include:\s+(.*)/gi),
		'scss': parseSource('SASS', /\/\/\s+include:\s+(.*)/gi),
		'less': parseSource('LESS', /\/\/\s+include:\s+(.*)/gi)
	};

  var endMarkerParsers = {
    'html': findEndMarker('HTML', /<!---?\s\/include\s+-?--\>/)
  };

	var templates = {
		'html':
		{
			'js': '<script type="text/javascript" src="{filePath}"></script>',
			'css': '<link href="{filePath}" rel="stylesheet" type="text/css">'
		},
		'haml':
		{
			'js': '%script{src: "{filePath}", type: "text/javascript"}',
			'css': '%link{href: "{filePath}", rel: "stylesheet", type: "text/css"}/'
		},
		'jade':
		{
			'js': 'script(src="{filePath}", type="text/javascript")',
			'css': 'link(href="{filePath}", rel="stylesheet", type="text/css")'
		},
		'scss':
		{
			'scss': '@import "{filePath}";',
			'css': '@import "{filePath}";'
		},
		'less':
		{
			'less': '@import "{filePath}";',
			'css': '@import "{filePath}";'
		}
	};

	var resolveFiles = function (basePath, includeOptions) {
		if (includeOptions.basePath) {
			basePath = includeOptions.basePath;
		}
		grunt.log.debug('Resolving files on base path "' + basePath + '"...');
		grunt.log.debug('Include options: ' + util.inspect(includeOptions));

		var files, sourcePath = '';
		if (includeOptions.bower) {
			grunt.log.debug('Resolving files from Bower component "' + includeOptions.bower + '"...');

			sourcePath =  path.join('bower_components', includeOptions.bower);
			basePath = path.join(basePath, sourcePath);
			grunt.log.debug('Full path is "' + basePath + '".');

			var sources = grunt.file.readJSON(path.join(basePath, 'bower.json')).sources;
			files = sources[includeOptions.type];
		} else {
			grunt.log.debug('Resolving files from include property...');
			files = includeOptions.files;
		}

		if (!files) {
			grunt.log.debug('No files found.');
			return [];
		}

		grunt.log.debug('Expanding files: ' + util.inspect(files));
		var expandedFiles = grunt.file.expand({ cwd: basePath }, files);

		var results = [];
		for (var i = 0; i < expandedFiles.length; ++i) {
			var file = path.join(sourcePath, expandedFiles[i]).replace(/\\/g, '/');
			grunt.log.debug('Found file "' + file + '".');
			results.push(file);
		}

		return results;
	};

	var pathCompareNatural = function (path1, path2) {
		if (path1 > path2) {
			return 1;
		} else if (path1 < path2) {
			return -1;
		} else {
			return 0;
		}
	};

	var pathCompareTopDown = function (path1, path2) {
		var seg1 = path1.split(/[\\/]/);
		var seg2 = path2.split(/[\\/]/);
		var i, j;

		if (seg1.length === seg2.length) {
			return pathCompareNatural(path1, path2);
		} else {
			j = Math.min(seg1.length, seg2.length) - 1;
			for (i = 0; i < j; ++i) {
				if (seg1[i] !== seg2[i]) {
					return pathCompareNatural(path1, path2);
				}
			}
			return seg1.length - seg2.length;
		}
	};

	var orderFiles = function (files, includeOptions) {
		if ('top-down' === includeOptions.ordering) {
			files.sort(pathCompareTopDown);
		}
	};

	// Register the task.
	grunt.registerMultiTask('includeSource', 'Include lists of files into your source files automatically.', function() {
		grunt.log.debug('Starting task "includeSource"...');

		var options = this.options({
			basePath: '',
			baseUrl: '',
			templates: {}
		});

		grunt.log.debug('Base path is "' + options.basePath + '".');

		// Iterate over all specified file groups.
		this.files.forEach(function(file) {
			grunt.log.debug('Handling output file "' + file.dest + "'...");

			// Concatenate the source files.
			var contents = file.src.filter(function(filePath) {
					grunt.log.debug('Using input file "' + filePath + '".');
					// Remove nonexistent files.
					if (!grunt.file.exists(filePath)) {
						grunt.log.warn('Source file "' + filePath + '" not found.');
						return false;
					} else {
						return true;
					}
				}).map(	function(filePath) {
					// Read and return the file's source.
					return grunt.file.read(filePath);
				}).join('\n');

			// Parse the contents, using a parser based on the target file.
			var fileType = path.extname(file.dest).substr(1);
			grunt.log.debug('File type is "' + fileType + '"');

			var parserFn = parsers[fileType];
      var findEndMarker = endMarkerParsers[fileType];

			if (!parserFn) {
				grunt.log.error('No parser found found file type "' + fileType + '".');
				return false;
			}

			// Get the available templates.
			var localTemplates = extendr.deepClone(templates);
			extendr.safeDeepExtendPlainObjects(localTemplates, options.templates);
			var typeTemplates = localTemplates[fileType];

			// Get the includes and rewrite the contents.
			var includes = parserFn(contents);
			var currentOffset = 0;

			grunt.log.debug('Found ' + includes.length + ' include statement(s).');

			includes.forEach(function(include, includeIndex) {
				var files = resolveFiles(options.basePath, include.options);
				orderFiles(files, include.options);

				var sep = os.EOL,
					lookFor = [ ' ', '\t', '\r', '\n' ],
					i;

				for (i = include.start + currentOffset - 1; i > 0 && lookFor.indexOf(contents[i]) >= 0; --i);
				if (i > 0) {
					++i;
					sep = contents.substr(i, include.start + currentOffset - i);
				}

				var	includeFragments = [];
				files.forEach(function(file) {
					grunt.log.debug('Including file "' + file + '".');
					includeFragments.push(typeTemplates[include.options.type]
						.replace(/\{filePath\}/g, url.resolve(include.options.baseUrl || options.baseUrl, file))
						.replace(/\{filePathDecoded\}/g, decodeURI(url.resolve(include.options.baseUrl || options.baseUrl, file)))
					);
				});

				var includeFragment = includeFragments.join(sep);

				// If there is an end marker before the next include or the end of the file
				// we want to replace the entire content between it and the include comment.
				var endMarker = null;
				if (findEndMarker){
				  var nextInclude = includes[includeIndex + 1];
				  var nextPartIndex = nextInclude ? nextInclude.start : contents.length;
				  var between = contents.substring(include.start + currentOffset, nextPartIndex + currentOffset);

				  endMarker = findEndMarker(between, include.start);
				}

				var replacementStart;
				var replacementEnd;
				if (endMarker === null) {
				  replacementStart = include.start + currentOffset;
				  replacementEnd = include.end + 1 + currentOffset;
				} else {
				  replacementStart = include.end + 1 + currentOffset;
				  replacementEnd = endMarker.start + currentOffset;
				}

				contents =
				  contents.substr(0, replacementStart) +
				  includeFragment +
				  contents.substr(replacementEnd);

				var addedCharacters = includeFragment.length;
				var removedCharacters = replacementEnd - replacementStart;
				currentOffset += addedCharacters - removedCharacters;
			});

			grunt.log.debug('Writing output...');
			grunt.file.write(file.dest, contents);
			grunt.log.writeln('File "' + file.dest + '" created.');
		});
	});
};
<|endoftext|>


<commit_before>/*
 * grunt-labeled-merge
 * https://github.com/allan/grunt-labeled-merge
 *
 * Copyright (c) 2015 atask
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('labeled_merge', 'Merges folders without overwriting files.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
        label: function(srcPath) {
            // Use millisecs as a label
            return Date.now();
        }
    });

    // Iterate over all specified file groups.
    this.files
        .filter(function(mapping) {
            // if not working with folders, forget it
            var goodSrc = true,
                goodDest = grunt.file.isDir(mapping.dest);
            mapping.src.forEach(function noDirIn(path) {
                if (!grunt.file.isDir(path)) {
                    goodSrc = false;
                }
            });
            return goodSrc && goodDest;
        })
        .forEach(function(mapping) {
            mapping.src.forEach(function (srcPath) {
                var label = options.label(srcPath),
                    mergeIndex = {};
                grunt.file.recurse(srcPath, function mergeFiles(abspath,
                        rootdir, subdir, filename) {
                    grunt.log.ok(abspath);
                    grunt.log.ok(rootdir);
                    grunt.log.ok(subdir);
                    grunt.log.ok(filename);
                });
            });
        });

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

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

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

      // Print a success message.
      grunt.log.writeln('File "' + f.dest + '" created.');
    });
    */
  });

};
<commit_msg>feature(labeled-merge): generate grunt copy mappings<commit_after>/*
 * grunt-labeled-merge
 * https://github.com/allan/grunt-labeled-merge
 *
 * Copyright (c) 2015 atask
 * Licensed under the MIT license.
 */

'use strict';

var fileHash = require('./lib/fileHash'),
    join = require('path').join,
    sep = require('path').sep;
module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('labeled_merge', 'Merges folders without overwriting files.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
            label: function(srcPath) {
                // Use millisecs as a label
                return Date.now();
            }
        }),

    // Iterate over all specified file groups.
    this.files
        .filter(function(mapping) {
            // if not working with folders, forget it
            var goodSrc = true,
                goodDest = grunt.file.isDir(mapping.dest);
            mapping.src.forEach(function noDirIn(path) {
                if (!grunt.file.isDir(path)) {
                    goodSrc = false;
                }
            });
            return goodSrc && goodDest;
        })
        .forEach(function(mapping) {
            mapping.src.forEach(function (srcPath) {
                var label = options.label(srcPath),
                    copyMappings = [],
                    mergeIndex = {};
                grunt.file.recurse(srcPath, function mergeFiles(abspath,
                        rootdir, subdir, filename) {

                    var skipFile = false,
                        destTestPath = subdir
                            ? join(mappings.dest, subdir, filename)
                            : join(mappings.dest, filename);

                    // if there is a different version of the same file
                    // save a copy with a labeled name
                    if (grunt.file.exists(destTestPath)) {
                        // check if we need a new copy
                        var srcMD5 = fileHash(abspath),
                            destMD5 = fileHash(destTestPath);
                        if (srcMD5 !== destMD5) {
                            // different files... generate new name
                            var dotPos = filename.lastIndexOf('.');
                            if (dotPos !== -1 && dotPos !== 0) {
                                // file has extension
                                var newFilename = filename.substring(0, dotPos) +
                                    '.' + label + filename.substring(dotPos, filename.length);
                                destTestPath = destTestPath.replace(filename, newFilename);
                            } else {
                                // no extension
                                destTestPath += '.' + label;
                            }
                        } else {
                            // same files, don't copy
                            skipFile = true;
                        }
                    }

                    if (!skipFile) {
                        // add mappings for copy task
                        copyMappings.push({
                            src: srcPath,
                            dest: destTestPath
                        });

                        // index the file
                        var deepest = mergeIndex;
                        destTestPath.split(sep).forEach(function traverseIndex(name, index, names) {
                            if (index < names.length - 1) {
                                if (!deepest.name) {
                                    // create object
                                    deepest.name = {};
                                }
                                deepest = deepest.name;
                            }
                        });
                    }
                    grunt.log.ok(abspath);
                    grunt.log.ok(rootdir);
                    grunt.log.ok(subdir);
                    grunt.log.ok(filename);
                });
            });
        });

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

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

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

      // Print a success message.
      grunt.log.writeln('File "' + f.dest + '" created.');
    });
    */
  });

};
<|endoftext|>


<commit_before>/*
 * grunt-makeTextFiles
 *
 *
 * Copyright (c) 2014 Incuna Ltd.
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks

    grunt.registerTask('makeTextFiles', 'Builds textfiles.js needed by eDetails', function() {

        // import Nodejs libs
        var fs = require('fs');
        var path = require('path');
        var _ = require('lodash');

        //static vars
        var packageFileName = 'package.json';
        var projectBasePath = 'project/';
        var projectPackage = grunt.file.readJSON(packageFileName);
        //template file relative to this file
        var templateFileName = '../templates/textFiles.template.js';

        // Merge task-specific and/or target-specific options with these defaults.
        var options = this.options({
            destinationFileName: projectBasePath + 'textFiles.js'
        });

        //converts path relative to project root to absolute file system path
        function projectToAbsPath(relPath) {
            return path.resolve(relPath);
        }
        //converts path relative to plugin root to absolute file system path
        function pluginToAbsPath(relPath) {
            return path.join(__dirname, relPath);
        }

        //takes a parsed package.json object and requireJS module name, and returns any text dirs as an array
        function textDirsFromPackage(packageObj, jamDir) {
            var packageName = null;
            var basePath = projectBasePath;
            if (jamDir) {
                //we only need to store package name and path for jam packages, not root project package
                packageName = packageObj.name;
                basePath = jamDir + '/' + packageName + '/';
            }

            var textDirs = [];
            if (packageObj.textDirs) {
                _(packageObj.textDirs).each(function(textDir) {
                    //we add the package name and path properties so we can use them later when making the template
                    textDir.packageName = packageName;
                    textDir.basePath = basePath;
                    textDirs.push(textDir);
                });
            }
            return textDirs;
        }

        function getJamPackages() {
            var jamPackages = [];

            //Add text dirs from jam packages
            if (projectPackage.jam && projectPackage.jam.packageDir && projectPackage.jam.dependencies) {
                //find all jam packages

                var jamPackageFiles = [];
                if (projectPackage.jam.dependencies) {
                    //we have some jam packages, so look for package.json files in each package
                    for (var packageName in projectPackage.jam.dependencies) {
                        var packageFilePath = projectPackage.jam.packageDir + '/' + packageName + '/' + packageFileName;
                        if (grunt.file.exists(packageFilePath)) {
                            jamPackageFiles.push(packageFilePath);
                        }
                    }
                }

                //read package.jsons and make object of parsed packages
                jamPackages = _(jamPackageFiles).map(function(packageFilePath) {
                    return grunt.file.readJSON(packageFilePath);
                });
            }
            return jamPackages;
        }

        //takes an array of textDir objects and returns all matched filepaths inside as actual paths and requireJS mdoule paths
        function expandTextDirFilePaths(textDirs) {
            //Look through each module path and make a list of matching text files
            //We make two arrays as they need to be output separately in the template
            var filePaths = [];
            var requireJSPaths = [];

            //Go through each text dir, adding matching files to the list
            _(textDirs).each(function (textDir) {
                //match all files for this textdir
                var fileMatchStrings = [];
                _(textDir.fileTypes).each(function(fileType) {
                    var fileTypeMatchString = textDir.path + '/**/*.' + fileType;
                    fileMatchStrings.push(fileTypeMatchString);
                });

                var matchOptions = {};
                if (textDir.basePath) {
                    //get files relative to package path if present
                    matchOptions.cwd = textDir.basePath;
                }

                var matchingFiles = grunt.file.expand(matchOptions, fileMatchStrings);

                //populate lists for template
                _(matchingFiles).each(function(filePath) {
                    if (!filePaths[filePath]) {
                        //dont add if we already have the paths in the list
                        //this allows overriding of paths by the project
                        var requireBasePath = 'text!';
                        if (textDir.packageName) {
                            requireBasePath += textDir.packageName + '/';
                        }

                        filePaths.push(filePath);
                        requireJSPaths.push(requireBasePath + filePath);
                    }
                });
            });

            return {
                realPaths: filePaths,
                requireJSPaths: requireJSPaths
            };
        }

        //write out textfiles.js file from template and filepath data
        function writeTemplate(filePaths) {
            // Write out the textFiles manifest using the template and the built files array
            //get absolute template path in filesystem
            var templatePath = pluginToAbsPath(templateFileName);
            //get template file contents
            var templateString = fs.readFileSync(templatePath, 'utf8');

            grunt.log.writeln('Writing ' + options.destinationFileName);

            var fileTemplate = _.template(templateString);
            var destinationFileContents = fileTemplate({
                requirePaths: filePaths.requireJSPaths.join("',\n    '"),
                textFiles: filePaths.realPaths.join("',\n        '")
            });
            var destinationPath = projectToAbsPath(options.destinationFileName);
            fs.writeFileSync(destinationPath, destinationFileContents);
        }

        function init() {
            //var to store all text dirs
            var textDirs = [];

            //Add text dirs from main project
            textDirs = textDirs.concat(textDirsFromPackage(projectPackage));

            var jamPackages = getJamPackages();
            //Add jam package text dirs to list
            _(jamPackages).each(function(jamPackage) {
                textDirs = textDirs.concat(textDirsFromPackage(jamPackage, projectPackage.jam.packageDir));
            });

            var filePaths = expandTextDirFilePaths(textDirs);

            if (!filePaths.realPaths) {
                //warn and exit grunt with a message
                grunt.warn('No files found', 0);
            }

            writeTemplate(filePaths);
        }

        init();
    });
};
<commit_msg>Trim whitespace<commit_after>/*
 * grunt-makeTextFiles
 *
 *
 * Copyright (c) 2014 Incuna Ltd.
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks

    grunt.registerTask('makeTextFiles', 'Builds textfiles.js needed by eDetails', function() {

        // import Nodejs libs
        var fs = require('fs');
        var path = require('path');
        var _ = require('lodash');

        //static vars
        var packageFileName = 'package.json';
        var projectBasePath = 'project/';
        var projectPackage = grunt.file.readJSON(packageFileName);
        //template file relative to this file
        var templateFileName = '../templates/textFiles.template.js';

        // Merge task-specific and/or target-specific options with these defaults.
        var options = this.options({
            destinationFileName: projectBasePath + 'textFiles.js'
        });

        //converts path relative to project root to absolute file system path
        function projectToAbsPath(relPath) {
            return path.resolve(relPath);
        }
        //converts path relative to plugin root to absolute file system path
        function pluginToAbsPath(relPath) {
            return path.join(__dirname, relPath);
        }

        //takes a parsed package.json object and requireJS module name, and returns any text dirs as an array
        function textDirsFromPackage(packageObj, jamDir) {
            var packageName = null;
            var basePath = projectBasePath;
            if (jamDir) {
                //we only need to store package name and path for jam packages, not root project package
                packageName = packageObj.name;
                basePath = jamDir + '/' + packageName + '/';
            }

            var textDirs = [];
            if (packageObj.textDirs) {
                _(packageObj.textDirs).each(function(textDir) {
                    //we add the package name and path properties so we can use them later when making the template
                    textDir.packageName = packageName;
                    textDir.basePath = basePath;
                    textDirs.push(textDir);
                });
            }
            return textDirs;
        }

        function getJamPackages() {
            var jamPackages = [];

            //Add text dirs from jam packages
            if (projectPackage.jam && projectPackage.jam.packageDir && projectPackage.jam.dependencies) {
                //find all jam packages

                var jamPackageFiles = [];
                if (projectPackage.jam.dependencies) {
                    //we have some jam packages, so look for package.json files in each package
                    for (var packageName in projectPackage.jam.dependencies) {
                        var packageFilePath = projectPackage.jam.packageDir + '/' + packageName + '/' + packageFileName;
                        if (grunt.file.exists(packageFilePath)) {
                            jamPackageFiles.push(packageFilePath);
                        }
                    }
                }

                //read package.jsons and make object of parsed packages
                jamPackages = _(jamPackageFiles).map(function(packageFilePath) {
                    return grunt.file.readJSON(packageFilePath);
                });
            }
            return jamPackages;
        }

        //takes an array of textDir objects and returns all matched filepaths inside as actual paths and requireJS mdoule paths
        function expandTextDirFilePaths(textDirs) {
            //Look through each module path and make a list of matching text files
            //We make two arrays as they need to be output separately in the template
            var filePaths = [];
            var requireJSPaths = [];

            //Go through each text dir, adding matching files to the list
            _(textDirs).each(function (textDir) {
                //match all files for this textdir
                var fileMatchStrings = [];
                _(textDir.fileTypes).each(function(fileType) {
                    var fileTypeMatchString = textDir.path + '/**/*.' + fileType;
                    fileMatchStrings.push(fileTypeMatchString);
                });

                var matchOptions = {};
                if (textDir.basePath) {
                    //get files relative to package path if present
                    matchOptions.cwd = textDir.basePath;
                }

                var matchingFiles = grunt.file.expand(matchOptions, fileMatchStrings);

                //populate lists for template
                _(matchingFiles).each(function(filePath) {
                    if (!filePaths[filePath]) {
                        //dont add if we already have the paths in the list
                        //this allows overriding of paths by the project
                        var requireBasePath = 'text!';
                        if (textDir.packageName) {
                            requireBasePath += textDir.packageName + '/';
                        }

                        filePaths.push(filePath);
                        requireJSPaths.push(requireBasePath + filePath);
                    }
                });
            });

            return {
                realPaths: filePaths,
                requireJSPaths: requireJSPaths
            };
        }

        //write out textfiles.js file from template and filepath data
        function writeTemplate(filePaths) {
            // Write out the textFiles manifest using the template and the built files array
            //get absolute template path in filesystem
            var templatePath = pluginToAbsPath(templateFileName);
            //get template file contents
            var templateString = fs.readFileSync(templatePath, 'utf8');

            grunt.log.writeln('Writing ' + options.destinationFileName);

            var fileTemplate = _.template(templateString);
            var destinationFileContents = fileTemplate({
                requirePaths: filePaths.requireJSPaths.join("',\n    '"),
                textFiles: filePaths.realPaths.join("',\n        '")
            });
            var destinationPath = projectToAbsPath(options.destinationFileName);
            fs.writeFileSync(destinationPath, destinationFileContents);
        }

        function init() {
            //var to store all text dirs
            var textDirs = [];

            //Add text dirs from main project
            textDirs = textDirs.concat(textDirsFromPackage(projectPackage));

            var jamPackages = getJamPackages();
            //Add jam package text dirs to list
            _(jamPackages).each(function(jamPackage) {
                textDirs = textDirs.concat(textDirsFromPackage(jamPackage, projectPackage.jam.packageDir));
            });

            var filePaths = expandTextDirFilePaths(textDirs);

            if (!filePaths.realPaths) {
                //warn and exit grunt with a message
                grunt.warn('No files found', 0);
            }

            writeTemplate(filePaths);
        }

        init();
    });
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import queryString from 'query-string';
import localstorage from 'store2';
import createHistory from 'history/createBrowserHistory';
import config from './config';
import './App.css';

import InviteUserForm from './components/InviteUserForm';

const history = createHistory();

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  componentWillMount() {
    if (location.pathname === '/logout') {
      localstorage.clear();
      history.replace('/');
    } else {
      this.checkForCode();
    }
  }

  checkForCode() {
    const query = queryString.parse(location.hash.substr(1));

    if (query.code && !localstorage('accessToken')) {
      localstorage({
        accessToken: query.access_token,
        expiresIn: query.expires_in,
        idToken: query.id_token,
        tokenType: query.token_type,
      });
      this.setState(localstorage());
      history.replace('/');
    } else if (localstorage('accessToken')) {
      this.setState(localstorage());
    }
  }

  renderLoggedOutContent() {
    return (

          <a href={`https://sso-client.dev:9000/op/auth?client_id=${config.clientId}&response_type=code id_token token&scope=${config.scope}&redirect_uri=${config.redirectUri}&nonce=nonce`}>Log In
           |
          <a href={`https://sso-client.dev:9000/user/register?client_id=${config.clientId}&response_type=code id_token token&scope=${config.scope}&redirect_uri=${config.redirectUri}&nonce=nonce`}>Sign Up

    );
  }

  renderLoggedInContent() {
    return (

Logged In

Access Token

{this.state.accessToken}

Expires In

{this.state.expiresIn}

Id Token

{this.state.idToken}

Token Type

{this.state.tokenType}

          <InviteUserForm />

<a href={`https://sso-client.dev:9000/user/profile?client_id=${config.clientId}&redirect_uri=${config.redirectUri}`}>Edit Profile

<a href={`https://sso-client.dev:9000/user/password?client_id=${config.clientId}&redirect_uri=${config.redirectUri}`}>Change Password

<a href={`https://sso-client.dev:9000/user/email-settings?client_id=${config.clientId}&redirect_uri=${config.redirectUri}`}>Email Settings

<a href={`https://sso-client.dev:9000/op/session/end?id_token_hint=${this.state.idToken}&post_logout_redirect_uri=${config.postLogoutRedirectUri}`}>Log Out

<a href={`https://sso-client.dev:9000/user/logout?post_logout_redirect_uri=${config.postLogoutRedirectUri}`}>One-click log Out

    );
  }

  render() {
    return (

Synapse Identity Platform

        {!this.state.accessToken ? this.renderLoggedOutContent() : this.renderLoggedInContent()}

    );
  }
}

export default App;
<commit_msg>Update App urls to use sso-client.test<commit_after>import React, { Component } from 'react';
import queryString from 'query-string';
import localstorage from 'store2';
import createHistory from 'history/createBrowserHistory';
import config from './config';
import './App.css';

import InviteUserForm from './components/InviteUserForm';

const history = createHistory();

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  componentWillMount() {
    if (location.pathname === '/logout') {
      localstorage.clear();
      history.replace('/');
    } else {
      this.checkForCode();
    }
  }

  checkForCode() {
    const query = queryString.parse(location.hash.substr(1));

    if (query.code && !localstorage('accessToken')) {
      localstorage({
        accessToken: query.access_token,
        expiresIn: query.expires_in,
        idToken: query.id_token,
        tokenType: query.token_type,
      });
      this.setState(localstorage());
      history.replace('/');
    } else if (localstorage('accessToken')) {
      this.setState(localstorage());
    }
  }

  renderLoggedOutContent() {
    return (

          <a href={`https://sso-client.test:9000/op/auth?client_id=${config.clientId}&response_type=code id_token token&scope=${config.scope}&redirect_uri=${config.redirectUri}&nonce=nonce`}>Log In
           |
          <a href={`https://sso-client.test:9000/user/register?client_id=${config.clientId}&response_type=code id_token token&scope=${config.scope}&redirect_uri=${config.redirectUri}&nonce=nonce`}>Sign Up

    );
  }

  renderLoggedInContent() {
    return (

Logged In

Access Token

{this.state.accessToken}

Expires In

{this.state.expiresIn}

Id Token

{this.state.idToken}

Token Type

{this.state.tokenType}

          <InviteUserForm />

<a href={`https://sso-client.test:9000/user/profile?client_id=${config.clientId}&redirect_uri=${config.redirectUri}`}>Edit Profile

<a href={`https://sso-client.test:9000/user/password?client_id=${config.clientId}&redirect_uri=${config.redirectUri}`}>Change Password

<a href={`https://sso-client.test:9000/user/email-settings?client_id=${config.clientId}&redirect_uri=${config.redirectUri}`}>Email Settings

<a href={`https://sso-client.test:9000/op/session/end?id_token_hint=${this.state.idToken}&post_logout_redirect_uri=${config.postLogoutRedirectUri}`}>Log Out

<a href={`https://sso-client.test:9000/user/logout?post_logout_redirect_uri=${config.postLogoutRedirectUri}`}>One-click log Out

    );
  }

  render() {
    return (

Synapse Identity Platform

        {!this.state.accessToken ? this.renderLoggedOutContent() : this.renderLoggedInContent()}

    );
  }
}

export default App;
<|endoftext|>