<commit_before>import traverse from 'traverse';
import {err, zip} from './util.js';
import kToken from './key-token';
import vToken from './value-token';
import resolveReplacer from './replacer';

export default class FsMapper {
  /**
   * construct FsMapper with template object
   * @param {object|string} template - specify object to define mapping
   * @throws {PluginError} throw gutil.PluginError when parameter is invalid
   */
  constructor(template) {
    // input guards
    if (!template) {
      throw err('Missing template object');
    } else if (!this._validate(template)) {
      throw err('Specified template is invalid');
    }

    this.travTemplate = traverse(template);
  }

  /**
   * validate template object
   * @access private
   * @param {object|string} template - specify target to validate
   * @return {boolean} if true, template is valid
   */
  _validate(template) {
    const nodes = traverse(template).nodes();
    const validTypes = ['object', 'string', 'undefined'];

    const isValidType = nodes.map((node) => typeof node)
                             .every((type) => validTypes.indexOf(type) >= 0);
    const differFromNext = (v, i, a) => i === a.length - 1 ||
                                        v !== a[i + 1];
    const isUnique = nodes.filter((node) => typeof node === 'string')
                          .map((str) => vToken(str).plainName)
                          .filter((str) => Boolean(str))
                          .sort()
                          .every(differFromNext);

    return isValidType && isUnique;
  }

  /**
   * match template with src and return mapping definition
   * @access public
   * @param {any} src - specify source object (or primitive value) to map
   * @param {object} replacer - specify replace functions by key-value object
   * @param {function(string)} onError - specify onError callback function
   * @throws {PluginError} throw gutil.PluginError, expecting to catch and emit error event
   * @return {Map<string, any>} mapping definition (path => value)
   */
  match(src, replacer, onError) {
    const travSrc = traverse(src);

    const availableNode = ([pathToken, nodeToken]) => {
      const srcExists = travSrc.has(pathToken.path);

      if (!srcExists) {
        if (!pathToken.isMeta && !nodeToken.canSkip) {
          onError(`Failed to match template (json["${pathToken.path.join('"]["')}"] is undefined)`);
          return false;
        }
      } else if (pathToken.path.length > 0) {
        const parentPath = pathToken.path.slice(0, -1);
        const srcParent = travSrc.get(parentPath);
        const templateParent = this.travTemplate.get(parentPath);
        if (typeof srcParent !== typeof templateParent ||
            Array.isArray(srcParent) !== Array.isArray(templateParent)) {
          onError(`Failed to match template (typeof json["${parentPath.join('"]["')}"] is invalid)`);
          return false;
        }
      }
      if (!nodeToken.value) {
        return false;
      }
      return true;
    };

    const toFile = ([pathToken, nodeToken]) => {
      const p = pathToken.path;
      const sliceParent = (childPath) => {
        const childIndex = Number(childPath.pop());
        const parentArray = travSrc.get(childPath);
        if (!Array.isArray(parentArray)) {
          onError(`Failed to match template (typeof json["${pathToken.path.join('"]["')}"] is not Array)`);
        }

        return [parentArray.slice(childIndex), childIndex];
      };

      if (nodeToken.isArrayIterate) {
        const [sliced, sliceIndex] = sliceParent(p);
        return sliced.map((e, i) => {
          const iteratePath = [...p, sliceIndex + i];
          const fileContent = e;
          const filePath = resolveReplacer(nodeToken.name,
                                           [fileContent, iteratePath, sliceIndex],
                                           replacer);
          return [filePath, fileContent];
        });
      } else {
        let fileContent;
        if (pathToken.isObjectRest) {
          p.pop();
          fileContent = this._getUnmapped(travSrc, p);
        } else if (nodeToken.isArraySpread) {
          fileContent = sliceParent(p)[0];
        } else {
          fileContent = travSrc.get(p);
        }

        const filePath = resolveReplacer(nodeToken.name,
                                        [fileContent, pathToken.path],
                                        replacer);
        return [filePath, fileContent];
      }
    };

    const flatten = (prev, next) => prev.concat(Array.isArray(next[0]) ?
                                                next : [next]);

    const keyValues = zip(this.travTemplate.paths(), this.travTemplate.nodes())
                      .map(([k, v]) => [kToken(k), vToken(v)])
                      .filter(availableNode)
                      .map(toFile)
                      .filter((e) => Boolean(e))
                      .reduce(flatten, []);
    return new Map(keyValues);
  }

  /**
   * get the element at specified path, excluding paths map to other file
   * @access private
   * @param {Traverse} travSrc - specify traversed source object to map
   * @param {string[]} parentPath - specify array of string keys from the root to the target node
   * @return {object} the element excluded mapped values
   */
  _getUnmapped(travSrc, parentPath) {
    function nextOfParent(p) {
      // parent: ["path", "to", "parent"]
      // p:      ["path", "to", "parent", "next"]
      // => return "next"
      if (p.length === parentPath.length + 1 &&
          p.every((e, i) =>
            e === parentPath[i] || i === p.length - 1)) {
        return p[p.length - 1];
      } else {
        return null;
      }
    }

    const parent = travSrc.get(parentPath);
    const copy = Object.assign({}, parent);

    // remove mapped values
    this.travTemplate.paths().map(nextOfParent)
                             .filter((key) => key && !kToken(key).isMeta)
                             .forEach((mappedKey) => delete copy[mappedKey]);
    return copy;
  }
}
<commit_msg>fix: skip array iteration if there's no element to iterate<commit_after>import traverse from 'traverse';
import {err, zip} from './util.js';
import kToken from './key-token';
import vToken from './value-token';
import resolveReplacer from './replacer';

export default class FsMapper {
  /**
   * construct FsMapper with template object
   * @param {object|string} template - specify object to define mapping
   * @throws {PluginError} throw gutil.PluginError when parameter is invalid
   */
  constructor(template) {
    // input guards
    if (!template) {
      throw err('Missing template object');
    } else if (!this._validate(template)) {
      throw err('Specified template is invalid');
    }

    this.travTemplate = traverse(template);
  }

  /**
   * validate template object
   * @access private
   * @param {object|string} template - specify target to validate
   * @return {boolean} if true, template is valid
   */
  _validate(template) {
    const nodes = traverse(template).nodes();
    const validTypes = ['object', 'string', 'undefined'];

    const isValidType = nodes.map((node) => typeof node)
                             .every((type) => validTypes.indexOf(type) >= 0);
    const differFromNext = (v, i, a) => i === a.length - 1 ||
                                        v !== a[i + 1];
    const isUnique = nodes.filter((node) => typeof node === 'string')
                          .map((str) => vToken(str).plainName)
                          .filter((str) => Boolean(str))
                          .sort()
                          .every(differFromNext);

    return isValidType && isUnique;
  }

  /**
   * match template with src and return mapping definition
   * @access public
   * @param {any} src - specify source object (or primitive value) to map
   * @param {object} replacer - specify replace functions by key-value object
   * @param {function(string)} onError - specify onError callback function
   * @throws {PluginError} throw gutil.PluginError, expecting to catch and emit error event
   * @return {Map<string, any>} mapping definition (path => value)
   */
  match(src, replacer, onError) {
    const travSrc = traverse(src);

    const availableNode = ([pathToken, nodeToken]) => {
      const srcExists = travSrc.has(pathToken.path);

      if (!srcExists) {
        if (!pathToken.isMeta && !nodeToken.canSkip) {
          onError(`Failed to match template (json["${pathToken.path.join('"]["')}"] is undefined)`);
          return false;
        }
      } else if (pathToken.path.length > 0) {
        const parentPath = pathToken.path.slice(0, -1);
        const srcParent = travSrc.get(parentPath);
        const templateParent = this.travTemplate.get(parentPath);
        if (typeof srcParent !== typeof templateParent ||
            Array.isArray(srcParent) !== Array.isArray(templateParent)) {
          onError(`Failed to match template (typeof json["${parentPath.join('"]["')}"] is invalid)`);
          return false;
        }
      }
      if (!nodeToken.value) {
        return false;
      }
      return true;
    };

    const toFile = ([pathToken, nodeToken]) => {
      const p = pathToken.path;
      const sliceParent = (childPath) => {
        const childIndex = Number(childPath.pop());
        const parentArray = travSrc.get(childPath);
        if (!Array.isArray(parentArray)) {
          onError(`Failed to match template (typeof json["${pathToken.path.join('"]["')}"] is not Array)`);
        }

        return [parentArray.slice(childIndex), childIndex];
      };

      if (nodeToken.isArrayIterate) {
        const [sliced, sliceIndex] = sliceParent(p);
        if (!sliced.length) {
          return null;  // nothing to iterate
        }
        return sliced.map((e, i) => {
          const iteratePath = [...p, sliceIndex + i];
          const fileContent = e;
          const filePath = resolveReplacer(nodeToken.name,
                                           [fileContent, iteratePath, sliceIndex],
                                           replacer);
          return [filePath, fileContent];
        });
      } else {
        let fileContent;
        if (pathToken.isObjectRest) {
          p.pop();
          fileContent = this._getUnmapped(travSrc, p);
        } else if (nodeToken.isArraySpread) {
          fileContent = sliceParent(p)[0];
        } else {
          fileContent = travSrc.get(p);
        }

        const filePath = resolveReplacer(nodeToken.name,
                                        [fileContent, pathToken.path],
                                        replacer);
        return [filePath, fileContent];
      }
    };

    const flatten = (prev, next) => prev.concat(Array.isArray(next[0]) ?
                                                next : [next]);

    const keyValues = zip(this.travTemplate.paths(), this.travTemplate.nodes())
                      .map(([k, v]) => [kToken(k), vToken(v)])
                      .filter(availableNode)
                      .map(toFile)
                      .filter((e) => Boolean(e))
                      .reduce(flatten, []);
    return new Map(keyValues);
  }

  /**
   * get the element at specified path, excluding paths map to other file
   * @access private
   * @param {Traverse} travSrc - specify traversed source object to map
   * @param {string[]} parentPath - specify array of string keys from the root to the target node
   * @return {object} the element excluded mapped values
   */
  _getUnmapped(travSrc, parentPath) {
    function nextOfParent(p) {
      // parent: ["path", "to", "parent"]
      // p:      ["path", "to", "parent", "next"]
      // => return "next"
      if (p.length === parentPath.length + 1 &&
          p.every((e, i) =>
            e === parentPath[i] || i === p.length - 1)) {
        return p[p.length - 1];
      } else {
        return null;
      }
    }

    const parent = travSrc.get(parentPath);
    const copy = Object.assign({}, parent);

    // remove mapped values
    this.travTemplate.paths().map(nextOfParent)
                             .filter((key) => key && !kToken(key).isMeta)
                             .forEach((mappedKey) => delete copy[mappedKey]);
    return copy;
  }
}
<|endoftext|>


<commit_before>var twitter = require('twitter');
var client = new twitter({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token_key: process.env.TWITTER_ACCESS_TOKEN,
  access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
});

var fs = require('fs')
var utility = require('../api/helpers/utilities.js')

// checkDataType parses the tweet object to find any matching influencers, hashtags, or mentions and then returns an array of each found in the tweet
var checkDataType = function(tweet, trackers) {
  var mentions = tweet.entities.user_mentions;
  var hashtags = tweet.entities.hashtags;

  // console.log(mentions)

  for(var i = 0; i < trackers.length; i++) {
    if(trackers[i].type === "influencer" && tweet.user.screen_name.toLowerCase() === trackers[i].name && tweet.text.trim()[0] !== '@') {
        return {tweet: tweet, tracker: trackers[i]}
    } else if(trackers[i].type === "mention" && mentions.length > 0 && !('retweeted_status' in tweet)) {
        for(var j = 0; j < mentions.length; j++) {
            if(trackers[i].name === mentions[j].screen_name.toLowerCase()) {
                return {tweet: tweet, tracker: trackers[i]}
            }
        }
    } else if(trackers[i].type === "hashtag" && hashtags.length > 0 && !('retweeted_status' in tweet)) {
        for(var j = 0; j < hashtags.length; j++) {
            if(trackers[i].name === hashtags[j].text.toLowerCase()) {
                return {tweet: tweet, tracker: trackers[i]}
            }
        }
    }

  }
  return false;
}

var runTwitterstream = function() {
    Tracker.find().populateAll().exec(function(err, trackers) {
        if(!err) {
            var track = {};

            trackers.forEach(function(t) {
              if(t.twitter_accounts.length > 0) {
                if(t.type == "influencer") {
                    if(track.follow) {
                      track.follow += ',' + t.twitter_id;
                    } else {
                      track.follow = t.twitter_id.toString();
                    }
                } else {
                    if(track.track) {
                      track.track += ',' + t.name;
                    } else {
                      track.track = t.name;
                    }
                }
              }
            });

            if(Object.keys(track).length === 0) {
              track.track ='inclusivedesign';
            }

            client.stream('statuses/filter', track, function(stream) {
              stream.on('data', function(tweet) {
                console.log(tweet.text);
                var trackerData = checkDataType(tweet, trackers);
                console.log("Tracker Data:",trackerData !== null)
                if(trackerData) {
                    async.each(trackerData.tracker.twitter_accounts ,function(account, callback) {
                        Twitter_Account.findOne({id: account.id}).populate('user').exec(function(err, account) {
                            if(!err && account && account.user && account.user.emailToggle) {
                                console.log("sending email...",account)
                                callback(utility.sendEmail(account.user.email, "[TwitterMafiaApp] You have new updates!", trackerData, false));
                            } else if(err) {
                                callback(err)
                            }else if (!account.user.emailToggle) {
                              console.log('email was not sent!')
                            }
                        });
                    });
                }
                console.log("*************************************\n\n");
              });

              stream.on('error', function(error) {
                console.log("ERROR!!",error);
                runTwitterstream();
              });
            });
        }
    });
}

module.exports.twitterstream = function() {
  runTwitterstream();
}<commit_msg>Added timeout to twitterstream reconnect<commit_after>var twitter = require('twitter');
var client = new twitter({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token_key: process.env.TWITTER_ACCESS_TOKEN,
  access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
});

var fs = require('fs')
var utility = require('../api/helpers/utilities.js')

// checkDataType parses the tweet object to find any matching influencers, hashtags, or mentions and then returns an array of each found in the tweet
var checkDataType = function(tweet, trackers) {
  var mentions = tweet.entities.user_mentions;
  var hashtags = tweet.entities.hashtags;

  // console.log(mentions)

  for(var i = 0; i < trackers.length; i++) {
    if(trackers[i].type === "influencer" && tweet.user.screen_name.toLowerCase() === trackers[i].name && tweet.text.trim()[0] !== '@') {
        return {tweet: tweet, tracker: trackers[i]}
    } else if(trackers[i].type === "mention" && mentions.length > 0 && !('retweeted_status' in tweet)) {
        for(var j = 0; j < mentions.length; j++) {
            if(trackers[i].name === mentions[j].screen_name.toLowerCase()) {
                return {tweet: tweet, tracker: trackers[i]}
            }
        }
    } else if(trackers[i].type === "hashtag" && hashtags.length > 0 && !('retweeted_status' in tweet)) {
        for(var j = 0; j < hashtags.length; j++) {
            if(trackers[i].name === hashtags[j].text.toLowerCase()) {
                return {tweet: tweet, tracker: trackers[i]}
            }
        }
    }

  }
  return false;
}

var runTwitterstream = function() {
    Tracker.find().populateAll().exec(function(err, trackers) {
        if(!err) {
            var track = {};

            trackers.forEach(function(t) {
              if(t.twitter_accounts.length > 0) {
                if(t.type == "influencer") {
                    if(track.follow) {
                      track.follow += ',' + t.twitter_id;
                    } else {
                      track.follow = t.twitter_id.toString();
                    }
                } else {
                    if(track.track) {
                      track.track += ',' + t.name;
                    } else {
                      track.track = t.name;
                    }
                }
              }
            });

            if(Object.keys(track).length === 0) {
              track.track ='inclusivedesign';
            }

            client.stream('statuses/filter', track, function(stream) {
              stream.on('data', function(tweet) {
                console.log(tweet.text);
                var trackerData = checkDataType(tweet, trackers);
                console.log("Tracker Data:",trackerData !== null)
                if(trackerData) {
                    async.each(trackerData.tracker.twitter_accounts ,function(account, callback) {
                        Twitter_Account.findOne({id: account.id}).populate('user').exec(function(err, account) {
                            if(!err && account && account.user && account.user.emailToggle) {
                                console.log("sending email...",account)
                                callback(utility.sendEmail(account.user.email, "[TwitterMafiaApp] You have new updates!", trackerData, false));
                            } else if(err) {
                                callback(err)
                            }else if (!account.user.emailToggle) {
                              console.log('email was not sent!')
                            }
                        });
                    });
                }
                console.log("*************************************\n\n");
              });

              stream.on('error', function(error) {
                console.log("ERROR!!",error);
                setTimeout(runTwitterstream, 3000);
              });
            });
        }
    });
}

module.exports.twitterstream = function() {
  runTwitterstream();
}<|endoftext|>


<commit_before>var twitter = require('twitter');
var client = new twitter({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token_key: process.env.TWITTER_ACCESS_TOKEN,
  access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
});

var fs = require('fs')
var utility = require('../api/helpers/utilities.js')

// checkDataType parses the tweet object to find any matching influencers, hashtags, or mentions and then returns an array of each found in the tweet
var checkDataType = function(tweet, trackers) {
  var mentions = tweet.entities.user_mentions;
  var hashtags = tweet.entities.hashtags;

  // console.log(mentions)

  for(var i = 0; i < trackers.length; i++) {
    if(trackers[i].type === "influencer" && tweet.user.screen_name.toLowerCase() === trackers[i].name && tweet.text.trim()[0] !== '@') {
        return {tweet: tweet, tracker: trackers[i]}
    } else if(trackers[i].type === "mention" && mentions.length > 0 && !('retweeted_status' in tweet)) {
        for(var j = 0; j < mentions.length; j++) {
            if(trackers[i].name === mentions[j].screen_name.toLowerCase()) {
                return {tweet: tweet, tracker: trackers[i]}
            }
        }
    } else if(trackers[i].type === "hashtag" && hashtags.length > 0 && !('retweeted_status' in tweet)) {
        for(var j = 0; j < hashtags.length; j++) {
            if(trackers[i].name === hashtags[j].text.toLowerCase()) {
                return {tweet: tweet, tracker: trackers[i]}
            }
        }
    }

  }
  return false;
}

var runTwitterstream = function() {
    Tracker.find().populateAll().exec(function(err, trackers) {
        if(!err) {
            var track = {};

            trackers.forEach(function(t) {
              if(t.twitter_accounts.length > 0) {
                if(t.type == "influencer") {
                    if(track.follow) {
                      track.follow += ',' + t.twitter_id;
                    } else {
                      track.follow = t.twitter_id.toString();
                    }
                } else {
                    if(track.track) {
                      track.track += ',' + t.name;
                    } else {
                      track.track = t.name;
                    }
                }
              }
            });

            if(Object.keys(track).length === 0) {
              track.track ='inclusivedesign';
            }

            client.stream('statuses/filter', track, function(stream) {
              stream.on('data', function(tweet) {
                console.log(tweet.text);
                var trackerData = checkDataType(tweet, trackers);
                console.log("Tracker Data:",trackerData !== null)
                if(trackerData) {
                    async.each(trackerData.tracker.twitter_accounts ,function(account, callback) {
                        Twitter_Account.findOne({id: account.id}).populate('user').exec(function(err, account) {
                            if(!err && account && account.user && account.user.emailToggle) {
                                console.log("sending email...",account)
                                callback(utility.sendEmail(account.user.email, "[TwitterMafiaApp] You have new updates!", trackerData, false));
                            } else if(err) {
                                callback(err)
                            }else if (!account.user.emailToggle) {
                              console.log('email was not sent!')
                            }
                        });
                    });
                }
                console.log("*************************************\n\n");
              });

              stream.on('error', function(error) {
                console.log("ERROR!!",error);
                setTimeout(runTwitterstream, 90000);
              });
            });
        }
    });
}

module.exports.twitterstream = function() {
  runTwitterstream();
}<commit_msg>Improved error message<commit_after>var twitter = require('twitter');
var client = new twitter({
  consumer_key: process.env.TWITTER_CONSUMER_KEY,
  consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
  access_token_key: process.env.TWITTER_ACCESS_TOKEN,
  access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
});

var fs = require('fs')
var utility = require('../api/helpers/utilities.js')

// checkDataType parses the tweet object to find any matching influencers, hashtags, or mentions and then returns an array of each found in the tweet
var checkDataType = function(tweet, trackers) {
  var mentions = tweet.entities.user_mentions;
  var hashtags = tweet.entities.hashtags;

  // console.log(mentions)

  for(var i = 0; i < trackers.length; i++) {
    if(trackers[i].type === "influencer" && tweet.user.screen_name.toLowerCase() === trackers[i].name && tweet.text.trim()[0] !== '@') {
        return {tweet: tweet, tracker: trackers[i]}
    } else if(trackers[i].type === "mention" && mentions.length > 0 && !('retweeted_status' in tweet)) {
        for(var j = 0; j < mentions.length; j++) {
            if(trackers[i].name === mentions[j].screen_name.toLowerCase()) {
                return {tweet: tweet, tracker: trackers[i]}
            }
        }
    } else if(trackers[i].type === "hashtag" && hashtags.length > 0 && !('retweeted_status' in tweet)) {
        for(var j = 0; j < hashtags.length; j++) {
            if(trackers[i].name === hashtags[j].text.toLowerCase()) {
                return {tweet: tweet, tracker: trackers[i]}
            }
        }
    }

  }
  return false;
}

var runTwitterstream = function() {
    Tracker.find().populateAll().exec(function(err, trackers) {
        if(!err) {
            var track = {};

            trackers.forEach(function(t) {
              if(t.twitter_accounts.length > 0) {
                if(t.type == "influencer") {
                    if(track.follow) {
                      track.follow += ',' + t.twitter_id;
                    } else {
                      track.follow = t.twitter_id.toString();
                    }
                } else {
                    if(track.track) {
                      track.track += ',' + t.name;
                    } else {
                      track.track = t.name;
                    }
                }
              }
            });

            if(Object.keys(track).length === 0) {
              track.track ='inclusivedesign';
            }

            client.stream('statuses/filter', track, function(stream) {
              stream.on('data', function(tweet) {
                console.log(tweet.text);
                var trackerData = checkDataType(tweet, trackers);
                console.log("Tracker Data:",trackerData !== null)
                if(trackerData) {
                    async.each(trackerData.tracker.twitter_accounts ,function(account, callback) {
                        Twitter_Account.findOne({id: account.id}).populate('user').exec(function(err, account) {
                            if(!err && account && account.user && account.user.emailToggle) {
                                console.log("sending email...",account)
                                callback(utility.sendEmail(account.user.email, "[TwitterMafiaApp] You have new updates!", trackerData, false));
                            } else if(err) {
                                callback(err)
                            }else if (!account.user.emailToggle) {
                              console.log('email was not sent!')
                            }
                        });
                    });
                }
                console.log("*************************************\n\n");
              });

              stream.on('error', function(error) {
                console.log("ERROR!!",error);
                console.log("DATA sent:",track);
                setTimeout(runTwitterstream, 90000);
              });
            });
        }
    });
}

module.exports.twitterstream = function() {
  runTwitterstream();
}<|endoftext|>


<commit_before>var webpack = require( 'webpack' );
var path = require( 'path' );
const hotMiddlewareScript = 'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true';

module.exports = {
    context: __dirname,
    devtool: "source-map-loader",
    resolve: {
        extensions: [ "", ".webpack.js", ".web.js", ".ts", ".tsx", ".js" ]
    },
    entry: {
        main: [ "./index.tsx" ],
        vendor: [ "react", "react-dom" ]
    },
    output: {
        publicPath: "/",
        path: path.resolve( path.join( 'build', 'resources', 'assets' ) ),
        filename: "javascript/[name].bundle.js",
        chunkFilename: 'javascript/[name].chunk.js'
    },
    target: 'web',
    module: {
        loaders: [
            {
                test: /\.tsx?$/,
                exclude: /node_modules/,
                loader: 'babel-loader!ts-loader'
            },
            {
                test: /\.css$/,
                loader: 'style!css!'
            },
            {
                test: /\.scss$/,
                loader: 'style!css!sass!'
            },
            {
                test: /\.jpg$/,
                loader: 'url-loader?mimetype=image/jpeg&limit=100000&name=images/img-[name].[ext]'
            }
        ]
    },
    plugins: [
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.NoErrorsPlugin()
    ]
};<commit_msg>Removed useless hotreload string<commit_after>var webpack = require( 'webpack' );
var path = require( 'path' );

module.exports = {
    context: __dirname,
    devtool: "source-map-loader",
    resolve: {
        extensions: [ "", ".webpack.js", ".web.js", ".ts", ".tsx", ".js" ]
    },
    entry: {
        main: [ "./index.tsx" ],
        vendor: [ "react", "react-dom" ]
    },
    output: {
        publicPath: "/",
        path: path.resolve( path.join( 'build', 'resources', 'assets' ) ),
        filename: "javascript/[name].bundle.js",
        chunkFilename: 'javascript/[name].chunk.js'
    },
    target: 'web',
    module: {
        loaders: [
            {
                test: /\.tsx?$/,
                exclude: /node_modules/,
                loader: 'babel-loader!ts-loader'
            },
            {
                test: /\.css$/,
                loader: 'style!css!'
            },
            {
                test: /\.scss$/,
                loader: 'style!css!sass!'
            },
            {
                test: /\.jpg$/,
                loader: 'url-loader?mimetype=image/jpeg&limit=100000&name=images/img-[name].[ext]'
            }
        ]
    },
    plugins: [
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.NoErrorsPlugin()
    ]
};<|endoftext|>


<commit_before>"use strict";

var strValidator = require('validator');
var _ = require('lodash');

var defaultValidators = {
  len: function (value, rule) {
    var result = false;
    if (strValidator.isInt(rule.len)) {
      result = strValidator.isLength(value, rule.len);
    } else if (isArrayOfLength(rule.len, 2)) {
      result = strValidator.isLength(value, rule.len[0], rule.len[1]);
    }
    return result;
  },
  empty: function (value, rule) {
    var shouldBeEmpty = !!rule.empty;
    return shouldBeEmpty ? _.isEmpty(value) : !_.isEmpty(value);
  }
};

var defaultMessages = {
  len: function (value, rule) {
    var msg = 'Invalid len';

    if (strValidator.isInt(rule.len)) {
      msg = 'Expected min ' + rule.len + ' symbols';
    } else if (isArrayOfLength(rule.len, 2)) {
      msg = 'Expected [' + rule.len[0] + ',' + rule.len[1] + ']  symbols.';
    }

    msg += ' Given: ' + value.length;

    return msg;
  },
  required: 'Is undefined',
  empty: 'Is empty',
  arrayMiss: function(value, rule) {
    return 'Some of [' + rule.name.join(',') + '] not exist';
  },
  default: 'Error'
};

var defaultOptions = {
  required: true,
  findFirst: true,
  short: true
};

function validate(value, rule, options) {
  var isRequired = _.isUndefined(rule.required) ? options.required : rule.required;
  var isFindFirst = _.isUndefined(rule.findFirst) ? options.findFirst : rule.findFirst;
  var isShort = _.isUndefined(rule.short) ? options.short : rule.short;
  var errors = {};
  var validators = [];

  if (_.isUndefined(value))
    return isRequired ? makeRequiredError(createMessage('arrayMiss', value, rule), isShort) : {};

  if (_.isArray(rule.name) && _.isArray(value) && _.some(value, function (val) {
    return _.isUndefined(val);
  })) return isRequired ? makeRequiredError(createMessage('arrayMiss', value, rule), isShort) : {};

  _.forOwn(rule, function (ruleValue, ruleName){
    if (!_.isUndefined(defaultValidators[ruleName])) {
      validators.push([ruleName, defaultValidators[ruleName]]);
    }
  });

  _.forOwn(rule.custom, function (validatorFunc, validatorName) {
    if (_.isFunction(validatorFunc)) {
      validators.push([validatorName, validatorFunc]);
    }
  });

  for (var i = 0; i < validators.length; i++) {
    var validatorName = validators[i][0];
    var validatorFunc = validators[i][1];
    var result = validatorFunc(value, rule);
    if (!result) {
      if (isShort) return createMessage(validatorName, value, rule);
      errors[validatorName] = createMessage(validatorName, value, rule);
    }
    if (_.size(errors) && isFindFirst) break;
  }

  return errors;
}

function makeRequiredError(message, isShort) {
  return isShort ? message : {name : message};
}

function createMessage(validatorName, value, rule) {
  var message;
  if (_.isObject(rule.msg) && !_.isUndefined(rule.msg[validatorName])) {
    message = rule.msg[validatorName];
  } else if (!_.isUndefined(defaultMessages[validatorName])) {
    message = defaultMessages[validatorName];
  } else {
    message = defaultMessages['default'];
  }

  if (_.isFunction(message))
    return message(value, rule);
  else if (_.isString(message))
    return message;
}

function isArrayOfLength(obj, len) {
  return _.isArray(obj) && obj.length === len;
}

function arrayFromKeysOf(keys, of) {
  var value = [];
  for (var i = 0; i < keys.length; i++) {
    var keyName = keys[i];
    value.push(of[keyName]);
  }
  return value;
}

function validateRule(toCheck, rule, options) {
  var value;

  if (_.isArray(rule.name)) {
    value = arrayFromKeysOf(rule.name, toCheck);
  } else {
    value = toCheck[rule.name];
  }
  var errors = validate(value, rule, options);
  return _.isEmpty(errors) ? null : errors;
}

function fillOptions(opt) {
  var result = {};
  _.forOwn(defaultOptions, function(value, name) {
    result[name] = _.isUndefined(opt[name]) ? value : opt[name];
  });
  return result;
}

module.exports = function (objectToCheck, rules, opt) {
  var errors = {};
  var options = _.isUndefined(opt)
    ? defaultOptions
    : fillOptions(opt);

  for (var i = 0; i < rules.length; i++) {
    var rule = rules[i];
    var error = validateRule(objectToCheck, rule, options);
    if (error === null) continue;

    if (_.isArray(rule.name)) {
      for (var j = 0; j < rule.name.length; j++) {
        errors[rule.name[j]] = error;
      }
    } else {
      errors[rule.name] = error;
    }
  }

  return errors;
};<commit_msg>fix bug with required message<commit_after>"use strict";

var strValidator = require('validator');
var _ = require('lodash');

var defaultValidators = {
  len: function (value, rule) {
    var result = false;
    if (strValidator.isInt(rule.len)) {
      result = strValidator.isLength(value, rule.len);
    } else if (isArrayOfLength(rule.len, 2)) {
      result = strValidator.isLength(value, rule.len[0], rule.len[1]);
    }
    return result;
  },
  empty: function (value, rule) {
    var shouldBeEmpty = !!rule.empty;
    return shouldBeEmpty ? _.isEmpty(value) : !_.isEmpty(value);
  }
};

var defaultMessages = {
  len: function (value, rule) {
    var msg = 'Invalid len';

    if (strValidator.isInt(rule.len)) {
      msg = 'Expected min ' + rule.len + ' symbols';
    } else if (isArrayOfLength(rule.len, 2)) {
      msg = 'Expected [' + rule.len[0] + ',' + rule.len[1] + ']  symbols.';
    }

    msg += ' Given: ' + value.length;

    return msg;
  },
  required: 'Is undefined',
  empty: 'Is empty',
  arrayMiss: function(value, rule) {
    return 'Some of [' + rule.name.join(',') + '] not exist';
  },
  default: 'Error'
};

var defaultOptions = {
  required: true,
  findFirst: true,
  short: true
};

function validate(value, rule, options) {
  var isRequired = _.isUndefined(rule.required) ? options.required : rule.required;
  var isFindFirst = _.isUndefined(rule.findFirst) ? options.findFirst : rule.findFirst;
  var isShort = _.isUndefined(rule.short) ? options.short : rule.short;
  var errors = {};
  var validators = [];

  if (_.isUndefined(value))
    return isRequired ? makeRequiredError(createMessage('required', value, rule), isShort) : {};

  if (_.isArray(rule.name) && _.isArray(value) && _.some(value, function (val) {
    return _.isUndefined(val);
  })) return isRequired ? makeRequiredError(createMessage('arrayMiss', value, rule), isShort) : {};

  _.forOwn(rule, function (ruleValue, ruleName){
    if (!_.isUndefined(defaultValidators[ruleName])) {
      validators.push([ruleName, defaultValidators[ruleName]]);
    }
  });

  _.forOwn(rule.custom, function (validatorFunc, validatorName) {
    if (_.isFunction(validatorFunc)) {
      validators.push([validatorName, validatorFunc]);
    }
  });

  for (var i = 0; i < validators.length; i++) {
    var validatorName = validators[i][0];
    var validatorFunc = validators[i][1];
    var result = validatorFunc(value, rule);
    if (!result) {
      if (isShort) return createMessage(validatorName, value, rule);
      errors[validatorName] = createMessage(validatorName, value, rule);
    }
    if (_.size(errors) && isFindFirst) break;
  }

  return errors;
}

function makeRequiredError(message, isShort) {
  return isShort ? message : {name : message};
}

function createMessage(validatorName, value, rule) {
  var message;
  if (_.isObject(rule.msg) && !_.isUndefined(rule.msg[validatorName])) {
    message = rule.msg[validatorName];
  } else if (!_.isUndefined(defaultMessages[validatorName])) {
    message = defaultMessages[validatorName];
  } else {
    message = defaultMessages['default'];
  }

  if (_.isFunction(message))
    return message(value, rule);
  else if (_.isString(message))
    return message;
}

function isArrayOfLength(obj, len) {
  return _.isArray(obj) && obj.length === len;
}

function arrayFromKeysOf(keys, of) {
  var value = [];
  for (var i = 0; i < keys.length; i++) {
    var keyName = keys[i];
    value.push(of[keyName]);
  }
  return value;
}

function validateRule(toCheck, rule, options) {
  var value;

  if (_.isArray(rule.name)) {
    value = arrayFromKeysOf(rule.name, toCheck);
  } else {
    value = toCheck[rule.name];
  }
  var errors = validate(value, rule, options);
  return _.isEmpty(errors) ? null : errors;
}

function fillOptions(opt) {
  var result = {};
  _.forOwn(defaultOptions, function(value, name) {
    result[name] = _.isUndefined(opt[name]) ? value : opt[name];
  });
  return result;
}

module.exports = function (objectToCheck, rules, opt) {
  var errors = {};
  var options = _.isUndefined(opt)
    ? defaultOptions
    : fillOptions(opt);

  for (var i = 0; i < rules.length; i++) {
    var rule = rules[i];
    var error = validateRule(objectToCheck, rule, options);
    if (error === null) continue;

    if (_.isArray(rule.name)) {
      for (var j = 0; j < rule.name.length; j++) {
        errors[rule.name[j]] = error;
      }
    } else {
      errors[rule.name] = error;
    }
  }

  return errors;
};<|endoftext|>


<commit_before>/**
 *  Vic Shóstak <vikkyshostak@gmail.com>
 *  Copyright (c) 2019 True web artisans https://truewebartisans.com
 *  http://opensource.org/licenses/MIT The MIT License (MIT)
 *
 *  goodshare.js v6.0.1 at 18/03/2019
 *
 *  Useful modern JavaScript solution for share a link from your website
 *  to social networks or mobile messengers. Easy to install and configuring
 *  on any of your website!
 */

/**
 *  Import social networks providers with share counter.
 */
import { Vkontakte } from "./providers/Vkontakte";
import { Facebook } from "./providers/Facebook";
import { Odnoklassniki } from "./providers/Odnoklassniki";
import { MoiMir } from "./providers/MoiMir";
import { LinkedIn } from "./providers/LinkedIn";
import { Tumblr } from "./providers/Tumblr";
import { Pinterest } from "./providers/Pinterest";
import { Surfingbird } from "./providers/Surfingbird";
import { Reddit } from "./providers/Reddit";
import { Buffer } from "./providers/Buffer";
import { StumbleUpon } from "./providers/StumbleUpon";
import { Pocket } from "./providers/Pocket";
import { Xing } from "./providers/Xing";

/**
 *  Import social networks providers without share counter.
 */

import { GooglePlus } from "./providers/GooglePlus";
import { Twitter } from "./providers/Twitter";
import { LiveJournal } from "./providers/LiveJournal";
import { Evernote } from "./providers/Evernote";
import { Delicious } from "./providers/Delicious";
import { Blogger } from "./providers/Blogger";
import { Instapaper } from "./providers/Instapaper";
import { Digg } from "./providers/Digg";
import { LiveInternet } from "./providers/LiveInternet";
import { WordPress } from "./providers/WordPress";
import { Baidu } from "./providers/Baidu";
import { RenRen } from "./providers/RenRen";
import { Weibo } from "./providers/Weibo";

/**
 *  Import mobile messengers providers.
 */

import { SMS } from "./providers/SMS";
import { Skype } from "./providers/Skype";
import { Telegram } from "./providers/Telegram";
import { Viber } from "./providers/Viber";
import { WhatsApp } from "./providers/WhatsApp";
import { Line } from "./providers/Line";

const providers = [
  // Import social networks providers with share counter.
  Vkontakte,
  Facebook,
  Odnoklassniki,
  MoiMir,
  LinkedIn,
  Tumblr,
  Pinterest,
  Surfingbird,
  Reddit,
  Buffer,
  StumbleUpon,
  Pocket,
  Xing,
  // Import social networks providers without share counter.
  GooglePlus,
  Twitter,
  LiveJournal,
  Evernote,
  Delicious,
  Blogger,
  Instapaper,
  Digg,
  LiveInternet,
  WordPress,
  Baidu,
  RenRen,
  Weibo,
  // Import mobile messengers providers.
  SMS,
  Skype,
  Telegram,
  Viber,
  WhatsApp,
  Line
];

class Goodshare {
  constructor() {
    this.providers = providers;
    this.getProviders();
  }

  setShareCallback(callback) {
    this.providers = this.providers.map(shareProvider =>
      shareProvider.setShareCallback(callback)
    );
  }

  getProviders() {
    this.providers = this.providers.map(shareProvider =>
      new shareProvider().getInstance()
    );

    return this.providers;
  }

  reNewAllInstance() {
    this.providers = this.providers.map(shareProvider =>
      shareProvider.reNewInstance()
    );
  }
}

(function() {
  window._goodshare = new Goodshare();
})();
<commit_msg>Update goodshare.js<commit_after>/**
 *  Vic Shóstak <vikkyshostak@gmail.com>
 *  Copyright (c) 2019 True web artisans https://truewebartisans.com
 *  http://opensource.org/licenses/MIT The MIT License (MIT)
 *
 *  goodshare.js v6.0.2 at 18/03/2019
 *
 *  Useful modern JavaScript solution for share a link from your website
 *  to social networks or mobile messengers. Easy to install and configuring
 *  on any of your website!
 */

/**
 *  Import social networks providers with share counter.
 */
import { Vkontakte } from "./providers/Vkontakte";
import { Facebook } from "./providers/Facebook";
import { Odnoklassniki } from "./providers/Odnoklassniki";
import { MoiMir } from "./providers/MoiMir";
import { LinkedIn } from "./providers/LinkedIn";
import { Tumblr } from "./providers/Tumblr";
import { Pinterest } from "./providers/Pinterest";
import { Surfingbird } from "./providers/Surfingbird";
import { Reddit } from "./providers/Reddit";
import { Buffer } from "./providers/Buffer";
import { StumbleUpon } from "./providers/StumbleUpon";
import { Pocket } from "./providers/Pocket";
import { Xing } from "./providers/Xing";

/**
 *  Import social networks providers without share counter.
 */

import { GooglePlus } from "./providers/GooglePlus";
import { Twitter } from "./providers/Twitter";
import { LiveJournal } from "./providers/LiveJournal";
import { Evernote } from "./providers/Evernote";
import { Delicious } from "./providers/Delicious";
import { Blogger } from "./providers/Blogger";
import { Instapaper } from "./providers/Instapaper";
import { Digg } from "./providers/Digg";
import { LiveInternet } from "./providers/LiveInternet";
import { WordPress } from "./providers/WordPress";
import { Baidu } from "./providers/Baidu";
import { RenRen } from "./providers/RenRen";
import { Weibo } from "./providers/Weibo";

/**
 *  Import mobile messengers providers.
 */

import { SMS } from "./providers/SMS";
import { Skype } from "./providers/Skype";
import { Telegram } from "./providers/Telegram";
import { Viber } from "./providers/Viber";
import { WhatsApp } from "./providers/WhatsApp";
import { Line } from "./providers/Line";

const providers = [
  // Import social networks providers with share counter.
  Vkontakte,
  Facebook,
  Odnoklassniki,
  MoiMir,
  LinkedIn,
  Tumblr,
  Pinterest,
  Surfingbird,
  Reddit,
  Buffer,
  StumbleUpon,
  Pocket,
  Xing,
  // Import social networks providers without share counter.
  GooglePlus,
  Twitter,
  LiveJournal,
  Evernote,
  Delicious,
  Blogger,
  Instapaper,
  Digg,
  LiveInternet,
  WordPress,
  Baidu,
  RenRen,
  Weibo,
  // Import mobile messengers providers.
  SMS,
  Skype,
  Telegram,
  Viber,
  WhatsApp,
  Line
];

class Goodshare {
  constructor() {
    this.providers = providers;
    this.getProviders();
  }

  setShareCallback(callback) {
    this.providers = this.providers.map(shareProvider =>
      shareProvider.setShareCallback(callback)
    );
  }

  getProviders() {
    this.providers = this.providers.map(shareProvider =>
      new shareProvider().getInstance()
    );

    return this.providers;
  }

  reNewAllInstance() {
    this.providers = this.providers.map(shareProvider =>
      shareProvider.reNewInstance()
    );
  }
}

(function() {
  window._goodshare = new Goodshare();
})();
<|endoftext|>


<commit_before>/*
 * Jakefile for Rimu Markup (http://github.com/srackham/rimu).
 */
'use strict';

var pkg = require('./package.json');
var shelljs = require('shelljs');
var child_process = require('child_process');

/* Inputs and outputs */

var RIMU_JS = 'bin/rimu.js';  // HTML script library format.
var RIMU_MIN_JS = 'bin/rimu.min.js';
var RIMU_COMMONJS2_JS = 'bin/rimu-commonjs2.js';  // CommonJS library format.
var RIMU_COMMONJS2_MIN_JS = 'bin/rimu-commonjs2.min.js';
var MAIN_TS = 'src/main.ts';
var MAIN_JS = 'out/main.js';
var SOURCE = shelljs.ls('src/*.ts');
var TESTS = shelljs.ls('test/*.js');
var TYPEDOC_DIR = 'doc/api';
var TYPEDOC_INDEX = TYPEDOC_DIR + '/index.html';
var GH_PAGES_DIR = './gh-pages/';

var DOCS = [
  {src: 'README.md', dst: 'doc/index.html', title: 'Rimu Markup'},
  {src: 'doc/tips.rmu', dst: 'doc/tips.html', title: 'Rimu Tips'}
];

var HTML = ['bin/rimuplayground.html'];
DOCS.forEach(function(doc) {
  HTML.push(doc.dst);
});

/* Utility functions. */

/*
 Execute shell commands in parallel then run the callback when they have all finished.
 `callback` defaults to the Jake async `complete` function.
 Abort if an error occurs.
 Write command output to the inherited stdout (unless the Jake --quiet option is set).
 Print a status message when each command starts and finishes (unless the Jake --quiet option is set).

 NOTE: This function is similar to the built-in jake.exec function but is twice as fast.
 */
function exec(commands, callback) {
  if (typeof commands === 'string') {
    commands = [commands];
  }
  callback = callback || complete;
  var remaining = commands.length;
  if (remaining === 0) {
    callback();
  } else {
    commands.forEach(function(command) {
      jake.logger.log('Starting: ' + command);
      child_process.exec(command, function(error, stdout, stderr) {
        if (!jake.program.opts.quiet) {
          process.stdout.write(stdout);
        }
        if (error !== null) {
          fail(error, error.code);
        }
        jake.logger.log('Finished: ' + command);
        remaining--;
        if (remaining === 0) {
          callback();
        }
      });
    });
  }
}

/*
 Tasks

 All tasks are synchronous (another task will not run until the current task has completed).
 Consequently all task dependencies are executed asynchronously in declaration order.
 The `exec` function ensures shell commands within each task run in parallel.
 */

desc('Run test task.');
task('default', ['test']);

desc('compile, jslint, test, tslint, build-gh-pages, validate-html.');
task('build', ['test', 'tslint', 'build-gh-pages', 'validate-html']);

desc('Update version number, tag and push to Github and npm. Use vers=x.y.z argument to set a new version number. Finally, rebuild and publish docs website.');
task('release', ['build', 'version', 'tag', 'publish', 'release-gh-pages']);

desc('Lint Javascript and JSON files.');
task('jslint', {async: true}, function() {
  var commands = TESTS.map(function(file) {
    return 'jshint ' + file;
  });
  commands.push('jsonlint --quiet package.json');
  exec(commands);
});

desc('Lint TypeScript source files.');
task('tslint', {async: true}, function() {
  var commands = SOURCE.map(function(file) {
    return 'tslint -f ' + file;
  });
  exec(commands);
});

desc('Run tests (recompile if necessary).');
task('test', ['compile', 'jslint'], {async: true}, function() {
  var commands = TESTS.map(function(file) {
    return 'nodeunit ' + file;
  });
  exec(commands);
});

desc('Compile Typescript to JavaScript then bundle CommonJS and scriptable libraries.');
task('compile', [MAIN_JS, RIMU_JS, RIMU_COMMONJS2_JS, RIMU_MIN_JS, RIMU_COMMONJS2_MIN_JS]);

file(MAIN_JS, SOURCE, {async: true}, function() {
  exec('tsc --module commonjs --outDir ./out ' + MAIN_TS);
});

file(RIMU_COMMONJS2_JS, MAIN_JS, {async: true}, function() {
  exec('webpack');
});

file(RIMU_JS, MAIN_JS, {async: true}, function() {
  exec('webpack --output-library-target var --output-file ' + RIMU_JS);
});

function minify(src, dst) {
  var preamble = '/* ' + pkg.name + ' ' + pkg.version + ' (' + pkg.repository.url + ') */';
  var command = 'uglifyjs  --preamble "' + preamble + '" --output ' + dst + ' ' + src;
  exec(command);
};

file(RIMU_COMMONJS2_MIN_JS, RIMU_COMMONJS2_JS, {async: true}, function() {
  minify(RIMU_COMMONJS2_JS, RIMU_COMMONJS2_MIN_JS)
});

file(RIMU_MIN_JS, RIMU_JS, {async: true}, function() {
  minify(RIMU_JS, RIMU_MIN_JS)
});

desc('Create TypeDoc API documentation.');
task('api-docs', [TYPEDOC_INDEX]);

file(TYPEDOC_INDEX, SOURCE, {async: true}, function() {
  shelljs.rm('-rf', TYPEDOC_DIR);
  exec('typedoc --out ' + TYPEDOC_DIR + ' ./src');
});

desc('Generate HTML documentation');
task('html-docs', {async: true}, function() {
  var commands = DOCS.map(function(doc) {
    return 'node ./bin/rimuc.js --output ' + doc.dst +
      ' --prepend "{--title}=\'' + doc.title + '\'"' +
      ' doc/doc-header.rmu ' + doc.src + ' doc/doc-footer.rmu';
  });
  exec(commands);
});

desc('Validate HTML documents with W3C Validator.');
task('validate-html', {async: true}, function() {
  var commands = HTML.map(function(file) {
    return 'w3cjs validate ' + file;
  });
  exec(commands);
});

desc('Display or update the project version number. Use vers=x.y.z argument to set a new version number.');
task('version', {async: true}, function() {
  var version = process.env.vers;
  if (!version) {
    console.log('\nversion: ' + pkg.version);
    complete();
  }
  else {
    if (!version.match(/^\d+\.\d+\.\d+$/)) {
      fail('Invalid version number: ' + version + '\n');
    }
    shelljs.sed('-i', /(\n\s*"version"\s*:\s*)"\d+\.\d+\.\d+"/, '$1' + '"' + version + '"', 'package.json');
    pkg.version = version;
    exec('git commit -m "Bump version number." package.json');
  }
});

desc('Create tag ' + pkg.version);
task('tag', ['test'], {async: true}, function() {
  exec('git tag -a -m "Tag ' + pkg.version + '" ' + pkg.version);
});

desc('Commit changes to local Git repo.');
task('commit', ['test'], {async: true}, function() {
  jake.exec('git commit -a', {interactive: true}, complete);
});

desc('push, publish-npm.');
task('publish', ['push', 'publish-npm']);

desc('Push local commits to Github.');
task('push', ['test'], {async: true}, function() {
  exec('git push -u --tags origin master');
});

desc('Publish to npm.');
task('publish-npm', {async: true}, ['test'], function() {
  exec('npm publish');
});

desc('Rebuild and validate documentation then commit and publish to GitHub Pages');
task('release-gh-pages', ['build-gh-pages', 'commit-gh-pages', 'push-gh-pages']);

desc('Generate documentation and copy to gh-pages repo');
task('build-gh-pages', ['html-docs', 'validate-html'], function() {
  shelljs.cp('-f', HTML.concat(RIMU_JS), GH_PAGES_DIR)
});

desc('Commit changes to local Github Pages repo. Use msg=\'commit message\' to set a custom commit message.');
task('commit-gh-pages', ['test'], {async: true}, function() {
  var msg = process.env.msg;
  if (!msg) {
    msg = 'Rebuilt project website.';
  }
  shelljs.cd(GH_PAGES_DIR);
  exec('git commit -a -m "' + msg + '"');
});

desc('Push Github Pages commits to Github.');
task('push-gh-pages', ['test'], {async: true}, function() {
  shelljs.cd(GH_PAGES_DIR);
  exec('git push origin gh-pages');
});
<commit_msg>Fix Jakefile dependencies problem.<commit_after>/*
 * Jakefile for Rimu Markup (http://github.com/srackham/rimu).
 */
'use strict';

var pkg = require('./package.json');
var shelljs = require('shelljs');
var child_process = require('child_process');

/* Inputs and outputs */

var RIMU_JS = 'bin/rimu.js';  // Script tag library format.
var RIMU_MIN_JS = 'bin/rimu.min.js';
var RIMU_COMMONJS2_JS = 'bin/rimu-commonjs2.js';  // Npm library format.
var RIMU_COMMONJS2_MIN_JS = 'bin/rimu-commonjs2.min.js';
var MAIN_TS = 'src/main.ts';
var MAIN_JS = 'out/main.js';
var SOURCE = shelljs.ls('src/*.ts');
var TESTS = shelljs.ls('test/*.js');
var TYPEDOC_DIR = 'doc/api';
var TYPEDOC_INDEX = TYPEDOC_DIR + '/index.html';
var GH_PAGES_DIR = './gh-pages/';

var DOCS = [
  {src: 'README.md', dst: 'doc/index.html', title: 'Rimu Markup'},
  {src: 'doc/tips.rmu', dst: 'doc/tips.html', title: 'Rimu Tips'}
];

var HTML = ['bin/rimuplayground.html'];
DOCS.forEach(function(doc) {
  HTML.push(doc.dst);
});

/* Utility functions. */

/*
 Execute shell commands in parallel then run the callback when they have all finished.
 `callback` defaults to the Jake async `complete` function.
 Abort if an error occurs.
 Write command output to the inherited stdout (unless the Jake --quiet option is set).
 Print a status message when each command starts and finishes (unless the Jake --quiet option is set).

 NOTE: This function is similar to the built-in jake.exec function but is twice as fast.
 */
function exec(commands, callback) {
  if (typeof commands === 'string') {
    commands = [commands];
  }
  callback = callback || complete;
  var remaining = commands.length;
  if (remaining === 0) {
    callback();
  } else {
    commands.forEach(function(command) {
      jake.logger.log('Starting: ' + command);
      child_process.exec(command, function(error, stdout, stderr) {
        if (!jake.program.opts.quiet) {
          process.stdout.write(stdout);
        }
        if (error !== null) {
          fail(error, error.code);
        }
        jake.logger.log('Finished: ' + command);
        remaining--;
        if (remaining === 0) {
          callback();
        }
      });
    });
  }
}

/*
 Tasks

 All tasks are synchronous (another task will not run until the current task has completed).
 Consequently all task dependencies are executed asynchronously in declaration order.
 The `exec` function ensures shell commands within each task run in parallel.
 */

desc('Run test task.');
task('default', ['test']);

desc('compile, jslint, test, tslint, build-gh-pages, validate-html.');
task('build', ['test', 'tslint', 'build-gh-pages', 'validate-html']);

desc('Update version number, tag and push to Github and npm. Use vers=x.y.z argument to set a new version number. Finally, rebuild and publish docs website.');
task('release', ['build', 'version', 'tag', 'publish', 'release-gh-pages']);

desc('Lint Javascript and JSON files.');
task('jslint', {async: true}, function() {
  var commands = TESTS.map(function(file) {
    return 'jshint ' + file;
  });
  commands.push('jsonlint --quiet package.json');
  exec(commands);
});

desc('Lint TypeScript source files.');
task('tslint', {async: true}, function() {
  var commands = SOURCE.map(function(file) {
    return 'tslint -f ' + file;
  });
  exec(commands);
});

desc('Run tests (recompile if necessary).');
task('test', ['compile', 'jslint'], {async: true}, function() {
  var commands = TESTS.map(function(file) {
    return 'nodeunit ' + file;
  });
  exec(commands);
});

// TODO: Fix me.
desc('Compile Typescript to JavaScript then bundle CommonJS and scriptable libraries.');
task('compile', [MAIN_JS, RIMU_JS, RIMU_COMMONJS2_JS, RIMU_MIN_JS, RIMU_COMMONJS2_MIN_JS]);

file(MAIN_JS, SOURCE, {async: true}, function() {
  exec('tsc --module commonjs --outDir ./out ' + MAIN_TS);
});

file(RIMU_COMMONJS2_JS, [MAIN_JS], {async: true}, function() {
  exec('webpack');
});

file(RIMU_JS, [MAIN_JS], {async: true}, function() {
  exec('webpack --output-library-target var --output-file ' + RIMU_JS);
});

function minify(src, dst) {
  var preamble = '/* ' + pkg.name + ' ' + pkg.version + ' (' + pkg.repository.url + ') */';
  var command = 'uglifyjs  --preamble "' + preamble + '" --output ' + dst + ' ' + src;
  exec(command);
};

file(RIMU_COMMONJS2_MIN_JS, [RIMU_COMMONJS2_JS], {async: true}, function() {
  minify(RIMU_COMMONJS2_JS, RIMU_COMMONJS2_MIN_JS)
});

file(RIMU_MIN_JS, [RIMU_JS], {async: true}, function() {
  minify(RIMU_JS, RIMU_MIN_JS)
});

desc('Create TypeDoc API documentation.');
task('api-docs', [TYPEDOC_INDEX]);

file(TYPEDOC_INDEX, SOURCE, {async: true}, function() {
  shelljs.rm('-rf', TYPEDOC_DIR);
  exec('typedoc --out ' + TYPEDOC_DIR + ' ./src');
});

desc('Generate HTML documentation');
task('html-docs', {async: true}, function() {
  var commands = DOCS.map(function(doc) {
    return 'node ./bin/rimuc.js --output ' + doc.dst +
      ' --prepend "{--title}=\'' + doc.title + '\'"' +
      ' doc/doc-header.rmu ' + doc.src + ' doc/doc-footer.rmu';
  });
  exec(commands);
});

desc('Validate HTML documents with W3C Validator.');
task('validate-html', {async: true}, function() {
  var commands = HTML.map(function(file) {
    return 'w3cjs validate ' + file;
  });
  exec(commands);
});

desc('Display or update the project version number. Use vers=x.y.z argument to set a new version number.');
task('version', {async: true}, function() {
  var version = process.env.vers;
  if (!version) {
    console.log('\nversion: ' + pkg.version);
    complete();
  }
  else {
    if (!version.match(/^\d+\.\d+\.\d+$/)) {
      fail('Invalid version number: ' + version + '\n');
    }
    shelljs.sed('-i', /(\n\s*"version"\s*:\s*)"\d+\.\d+\.\d+"/, '$1' + '"' + version + '"', 'package.json');
    pkg.version = version;
    exec('git commit -m "Bump version number." package.json');
  }
});

desc('Create tag ' + pkg.version);
task('tag', ['test'], {async: true}, function() {
  exec('git tag -a -m "Tag ' + pkg.version + '" ' + pkg.version);
});

desc('Commit changes to local Git repo.');
task('commit', ['test'], {async: true}, function() {
  jake.exec('git commit -a', {interactive: true}, complete);
});

desc('push, publish-npm.');
task('publish', ['push', 'publish-npm']);

desc('Push local commits to Github.');
task('push', ['test'], {async: true}, function() {
  exec('git push -u --tags origin master');
});

desc('Publish to npm.');
task('publish-npm', {async: true}, ['test'], function() {
  exec('npm publish');
});

desc('Rebuild and validate documentation then commit and publish to GitHub Pages');
task('release-gh-pages', ['build-gh-pages', 'commit-gh-pages', 'push-gh-pages']);

desc('Generate documentation and copy to gh-pages repo');
task('build-gh-pages', ['html-docs', 'validate-html'], function() {
  shelljs.cp('-f', HTML.concat(RIMU_JS), GH_PAGES_DIR)
});

desc('Commit changes to local Github Pages repo. Use msg=\'commit message\' to set a custom commit message.');
task('commit-gh-pages', ['test'], {async: true}, function() {
  var msg = process.env.msg;
  if (!msg) {
    msg = 'Rebuilt project website.';
  }
  shelljs.cd(GH_PAGES_DIR);
  exec('git commit -a -m "' + msg + '"');
});

desc('Push Github Pages commits to Github.');
task('push-gh-pages', ['test'], {async: true}, function() {
  shelljs.cd(GH_PAGES_DIR);
  exec('git push origin gh-pages');
});
<|endoftext|>


<commit_before>require('babel-register');
const Joi = require('joi');
const util = require('util');
const _ = require('lodash');
const hashAString = require('string-hash');

const schema = Joi.object().keys({
    a: Joi.boolean().valid(true),
    b: Joi.alternatives().try([
        Joi.string().regex(/^a/),
        Joi.string().valid('boom')
    ]),
    c: Joi.number().valid(5),
    d: Joi.string().valid('key'),
    e: Joi.object().keys({
        hi:    Joi.string(),
        hello: Joi.number()
    })
});

// Cache of validated values for each model
const validatedValues = {};

function createJoiModel(schema, defaults) {

    // Check if schema is a Joi schema
    if (!schema.isJoi && !(schema._type === 'object')) {
        throw new Error('Schema passed to joi-model2 must be a Joi schema.');
    }

    // Check if default object is valid itself
    if (defaults) {
        const validation = Joi.validate(schema, defaults);
        if (validation.error) {
            throw new Error('JoiModel default values do not validate against given schema \n' + validation.error);
        }
    }

    // Create a shadow object that
    const shadowObj = _.cloneDeep(defaults || {});

    // TODO make real random UUIDs
    const modelUUID = '12345';
    let JoiModel = {
        _UUID:      modelUUID,
        _shadowObj: shadowObj,
        _data:       {}
    };

    // Create an object to store cached values
    validatedValues[ modelUUID ] = {};

    const childrenSchemas = schema._inner.children;

    for (let childSchema of childrenSchemas) {

        const key = childSchema.key;

        Object.defineProperty(JoiModel, key, {
            enumerable: true,
            get() {
                return this._data[ key ];
            },
            set(val) {
                const _this = this;
                const hash = hashAString(JSON.stringify(val));

                // If this value has already been validated for this key before, then just set the value
                if (validatedValues[ modelUUID ][ hash ]) {
                    return _this._data[ key ] = val;
                }

                // Do the validation against the shadow object
                const oldVal = _this._data[ key ];
                _this._shadowObj[ key ] = val;
                const validation = Joi.validate(_this._shadowObj, schema);
                if (validation.error) {
                    _this._shadowObj[ key ] = oldVal;
                    throw new Error('Attempted to change a property to an invalid value: \n' + validation.error);
                }
                else {
                    // Cache the validated value
                    validatedValues[ modelUUID ][ hash ] = true;
                    return _this._data[ key ] = val;

                }
            }
        });
    }

    JoiModel.toJSON = function() {
        return this._shadowObj;
    };

    JoiModel.toString = function() {
        return this._shadowObj + '';
    };

    JoiModel.inspect = function() {
        return this._shadowObj;
    };
    return JoiModel;
}

export default createJoiModel;<commit_msg>Prevent extensions to JoiModels<commit_after>require('babel-register');
const Joi = require('joi');
const util = require('util');
const _ = require('lodash');
const hashAString = require('string-hash');

const schema = Joi.object().keys({
    a: Joi.boolean().valid(true),
    b: Joi.alternatives().try([
        Joi.string().regex(/^a/),
        Joi.string().valid('boom')
    ]),
    c: Joi.number().valid(5),
    d: Joi.string().valid('key'),
    e: Joi.object().keys({
        hi:    Joi.string(),
        hello: Joi.number()
    })
});

// Cache of validated values for each model
const validatedValues = {};

function createJoiModel(schema, defaults) {

    // Check if schema is a Joi schema
    if (!schema.isJoi && !(schema._type === 'object')) {
        throw new Error('Schema passed to joi-model2 must be a Joi schema.');
    }

    // Check if default object is valid itself
    if (defaults) {
        const validation = Joi.validate(schema, defaults);
        if (validation.error) {
            throw new Error('JoiModel default values do not validate against given schema \n' + validation.error);
        }
    }

    // Create a shadow object that
    const shadowObj = _.cloneDeep(defaults || {});

    // TODO make real random UUIDs
    const modelUUID = '12345';
    let JoiModel = {
        _UUID:      modelUUID,
        _shadowObj: shadowObj,
        _data:       {}
    };

    // Create an object to store cached values
    validatedValues[ modelUUID ] = {};

    const childrenSchemas = schema._inner.children;

    for (let childSchema of childrenSchemas) {

        const key = childSchema.key;

        Object.defineProperty(JoiModel, key, {
            enumerable: true,
            get() {
                return this._data[ key ];
            },
            set(val) {
                const _this = this;
                const hash = hashAString(JSON.stringify(val));

                // If this value has already been validated for this key before, then just set the value
                if (validatedValues[ modelUUID ][ hash ]) {
                    return _this._data[ key ] = val;
                }

                // Do the validation against the shadow object
                const oldVal = _this._data[ key ];
                _this._shadowObj[ key ] = val;
                const validation = Joi.validate(_this._shadowObj, schema);
                if (validation.error) {
                    _this._shadowObj[ key ] = oldVal;
                    throw new Error('Attempted to change a property to an invalid value: \n' + validation.error);
                }
                else {
                    // Cache the validated value
                    validatedValues[ modelUUID ][ hash ] = true;
                    return _this._data[ key ] = val;

                }
            }
        });
    }

    JoiModel.toJSON = function() {
        return this._shadowObj;
    };

    JoiModel.toString = function() {
        return this._shadowObj + '';
    };

    JoiModel.inspect = function() {
        return this._shadowObj;
    };

    // Stops the addition of new properties
    Object.preventExtensions(JoiModel);

    return JoiModel;
}

export default createJoiModel;<|endoftext|>


<commit_before>/**
 * A Gulp task for running specs using Karma.
 *
 * To use this in a gulpfile.js:
 *
 *    import SpecTask from 'carbon-factory/lib/gulp/spec';
 *    gulp.task('test', SpecTask());
 *
 * You can also pass a hash of options to customise the task:
 *
 *    import SpecTask from 'carbon-factory/lib/gulp/spec';
 *
 *    var opts = {
 *      path: "/src/*.js",
 *      specs: "/src/*.spec.js",
 *      preProcessors: [ 'babel', 'coverage', 'browserify' ],
 *      specPreProcessors: [ 'babel', 'browserify' ],
 *      coverage: {
 *        statements: 100,
 *        branches: 100,
 *        functions: 100,
 *        lines: 100
 *      },
 *      configFile: 'karma.conf.js'
 *    }
 *
 *    gulp.task('test', SpecTask(opts));
 *
 * If you have setup the task using the task name 'test' then you can run it
 * through the command line like this:
 *
 *    gulp test
 *
 * By default this will automatically run in PhantomJS and will watch for any
 * changes. You can supply additional arguments to run in alternative modes:
 *
 * == To run in watch mode with coverage reports:
 *
 *    gulp test --coverage
 *
 * == To perform a single run with coverage:
 *
 *    gulp test --build
 *
 * == To run the tests in a specific browser:
 *
 *    gulp test -b chrome
 *
 * == To run the test across all browsers:
 *
 *    gulp test -b all
 */

import gutil from 'gulp-util';
import S from 'string';
import yargs from 'yargs';
import karma from 'karma';
import istanbul from 'browserify-istanbul';
import babelify from 'babelify';
import fs from 'fs';

var argv = yargs.argv;
var Server = karma.Server;

export default function(opts) {
  var options = opts;

  return function(done) {
    var opts = options || {};
    // the js files to test (everything except __spec__ files)
    var path = opts.path || '/src/***/**/!(__spec__).js';
    // the specs
    var specs = opts.specs || '/src/***/**/__spec__.js';
    // which preprocessors the js files should run through
    var preProcessors = opts.preProcessors || [ 'eslint', 'babel', 'coverage', 'browserify' ];
    // which preprocessors the spec files should run through
    var specpreProcessors = opts.specpreProcessors || [ 'babel', 'browserify' ];
    // where to find the karma config file
    var configFile = opts.configFile || __dirname + '/karma.conf.js';
    // defaults the coverage thresholds
    var coverageThreshold = Object.assign({}, {
      statements: 100,
      branches: 100,
      functions: 100,
      lines: 100
    }, opts.coverage);

    // where the gulp task was ran from
    var originPath = process.cwd();

    // check if eslintrc file exists, if not then prompt dev to create one
    fs.stat(originPath + '/.eslintrc', function(err, stat) {
      if (err == null) { return }
      if (err.code == 'ENOENT') {
        gutil.log(gutil.colors.red("Cannot find '.eslintrc' file"));
        gutil.log(gutil.colors.white("Create an '.eslintrc' file in the root of your project and add the following code:\n{\n  \"extends\": \"./node_modules/carbon-factory/.eslintrc\"\n}"));
        process.exit();
      }
    });

    // prefix the paths with where the gulp task was ran from so the files can
    // be found from the correct location
    var src = originPath + path,
        specSrc = originPath + specs;

    // default configuration for the spec build
    var config = {
      // all the files that should be included
      files: [ src, { pattern: specSrc, watched: false, included: true, served: true } ],
      // the karma config file
      configFile: configFile,
      // the preprocessors to run the files through
      preprocessors: {},
      // which browsers to run the specs through
      browsers: [ 'PhantomJS' ],
      // options for browserify
      browserify: {
        debug: true,
        // lookup paths for any imported files
        paths: [ originPath + '/src' ],
        // configure any transforms for browserify
        transform: [
          babelify.configure({
            // only babelify files in the src directory
            ignore: /node_modules/,
            // compile experimental es7 class properties
            optional: [ "es7.classProperties" ],
            // ignore code in the coverage that babelify generates
            auxiliaryCommentBefore: "istanbul ignore next"
          }),
          istanbul({
            // ignore these files from code coverage
            ignore: [ '**/node_modules/**', '**/__spec__.js' ]
          })
        ]
      },
      // what kind of reporters should karma generate
      reporters: ['progress', 'coverage'],
      // auto watch for any changes to rerun specs
      autoWatch: true,
      // only run the specs once
      singleRun: true,
      // setup config for coverage
      coverageReporter: {
        dir: originPath + '/coverage',
        reporters: [
          { type : 'text-summary' },
          { type : 'html' }
        ],
        check: {
          global: coverageThreshold
        }
      },
      // config for eslint
      eslint: {
        stopOnError: false,
        stopOnWarning: false
      }
    }

    // tie the preprocessors to the relevant sources
    config.preprocessors[src] = preProcessors;
    config.preprocessors[specSrc] = specpreProcessors;

    if (argv.b == 'all') {
      // if `gulp -b all` then run through all browsers
      config.browsers = [ 'PhantomJS', 'Chrome', 'Firefox', 'Safari' ];
    } else if (argv.b) {
      // if `gulp -b [browser]` then use the browser supplied
      config.browsers = [ S(argv.b).capitalize().s ];
    }

    if (argv.build) {
      // if `gulp --build` then use single run mode
      config.autoWatch = false;
      // stop on lint failures in build mode
      config.eslint.stopOnError = true;
    } else {
      // default to watch mode
      config.singleRun = false;

      if (!argv.coverage) {
        // if `--coverage` is not supplied then do not run coverage in watch mode
        config.reporters = [ 'progress' ];
      }
    }

    var server = new Server(config, function(status) {
      if (status) {
        gutil.log(gutil.colors.red('UI Tests FAILED'));
      } else {
        gutil.log(gutil.colors.green('UI Tests SUCCEEDED'));
      }

      done();

      process.exit(status);
    });

    server.start();
  };
}
<commit_msg>disable source maps in build mode<commit_after>/**
 * A Gulp task for running specs using Karma.
 *
 * To use this in a gulpfile.js:
 *
 *    import SpecTask from 'carbon-factory/lib/gulp/spec';
 *    gulp.task('test', SpecTask());
 *
 * You can also pass a hash of options to customise the task:
 *
 *    import SpecTask from 'carbon-factory/lib/gulp/spec';
 *
 *    var opts = {
 *      path: "/src/*.js",
 *      specs: "/src/*.spec.js",
 *      preProcessors: [ 'babel', 'coverage', 'browserify' ],
 *      specPreProcessors: [ 'babel', 'browserify' ],
 *      coverage: {
 *        statements: 100,
 *        branches: 100,
 *        functions: 100,
 *        lines: 100
 *      },
 *      configFile: 'karma.conf.js'
 *    }
 *
 *    gulp.task('test', SpecTask(opts));
 *
 * If you have setup the task using the task name 'test' then you can run it
 * through the command line like this:
 *
 *    gulp test
 *
 * By default this will automatically run in PhantomJS and will watch for any
 * changes. You can supply additional arguments to run in alternative modes:
 *
 * == To run in watch mode with coverage reports:
 *
 *    gulp test --coverage
 *
 * == To perform a single run with coverage:
 *
 *    gulp test --build
 *
 * == To run the tests in a specific browser:
 *
 *    gulp test -b chrome
 *
 * == To run the test across all browsers:
 *
 *    gulp test -b all
 */

import gutil from 'gulp-util';
import S from 'string';
import yargs from 'yargs';
import karma from 'karma';
import istanbul from 'browserify-istanbul';
import babelify from 'babelify';
import fs from 'fs';

var argv = yargs.argv;
var Server = karma.Server;

export default function(opts) {
  var options = opts;

  return function(done) {
    var opts = options || {};
    // the js files to test (everything except __spec__ files)
    var path = opts.path || '/src/***/**/!(__spec__).js';
    // the specs
    var specs = opts.specs || '/src/***/**/__spec__.js';
    // which preprocessors the js files should run through
    var preProcessors = opts.preProcessors || [ 'eslint', 'babel', 'coverage', 'browserify' ];
    // which preprocessors the spec files should run through
    var specpreProcessors = opts.specpreProcessors || [ 'babel', 'browserify' ];
    // where to find the karma config file
    var configFile = opts.configFile || __dirname + '/karma.conf.js';
    // defaults the coverage thresholds
    var coverageThreshold = Object.assign({}, {
      statements: 100,
      branches: 100,
      functions: 100,
      lines: 100
    }, opts.coverage);

    // where the gulp task was ran from
    var originPath = process.cwd();

    // check if eslintrc file exists, if not then prompt dev to create one
    fs.stat(originPath + '/.eslintrc', function(err, stat) {
      if (err == null) { return }
      if (err.code == 'ENOENT') {
        gutil.log(gutil.colors.red("Cannot find '.eslintrc' file"));
        gutil.log(gutil.colors.white("Create an '.eslintrc' file in the root of your project and add the following code:\n{\n  \"extends\": \"./node_modules/carbon-factory/.eslintrc\"\n}"));
        process.exit();
      }
    });

    // prefix the paths with where the gulp task was ran from so the files can
    // be found from the correct location
    var src = originPath + path,
        specSrc = originPath + specs;

    // default configuration for the spec build
    var config = {
      // all the files that should be included
      files: [ src, { pattern: specSrc, watched: false, included: true, served: true } ],
      // the karma config file
      configFile: configFile,
      // the preprocessors to run the files through
      preprocessors: {},
      // which browsers to run the specs through
      browsers: [ 'PhantomJS' ],
      // options for browserify
      browserify: {
        debug: true,
        // lookup paths for any imported files
        paths: [ originPath + '/src' ],
        // configure any transforms for browserify
        transform: [
          babelify.configure({
            // only babelify files in the src directory
            ignore: /node_modules/,
            // compile experimental es7 class properties
            optional: [ "es7.classProperties" ],
            // ignore code in the coverage that babelify generates
            auxiliaryCommentBefore: "istanbul ignore next"
          }),
          istanbul({
            // ignore these files from code coverage
            ignore: [ '**/node_modules/**', '**/__spec__.js' ]
          })
        ]
      },
      // what kind of reporters should karma generate
      reporters: ['progress', 'coverage'],
      // auto watch for any changes to rerun specs
      autoWatch: true,
      // only run the specs once
      singleRun: true,
      // setup config for coverage
      coverageReporter: {
        dir: originPath + '/coverage',
        reporters: [
          { type : 'text-summary' },
          { type : 'html' }
        ],
        check: {
          global: coverageThreshold
        }
      },
      // config for eslint
      eslint: {
        stopOnError: false,
        stopOnWarning: false
      }
    }

    // tie the preprocessors to the relevant sources
    config.preprocessors[src] = preProcessors;
    config.preprocessors[specSrc] = specpreProcessors;

    if (argv.b == 'all') {
      // if `gulp -b all` then run through all browsers
      config.browsers = [ 'PhantomJS', 'Chrome', 'Firefox', 'Safari' ];
    } else if (argv.b) {
      // if `gulp -b [browser]` then use the browser supplied
      config.browsers = [ S(argv.b).capitalize().s ];
    }

    if (argv.build) {
      // if `gulp --build` then use single run mode
      config.autoWatch = false;
      // stop on lint failures in build mode
      config.eslint.stopOnError = true;
      // disable source maps in build mode
      config.browserify.debug = false;
    } else {
      // default to watch mode
      config.singleRun = false;

      if (!argv.coverage) {
        // if `--coverage` is not supplied then do not run coverage in watch mode
        config.reporters = [ 'progress' ];
      }
    }

    var server = new Server(config, function(status) {
      if (status) {
        gutil.log(gutil.colors.red('UI Tests FAILED'));
      } else {
        gutil.log(gutil.colors.green('UI Tests SUCCEEDED'));
      }

      done();

      process.exit(status);
    });

    server.start();
  };
}
<|endoftext|>


<commit_before>import SPELLS from 'common/SPELLS';

<commit_msg>Remove unused file<commit_after><|endoftext|>


<commit_before>import _ from 'lodash';
import npmData from '../services/downloads.js';
import {graph} from '../graph/graph.js';
import config from '../../config.js';

const palette = config.palette;

var {default: packageInput, emitter: packageEvents, packages, removePackage} = require('../packages/packages.js');

const injectDisqus = () => {
  var d = document, s = d.createElement('script');
  s.src = '//npmcharts.disqus.com/embed.js';
  s.setAttribute('data-timestamp', +new Date());
  (d.head || d.body).appendChild(s);

  var d = document, s = d.createElement('script');
  s.src = '//npmcharts.disqus.com/count.js';
  s.setAttribute('data-timestamp', +new Date());
  s.setAttribute('id', 'dsq-count-scr');
  (d.head || d.body).appendChild(s);
};

const resetDisqus = (packages) => {
  if (!packages) { return }
  const sortedPackages = packages.slice().sort();
  if (window.DISQUS && window.DISQUSWIDGETS) {
    window.DISQUS.reset({
      reload: true,
      config: function () {
        this.page.identifier = sortedPackages.join(',')
        this.page.url = 'http://npmcharts.com/compare/' + sortedPackages.join(',');
      }
    })
    DISQUSWIDGETS.getCount({reset: true});
  } else {
    setTimeout(resetDisqus, 500)
  }
}

export default Vue.extend({
  route: {
    waitForData: true,
    data ({ to, next, redirect }) {
      const packageNames = (
        to.path === '/' || !to.params.packages
          ? _.sample(this.presetPackages)
          : to.params.packages.split(',').map(packageName => window.decodeURIComponent(packageName))
      );

      if (to.path === '/' || !to.params.packages) {
        document.title = "Compare download stats for npm packages - npmcharts";
        this.isUsingPresetPackages = true;
      } else {
        document.title = "Compare downloads for " + to.params.packages.split(',').join(', ') + " - npmcharts";
      }

      ga('send', 'pageview');

      packageNames
      ? npmData.fetch(packageNames, false)
          .then(() => {
            const moduleData = npmData.modules.map(x => ({
              ...x,
              // if most recent day has no download count, remove it
              downloads: _.last(x.downloads).count === 0 ? _.initial(x.downloads) : x.downloads,
            }))
            next({moduleNames: npmData.moduleNames, moduleData, isUsingPresetPackages: !to.params.packages});
          })
      : next({moduleNames: null, moduleData: null, samplePreset: _.sample(this.presetPackages)});
    },
  },
  template: require('./home.html'),
  data () {
    return {
      presetPackages: config.presetPackages,
      samplePreset: [],
      moduleNames: null,
      moduleData: null,
      palette,
      showWeekends: false,
      showOutliers: true,
      isUsingPresetPackages: undefined,
      hoverCount: 0,
      twitterIcon: require('../assets/images/icon-twitter.svg'),
      shouldShowComments: window.innerWidth >= 1000 && !(JSON.parse(window.localStorage.getItem('shouldShowComments')) === false),
    };
  },
  computed: {
    shareUrl () {
      return this.moduleNames && `http://npmcharts.com/compare/${this.moduleNames.join(',')}`;
    },
    twitterShareUrl () {
      return this.shareUrl && `https://twitter.com/intent/tweet?url=${window.encodeURIComponent(this.shareUrl)}`;
    },
    twitterMessage () {
      const hoverCount = this.hoverCount;
      return hoverCount < 3
        ? 'this chart'
        : hoverCount < 6
          ? 'neat eh?'
          : hoverCount < 10
            ? 'do iiiit'
            : 'just click it already!'
    },
    disqusIdentifier () {
      return (this.moduleNames || []).slice().sort().join(',');
    },
  },
  watch: {
    moduleNames (moduleNames, oldModuleNames) {
      resetDisqus(moduleNames);
    },
    shouldShowComments () {
      this.$refs.graph.render()
    },
  },
  ready () {
    injectDisqus()
    packageEvents.on('change', () => {
      this.$route.router.go('/compare/' + packages.join(','));
      console.log('change', resetDisqus)
      resetDisqus(packages);
    });
  },
  methods: {
    addPackage (packageName) {
      ga('send', 'event', 'packageInput', 'add', `${packageName} existing:${this.moduleNames}`);
      if (this.$route.params && this.$route.params.packages) {
        this.$route.router.go('/compare/' + this.$route.params.packages + ',' + packageName);
      } else {
        this.$route.router.go('/compare/' + packageName);
      }
    },
    clearPackages () {
      this.$route.router.go('/compare');
    },
    handleClickToggleComments () {
      const eventAction = this.shouldShowComments ? 'close' : 'open';
      const eventLabel = (this.moduleNames || []).slice().sort().join(',');
      ga('send', 'event', 'comment toggle', eventAction, eventLabel);
      this.shouldShowComments = !this.shouldShowComments;
      window.localStorage.setItem('shouldShowComments', this.shouldShowComments);
    },
    handleClickTwitter () {
      ga('send', 'event', 'share', 'twitter', this.twitterShareUrl);
      window.open(this.twitterShareUrl);
    },
    handleHoverTwitter () {
      this.hoverCount++;
      ga('send', 'event', 'hoverShare', 'twitter', this.twitterShareUrl, this.hoverCount);

    },
    handleMouseEnterTwitter () {
      this.twitterEventTimeout = setTimeout(this.handleHoverTwitter, 500)
    },
    handleMouseLeaveTwitter () {
      clearTimeout(this.twitterEventTimeout);
    },
    shuffle: _.shuffle,
  },
  components: {
    'package-input': packageInput,
    graph: require('../graph/graph.js')
  }
});<commit_msg>default to not showing comments<commit_after>import _ from 'lodash';
import npmData from '../services/downloads.js';
import {graph} from '../graph/graph.js';
import config from '../../config.js';

const palette = config.palette;

var {default: packageInput, emitter: packageEvents, packages, removePackage} = require('../packages/packages.js');

const injectDisqus = () => {
  var d = document, s = d.createElement('script');
  s.src = '//npmcharts.disqus.com/embed.js';
  s.setAttribute('data-timestamp', +new Date());
  (d.head || d.body).appendChild(s);

  var d = document, s = d.createElement('script');
  s.src = '//npmcharts.disqus.com/count.js';
  s.setAttribute('data-timestamp', +new Date());
  s.setAttribute('id', 'dsq-count-scr');
  (d.head || d.body).appendChild(s);
};

const resetDisqus = (packages) => {
  if (!packages) { return }
  const sortedPackages = packages.slice().sort();
  if (window.DISQUS && window.DISQUSWIDGETS) {
    window.DISQUS.reset({
      reload: true,
      config: function () {
        this.page.identifier = sortedPackages.join(',')
        this.page.url = 'http://npmcharts.com/compare/' + sortedPackages.join(',');
      }
    })
    DISQUSWIDGETS.getCount({reset: true});
  } else {
    setTimeout(resetDisqus, 500)
  }
}

export default Vue.extend({
  route: {
    waitForData: true,
    data ({ to, next, redirect }) {
      const packageNames = (
        to.path === '/' || !to.params.packages
          ? _.sample(this.presetPackages)
          : to.params.packages.split(',').map(packageName => window.decodeURIComponent(packageName))
      );

      if (to.path === '/' || !to.params.packages) {
        document.title = "Compare download stats for npm packages - npmcharts";
        this.isUsingPresetPackages = true;
      } else {
        document.title = "Compare downloads for " + to.params.packages.split(',').join(', ') + " - npmcharts";
      }

      ga('send', 'pageview');

      packageNames
      ? npmData.fetch(packageNames, false)
          .then(() => {
            const moduleData = npmData.modules.map(x => ({
              ...x,
              // if most recent day has no download count, remove it
              downloads: _.last(x.downloads).count === 0 ? _.initial(x.downloads) : x.downloads,
            }))
            next({moduleNames: npmData.moduleNames, moduleData, isUsingPresetPackages: !to.params.packages});
          })
      : next({moduleNames: null, moduleData: null, samplePreset: _.sample(this.presetPackages)});
    },
  },
  template: require('./home.html'),
  data () {
    return {
      presetPackages: config.presetPackages,
      samplePreset: [],
      moduleNames: null,
      moduleData: null,
      palette,
      showWeekends: false,
      showOutliers: true,
      isUsingPresetPackages: undefined,
      hoverCount: 0,
      twitterIcon: require('../assets/images/icon-twitter.svg'),
      shouldShowComments: window.innerWidth >= 1000 && !(JSON.parse(!!window.localStorage.getItem('shouldShowComments'))),
    };
  },
  computed: {
    shareUrl () {
      return this.moduleNames && `http://npmcharts.com/compare/${this.moduleNames.join(',')}`;
    },
    twitterShareUrl () {
      return this.shareUrl && `https://twitter.com/intent/tweet?url=${window.encodeURIComponent(this.shareUrl)}`;
    },
    twitterMessage () {
      const hoverCount = this.hoverCount;
      return hoverCount < 3
        ? 'this chart'
        : hoverCount < 6
          ? 'neat eh?'
          : hoverCount < 10
            ? 'do iiiit'
            : 'just click it already!'
    },
    disqusIdentifier () {
      return (this.moduleNames || []).slice().sort().join(',');
    },
  },
  watch: {
    moduleNames (moduleNames, oldModuleNames) {
      resetDisqus(moduleNames);
    },
    shouldShowComments () {
      this.$refs.graph.render()
    },
  },
  ready () {
    injectDisqus()
    packageEvents.on('change', () => {
      this.$route.router.go('/compare/' + packages.join(','));
      console.log('change', resetDisqus)
      resetDisqus(packages);
    });
  },
  methods: {
    addPackage (packageName) {
      ga('send', 'event', 'packageInput', 'add', `${packageName} existing:${this.moduleNames}`);
      if (this.$route.params && this.$route.params.packages) {
        this.$route.router.go('/compare/' + this.$route.params.packages + ',' + packageName);
      } else {
        this.$route.router.go('/compare/' + packageName);
      }
    },
    clearPackages () {
      this.$route.router.go('/compare');
    },
    handleClickToggleComments () {
      const eventAction = this.shouldShowComments ? 'close' : 'open';
      const eventLabel = (this.moduleNames || []).slice().sort().join(',');
      ga('send', 'event', 'comment toggle', eventAction, eventLabel);
      this.shouldShowComments = !this.shouldShowComments;
      window.localStorage.setItem('shouldShowComments', this.shouldShowComments);
    },
    handleClickTwitter () {
      ga('send', 'event', 'share', 'twitter', this.twitterShareUrl);
      window.open(this.twitterShareUrl);
    },
    handleHoverTwitter () {
      this.hoverCount++;
      ga('send', 'event', 'hoverShare', 'twitter', this.twitterShareUrl, this.hoverCount);

    },
    handleMouseEnterTwitter () {
      this.twitterEventTimeout = setTimeout(this.handleHoverTwitter, 500)
    },
    handleMouseLeaveTwitter () {
      clearTimeout(this.twitterEventTimeout);
    },
    shuffle: _.shuffle,
  },
  components: {
    'package-input': packageInput,
    graph: require('../graph/graph.js')
  }
});<|endoftext|>