<commit_before>/**
 * Module dependencies.
 */

var express = require('express')
  , InstagramStrategy = require('passport-instagram').Strategy
  , BearerStrategy = require('passport-http-bearer').Strategy
  , mongoose = require('mongoose')
  , connect = require('connect')
  , HerokuRedisStore = require('connect-heroku-redis')(connect)
  , lessMiddleware = require('less-middleware');

var User = mongoose.model('User');

Instagram = require('instagram-node-lib');
Instagram.set('client_id', config.instagram.client_id);
Instagram.set('client_secret', config.instagram.client_secret);
Instagram.set('callback_url', config.instagram.realtime_callback_url);
Instagram.set('maxSockets', 10);

exports.boot = function(app) {
  bootApplication(app);
}

// PASSPORT Auth

// Use the InstagramStrategy within Passport.
//   Strategies in Passport require a `verify` function, which accept
//   credentials (in this case, an accessToken, refreshToken, and Instagram
//   profile), and invoke a callback with a user object.
passport.use(new InstagramStrategy({
    clientID: config.instagram.client_id,
    clientSecret: config.instagram.client_secret,
    callbackURL: config.instagram.oauth_callback_url
  },
  function(accessToken, refreshToken, profile, done) {
    // asynchronous verification, for effect...
    process.nextTick(function () {

      User.findOne({instagram_id: profile.id}, function(err, user){
        if (user) {
          done(null, user);
        } else {
          var new_user = new User();
          new_user.provider = "instagram";
          new_user.instagram_id = profile.id;
          new_user.instagram_name = profile.username;
          new_user.displayName = profile.displayName;
          new_user.name = profile.name;
          new_user.bio = profile._json.data.bio;
          new_user.website = profile._json.data.website;
          new_user.external_counts.instagram = profile._json.data.counts;
          new_user.profile_picture = profile._json.data.profile_picture;
          new_user.oauth_token = accessToken;
          new_user.save(function(err){
            if (err) { throw err; }
            done(null, new_user);
          });
        }
      });
    });
  }
));
passport.use("token-auth", new BearerStrategy({ },
  function(token, done){
    process.nextTick(function () {
      User.findOne({api_key: token}, function(err, user) {
        if (err) { return done(err); }
        if (!user) { return done(null, false); }
        return done(null, user);
      })
    });
  }
));

passport.serializeUser(function(user, done) {
  done(null, user.instagram_id);
});

passport.deserializeUser(function(uid, done) {
  User.findOne({instagram_id: uid}, function (err, user) {
    done(err, user);
  });
});

// App settings and middleware

function bootApplication(app) {
  app.configure(function(){

    app.set('views', __dirname + '/app/views');
    app.set('view engine', 'jade');
    app.set('view options', { layout: 'layouts/default' })
    app.use(lessMiddleware({
            src: __dirname + '/public',
            compress: true
        }));

    // HACKY middleware to bring req.rawBody back since
    // Instagram-node-lib requires it. Will fix that lib
    // soon.
    // This taken from here: https://github.com/visionmedia/express/issues/897
    app.use (function(req, res, next) {
        req.rawBody = '';
        req.setEncoding('utf8');
        req.on('data', function(chunk) { req.rawBody += chunk });
        next();
    });
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({ store: new HerokuRedisStore, secret: (process.env.SESSION_SECRET || "sssh sssh ssshhhhhhh") }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(express.static(__dirname + '/public', {maxAge: 86400000}));
    app.use(express.logger(':method :url :status'));
    app.use(express.favicon());
    app.use(app.router);
  });

  app.configure('development', function(){
    // app.use(express.errorHandler());
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
  });

  // Suppress errors, allow all search engines
  app.configure('production', function(){
  	app.all('/robots.txt', function(req,res) {
  		res.send('User-agent: *', {'Content-Type': 'text/plain'});
  	});
  });

  // Template helpers
  app.dynamicHelpers({
  	'session': function(req, res) {
  		return req.session;
  	},
  	'current_user': function(req, res) {
  	  return req.user === undefined ? null : req.user;
  	},
  	messages: require('express-messages-bootstrap')
  });

}<commit_msg>enable jsonp support<commit_after>/**
 * Module dependencies.
 */

var express = require('express')
  , InstagramStrategy = require('passport-instagram').Strategy
  , BearerStrategy = require('passport-http-bearer').Strategy
  , mongoose = require('mongoose')
  , connect = require('connect')
  , HerokuRedisStore = require('connect-heroku-redis')(connect)
  , lessMiddleware = require('less-middleware');

var User = mongoose.model('User');

Instagram = require('instagram-node-lib');
Instagram.set('client_id', config.instagram.client_id);
Instagram.set('client_secret', config.instagram.client_secret);
Instagram.set('callback_url', config.instagram.realtime_callback_url);
Instagram.set('maxSockets', 10);

exports.boot = function(app) {
  bootApplication(app);
}

// PASSPORT Auth

// Use the InstagramStrategy within Passport.
//   Strategies in Passport require a `verify` function, which accept
//   credentials (in this case, an accessToken, refreshToken, and Instagram
//   profile), and invoke a callback with a user object.
passport.use(new InstagramStrategy({
    clientID: config.instagram.client_id,
    clientSecret: config.instagram.client_secret,
    callbackURL: config.instagram.oauth_callback_url
  },
  function(accessToken, refreshToken, profile, done) {
    // asynchronous verification, for effect...
    process.nextTick(function () {

      User.findOne({instagram_id: profile.id}, function(err, user){
        if (user) {
          done(null, user);
        } else {
          var new_user = new User();
          new_user.provider = "instagram";
          new_user.instagram_id = profile.id;
          new_user.instagram_name = profile.username;
          new_user.displayName = profile.displayName;
          new_user.name = profile.name;
          new_user.bio = profile._json.data.bio;
          new_user.website = profile._json.data.website;
          new_user.external_counts.instagram = profile._json.data.counts;
          new_user.profile_picture = profile._json.data.profile_picture;
          new_user.oauth_token = accessToken;
          new_user.save(function(err){
            if (err) { throw err; }
            done(null, new_user);
          });
        }
      });
    });
  }
));
passport.use("token-auth", new BearerStrategy({ },
  function(token, done){
    process.nextTick(function () {
      User.findOne({api_key: token}, function(err, user) {
        if (err) { return done(err); }
        if (!user) { return done(null, false); }
        return done(null, user);
      })
    });
  }
));

passport.serializeUser(function(user, done) {
  done(null, user.instagram_id);
});

passport.deserializeUser(function(uid, done) {
  User.findOne({instagram_id: uid}, function (err, user) {
    done(err, user);
  });
});

// App settings and middleware

function bootApplication(app) {
  app.configure(function(){

    app.set('views', __dirname + '/app/views');
    app.set('view engine', 'jade');
    app.set('view options', { layout: 'layouts/default' });
    app.set('jsonp callback', true);
    app.use(lessMiddleware({
            src: __dirname + '/public',
            compress: true
        }));

    // HACKY middleware to bring req.rawBody back since
    // Instagram-node-lib requires it. Will fix that lib
    // soon.
    // This taken from here: https://github.com/visionmedia/express/issues/897
    app.use (function(req, res, next) {
        req.rawBody = '';
        req.setEncoding('utf8');
        req.on('data', function(chunk) { req.rawBody += chunk });
        next();
    });
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({ store: new HerokuRedisStore, secret: (process.env.SESSION_SECRET || "sssh sssh ssshhhhhhh") }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(express.static(__dirname + '/public', {maxAge: 86400000}));
    app.use(express.logger(':method :url :status'));
    app.use(express.favicon());
    app.use(app.router);
  });

  app.configure('development', function(){
    // app.use(express.errorHandler());
    app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
  });

  // Suppress errors, allow all search engines
  app.configure('production', function(){
  	app.all('/robots.txt', function(req,res) {
  		res.send('User-agent: *', {'Content-Type': 'text/plain'});
  	});
  });

  // Template helpers
  app.dynamicHelpers({
  	'session': function(req, res) {
  		return req.session;
  	},
  	'current_user': function(req, res) {
  	  return req.user === undefined ? null : req.user;
  	},
  	messages: require('express-messages-bootstrap')
  });

}<|endoftext|>


<commit_before>// Karma configuration
module.exports = function(config) {
    config.set({

        // base path that will be used to resolve all patterns (eg. files, exclude)
        basePath: '',

        // frameworks to use
        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
        frameworks: ['mocha', 'sinon-chai'],

        // list of files / patterns to load in the browser
        files: [
            '../test/browser/**/*.js',
            '../test/shared/**/*.js'
        ],
        // list of files to exclude
        exclude: [],

        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {
            '../test/shared/**/*.js': ['webpack'],
            '../test/browser/**/*.js': ['webpack'],
        },
        webpack: {
            devtool: 'source-map',
            module: {
                postLoaders: [{
                    test: /\.js$/,
                    exclude: /test|node_modules\/dist/,
                    loader: 'isparta-instrumenter-loader'
                }],
                loaders: [{
                    test: /\.js$/,
                    exclude: /node_modules\/dist/,
                    loader: 'babel-loader'
                }]
            }
        },

        webpackMiddleware: {
            noInfo: true
        },

        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['mocha', 'coverage'],

        coverageReporter: {
            reporters: [{
                type: 'html',
                dir: '../coverage'
            }, {
                type: 'text',
                dir: '../coverage'
            }, {
                type: 'lcov',
                dir: '../coverage'
            }]
        },

        browsers: ['Chrome'],
        // custom launchers
        customLaunchers: {
            Chrome_for_Travis_CI: {
                base: 'Chrome',
                flags: ['--no-sandbox']
            }
        },

        browserDisconnectTimeout: 10000,
        browserDisconnectTolerance: 2,
        // concurrency level how many browser should be started simultaneously
        concurrency: 4,
        // If browser does not capture in given timeout [ms], kill it
        captureTimeout: 100000,
        browserNoActivityTimeout: 30000,
        // enable / disable colors in the output (reporters and logs)
        colors: true,
        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,
        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: false,
        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: true
    });
    if (process.env.TRAVIS) {

        // Use Chrome as default browser for Travis CI
        config.browsers = ['Chrome_for_Travis_CI'];
        // Used by Travis to push coveralls info corretly to example coveralls.io
        config.reporters = ['mocha', 'coverage', 'coveralls'];
        // Karma (with socket.io 1.x) buffers by 50 and 50 tests can take a long time on IEs;-)
        config.browserNoActivityTimeout = 120000;
    }
};<commit_msg>karma.conf fix<commit_after>// Karma configuration
module.exports = function(config) {
    config.set({

        // base path that will be used to resolve all patterns (eg. files, exclude)
        basePath: '',

        // frameworks to use
        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
        frameworks: ['mocha', 'sinon-chai'],

        // list of files / patterns to load in the browser
        files: [
            '../test/browser/**/*.js',
            '../test/shared/**/*.js'
        ],
        // list of files to exclude
        exclude: [],

        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {
            '../test/shared/**/*.js': ['webpack'],
            '../test/browser/**/*.js': ['webpack'],
        },
        webpack: {
            devtool: 'source-map',
            module: {
                postLoaders: [{
                    test: /\.js$/,
                    exclude: /test|node_modules\/dist/,
                    loader: 'isparta-instrumenter-loader'
                }],
                loaders: [{
                    test: /\.js$/,
                    exclude: /node_modules\/dist/,
                    loader: 'babel-loader'
                }]
            }
        },

        webpackMiddleware: {
            noInfo: true
        },

        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['mocha', 'coverage'],

        coverageReporter: {
            reporters: [{
                type: 'html',
                dir: '../coverage'
            }, {
                type: 'text',
                dir: '../coverage'
            }, {
                type: 'lcov',
                dir: '../coverage'
            }]
        },

        browsers: ['Chrome'],
        // custom launchers
        customLaunchers: {
            Chrome_for_Travis_CI: {
                base: 'Chrome',
                flags: ['--no-sandbox']
            }
        },

        browserDisconnectTimeout: 10000,
        browserDisconnectTolerance: 2,
        // concurrency level how many browser should be started simultaneously
        concurrency: 4,
        // If browser does not capture in given timeout [ms], kill it
        captureTimeout: 100000,
        browserNoActivityTimeout: 30000,
        // enable / disable colors in the output (reporters and logs)
        colors: true,
        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,
        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: false,
        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: true
    });
    if (process.env.TRAVIS) {

        // Use Chrome as default browser for Travis CI
        config.browsers = ['Chrome_for_Travis_CI'];
        // Used by Travis to push coveralls info corretly to example coveralls.io
//        config.reporters = ['mocha', 'coverage', 'coveralls'];
        // Karma (with socket.io 1.x) buffers by 50 and 50 tests can take a long time on IEs;-)
        config.browserNoActivityTimeout = 120000;
    }
};<|endoftext|>


<commit_before>;(function($$){ 'use strict';

  var defaults = {
    fit: true, // whether to fit the viewport to the graph
    directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
    padding: 30, // padding on fit
    circle: false, // put depths in concentric circles if true, put depths top down if false
    spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)
    boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
    avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
    roots: undefined, // the roots of the trees
    maximalAdjustments: 0, // how many times to try to position the nodes in a maximal way (i.e. no backtracking)
    animate: false, // whether to transition the node positions
    animationDuration: 500, // duration of animation in ms if enabled
    ready: undefined, // callback on layoutready
    stop: undefined // callback on layoutstop
  };

  function BreadthFirstLayout( options ){
    this.options = $$.util.extend({}, defaults, options);
  }

  BreadthFirstLayout.prototype.run = function(){
    var params = this.options;
    var options = params;

    var cy = params.cy;
    var eles = options.eles;
    var nodes = eles.nodes().not(':parent');
    var graph = eles;

    var bb = $$.util.makeBoundingBox( options.boundingBox ? options.boundingBox : {
      x1: 0, y1: 0, w: cy.width(), h: cy.height()
    } );

    var roots;
    if( $$.is.elementOrCollection(options.roots) ){
      roots = options.roots;
    } else if( $$.is.array(options.roots) ){
      var rootsArray = [];

      for( var i = 0; i < options.roots.length; i++ ){
        var id = options.roots[i];
        var ele = cy.getElementById( id );
        rootsArray.push( ele );
      }

      roots = new $$.Collection( cy, rootsArray );
    } else if( $$.is.string(options.roots) ){
      roots = cy.$( options.roots );

    } else {
      if( options.directed ){
        roots = nodes.roots();
      } else {
        var components = [];
        var unhandledNodes = nodes;

        while( unhandledNodes.length > 0 ){
          var currComp = cy.collection();

          eles.bfs({
            roots: unhandledNodes[0],
            visit: function(i, depth, node, edge, pNode){
              currComp = currComp.add( node );
            },
            directed: false
          });

          unhandledNodes = unhandledNodes.not( currComp );
          components.push( currComp );
        }

        roots = cy.collection();
        for( var i = 0; i < components.length; i++ ){
          var comp = components[i];
          var maxDegree = comp.maxDegree( false );
          var compRoots = comp.filter(function(){
            return this.degree(false) === maxDegree;
          });

          roots = roots.add( compRoots );
        }

      }
    }

    var depths = [];
    var foundByBfs = {};
    var id2depth = {};
    var prevNode = {};
    var prevEdge = {};
    var successors = {};

    // find the depths of the nodes
    graph.bfs({
      roots: roots,
      directed: options.directed,
      visit: function(i, depth, node, edge, pNode){
        var ele = this[0];
        var id = ele.id();

        if( !depths[depth] ){
          depths[depth] = [];
        }

        depths[depth].push( ele );
        foundByBfs[ id ] = true;
        id2depth[ id ] = depth;
        prevNode[ id ] = pNode;
        prevEdge[ id ] = edge;

        if( pNode ){
          var prevId = pNode.id();
          var succ = successors[ prevId ] = successors[ prevId ] || [];

          succ.push( node );
        }
      }
    });

    // check for nodes not found by bfs
    var orphanNodes = [];
    for( var i = 0; i < nodes.length; i++ ){
      var ele = nodes[i];

      if( foundByBfs[ ele.id() ] ){
        continue;
      } else {
        orphanNodes.push( ele );
      }
    }

    // assign orphan nodes a depth from their neighborhood
    var maxChecks = orphanNodes.length * 3;
    var checks = 0;
    while( orphanNodes.length !== 0 && checks < maxChecks ){
      var node = orphanNodes.shift();
      var neighbors = node.neighborhood().nodes();
      var assignedDepth = false;

      for( var i = 0; i < neighbors.length; i++ ){
        var depth = id2depth[ neighbors[i].id() ];

        if( depth !== undefined ){
          depths[depth].push( node );
          assignedDepth = true;
          break;
        }
      }

      if( !assignedDepth ){
        orphanNodes.push( node );
      }

      checks++;
    }

    // assign orphan nodes that are still left to the depth of their subgraph
    while( orphanNodes.length !== 0 ){
      var node = orphanNodes.shift();
      //var subgraph = graph.bfs( node ).path;
      var assignedDepth = false;

      // for( var i = 0; i < subgraph.length; i++ ){
      //   var depth = id2depth[ subgraph[i].id() ];

      //   if( depth !== undefined ){
      //     depths[depth].push( node );
      //     assignedDepth = true;
      //     break;
      //   }
      // }

      if( !assignedDepth ){ // worst case if the graph really isn't tree friendly, then just dump it in 0
        if( depths.length === 0 ){
          depths.push([]);
        }

        depths[0].push( node );
      }
    }

    // assign the nodes a depth and index
    var assignDepthsToEles = function(){
      for( var i = 0; i < depths.length; i++ ){
        var eles = depths[i];

        for( var j = 0; j < eles.length; j++ ){
          var ele = eles[j];

          ele._private.scratch.breadthfirst = {
            depth: i,
            index: j
          };
        }
      }
    };
    assignDepthsToEles();

    var intersectsDepth = function( node ){ // returns true if has edges pointing in from a higher depth
      var edges = node.connectedEdges(function(){
        return this.data('target') === node.id();
      });
      var thisInfo = node._private.scratch.breadthfirst;
      var highestDepthOfOther = 0;
      var highestOther;
      for( var i = 0; i < edges.length; i++ ){
        var edge = edges[i];
        var otherNode = edge.source()[0];
        var otherInfo = otherNode._private.scratch.breadthfirst;

        if( thisInfo.depth <= otherInfo.depth && highestDepthOfOther < otherInfo.depth ){
          highestDepthOfOther = otherInfo.depth;
          highestOther = otherNode;
        }
      }

      return highestOther;
    };

     // make maximal if so set by adjusting depths
    for( var adj = 0; adj < options.maximalAdjustments; adj++ ){

      var nDepths = depths.length;
      var elesToMove = [];
      for( var i = 0; i < nDepths; i++ ){
        var depth = depths[i];

        var nDepth = depth.length;
        for( var j = 0; j < nDepth; j++ ){
          var ele = depth[j];
          var info = ele._private.scratch.breadthfirst;
          var intEle = intersectsDepth(ele);

          if( intEle ){
            info.intEle = intEle;
            elesToMove.push( ele );
          }
        }
      }

      for( var i = 0; i < elesToMove.length; i++ ){
        var ele = elesToMove[i];
        var info = ele._private.scratch.breadthfirst;
        var intEle = info.intEle;
        var intInfo = intEle._private.scratch.breadthfirst;

        depths[ info.depth ].splice( info.index, 1 ); // remove from old depth & index

        // add to end of new depth
        var newDepth = intInfo.depth + 1;
        while( newDepth > depths.length - 1 ){
          depths.push([]);
        }
        depths[ newDepth ].push( ele );

        info.depth = newDepth;
        info.index = depths[newDepth].length - 1;
      }

      assignDepthsToEles();
    }

    // find min distance we need to leave between nodes
    var minDistance = 0;
    if( options.avoidOverlap ){
      for( var i = 0; i < nodes.length; i++ ){
        var w = nodes[i].outerWidth();
        var h = nodes[i].outerHeight();

        minDistance = Math.max(minDistance, w, h);
      }
      minDistance *= options.spacingFactor; // just to have some nice spacing
    }

    // get the weighted percent for an element based on its connectivity to other levels
    var cachedWeightedPercent = {};
    var getWeightedPercent = function( ele ){
      if( cachedWeightedPercent[ ele.id() ] ){
        return cachedWeightedPercent[ ele.id() ];
      }

      var eleDepth = ele._private.scratch.breadthfirst.depth;
      var neighbors = ele.neighborhood().nodes();
      var percent = 0;
      var samples = 0;

      for( var i = 0; i < neighbors.length; i++ ){
        var neighbor = neighbors[i];
        var index = neighbor._private.scratch.breadthfirst.index;
        var depth = neighbor._private.scratch.breadthfirst.depth;
        var nDepth = depths[depth].length;

        if( eleDepth > depth || eleDepth === 0 ){ // only get influenced by elements above
          percent += index / nDepth;
          samples++;
        }
      }

      samples = Math.max(1, samples);
      percent = percent / samples;

      if( samples === 0 ){ // so lone nodes have a "don't care" state in sorting
        percent = undefined;
      }

      cachedWeightedPercent[ ele.id() ] = percent;
      return percent;
    };

    // rearrange the indices in each depth level based on connectivity

    var sortFn = function(a, b){
      var apct = getWeightedPercent( a );
      var bpct = getWeightedPercent( b );

      return apct - bpct;
    };

    for( var times = 0; times < 3; times++ ){ // do it a few times b/c the depths are dynamic and we want a more stable result

      for( var i = 0; i < depths.length; i++ ){
        depths[i] = depths[i].sort( sortFn );
      }
      assignDepthsToEles(); // and update

    }

    var biggestDepthSize = 0;
    for( var i = 0; i < depths.length; i++ ){
      biggestDepthSize = Math.max( depths[i].length, biggestDepthSize );
    }

    var center = {
      x: bb.x1 + bb.w/2,
      y: bb.x1 + bb.h/2
    };

    var getPosition = function( ele, isBottomDepth ){
      var info = ele._private.scratch.breadthfirst;
      var depth = info.depth;
      var index = info.index;
      var depthSize = depths[depth].length;

      var distanceX = Math.max( bb.w / (depthSize + 1), minDistance );
      var distanceY = Math.max( bb.h / (depths.length + 1), minDistance );
      var radiusStepSize = Math.min( bb.w / 2 / depths.length, bb.h / 2 / depths.length );
      radiusStepSize = Math.max( radiusStepSize, minDistance );

      if( !options.circle ){

        var epos = {
          x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
          y: (depth + 1) * distanceY
        };

        if( isBottomDepth ){
          return epos;
        }

        // var succs = successors[ ele.id() ];
        // if( succs ){
        //   epos.x = 0;
        //
        //   for( var i = 0 ; i < succs.length; i++ ){
        //     var spos = pos[ succs[i].id() ];
        //
        //     epos.x += spos.x;
        //   }
        //
        //   epos.x /= succs.length;
        // } else {
        //   //debugger;
        // }

        return epos;

      } else {
        if( options.circle ){
          var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize/2 : 0);
          var theta = 2 * Math.PI / depths[depth].length * index;

          if( depth === 0 && depths[0].length === 1 ){
            radius = 1;
          }

          return {
            x: center.x + radius * Math.cos(theta),
            y: center.y + radius * Math.sin(theta)
          };

        } else {
          return {
            x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
            y: (depth + 1) * distanceY
          };
        }
      }

    };

    // get positions in reverse depth order
    var pos = {};
    for( var i = depths.length - 1; i >=0; i-- ){
      var depth = depths[i];

      for( var j = 0; j < depth.length; j++ ){
        var node = depth[j];

        pos[ node.id() ] = getPosition( node, i === depths.length - 1 );
      }
    }

    nodes.layoutPositions(this, options, function(){
      return pos[ this.id() ];
    });

    return this; // chaining
  };

  $$('layout', 'breadthfirst', BreadthFirstLayout);

})( cytoscape );
<commit_msg> Directed graphs fail to lay out in this case #922<commit_after>;(function($$){ 'use strict';

  var defaults = {
    fit: true, // whether to fit the viewport to the graph
    directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
    padding: 30, // padding on fit
    circle: false, // put depths in concentric circles if true, put depths top down if false
    spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)
    boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
    avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
    roots: undefined, // the roots of the trees
    maximalAdjustments: 0, // how many times to try to position the nodes in a maximal way (i.e. no backtracking)
    animate: false, // whether to transition the node positions
    animationDuration: 500, // duration of animation in ms if enabled
    ready: undefined, // callback on layoutready
    stop: undefined // callback on layoutstop
  };

  function BreadthFirstLayout( options ){
    this.options = $$.util.extend({}, defaults, options);
  }

  BreadthFirstLayout.prototype.run = function(){
    var params = this.options;
    var options = params;

    var cy = params.cy;
    var eles = options.eles;
    var nodes = eles.nodes().not(':parent');
    var graph = eles;

    var bb = $$.util.makeBoundingBox( options.boundingBox ? options.boundingBox : {
      x1: 0, y1: 0, w: cy.width(), h: cy.height()
    } );

    var roots;
    if( $$.is.elementOrCollection(options.roots) ){
      roots = options.roots;
    } else if( $$.is.array(options.roots) ){
      var rootsArray = [];

      for( var i = 0; i < options.roots.length; i++ ){
        var id = options.roots[i];
        var ele = cy.getElementById( id );
        rootsArray.push( ele );
      }

      roots = new $$.Collection( cy, rootsArray );
    } else if( $$.is.string(options.roots) ){
      roots = cy.$( options.roots );

    } else {
      if( options.directed ){
        roots = nodes.roots();
      } else {
        var components = [];
        var unhandledNodes = nodes;

        while( unhandledNodes.length > 0 ){
          var currComp = cy.collection();

          eles.bfs({
            roots: unhandledNodes[0],
            visit: function(i, depth, node, edge, pNode){
              currComp = currComp.add( node );
            },
            directed: false
          });

          unhandledNodes = unhandledNodes.not( currComp );
          components.push( currComp );
        }

        roots = cy.collection();
        for( var i = 0; i < components.length; i++ ){
          var comp = components[i];
          var maxDegree = comp.maxDegree( false );
          var compRoots = comp.filter(function(){
            return this.degree(false) === maxDegree;
          });

          roots = roots.add( compRoots );
        }

      }
    }

    var depths = [];
    var foundByBfs = {};
    var id2depth = {};
    var prevNode = {};
    var prevEdge = {};
    var successors = {};

    // find the depths of the nodes
    graph.bfs({
      roots: roots,
      directed: options.directed,
      visit: function(i, depth, node, edge, pNode){
        var ele = this[0];
        var id = ele.id();

        if( !depths[depth] ){
          depths[depth] = [];
        }

        depths[depth].push( ele );
        foundByBfs[ id ] = true;
        id2depth[ id ] = depth;
        prevNode[ id ] = pNode;
        prevEdge[ id ] = edge;

        if( pNode ){
          var prevId = pNode.id();
          var succ = successors[ prevId ] = successors[ prevId ] || [];

          succ.push( node );
        }
      }
    });

    // check for nodes not found by bfs
    var orphanNodes = [];
    for( var i = 0; i < nodes.length; i++ ){
      var ele = nodes[i];

      if( foundByBfs[ ele.id() ] ){
        continue;
      } else {
        orphanNodes.push( ele );
      }
    }

    // assign orphan nodes a depth from their neighborhood
    var maxChecks = orphanNodes.length * 3;
    var checks = 0;
    while( orphanNodes.length !== 0 && checks < maxChecks ){
      var node = orphanNodes.shift();
      var neighbors = node.neighborhood().nodes();
      var assignedDepth = false;

      for( var i = 0; i < neighbors.length; i++ ){
        var depth = id2depth[ neighbors[i].id() ];

        if( depth !== undefined ){
          depths[depth].push( node );
          assignedDepth = true;
          break;
        }
      }

      if( !assignedDepth ){
        orphanNodes.push( node );
      }

      checks++;
    }

    // assign orphan nodes that are still left to the depth of their subgraph
    while( orphanNodes.length !== 0 ){
      var node = orphanNodes.shift();
      //var subgraph = graph.bfs( node ).path;
      var assignedDepth = false;

      // for( var i = 0; i < subgraph.length; i++ ){
      //   var depth = id2depth[ subgraph[i].id() ];

      //   if( depth !== undefined ){
      //     depths[depth].push( node );
      //     assignedDepth = true;
      //     break;
      //   }
      // }

      if( !assignedDepth ){ // worst case if the graph really isn't tree friendly, then just dump it in 0
        if( depths.length === 0 ){
          depths.push([]);
        }

        depths[0].push( node );
      }
    }

    // assign the nodes a depth and index
    var assignDepthsToEles = function(){
      for( var i = 0; i < depths.length; i++ ){
        var eles = depths[i];

        for( var j = 0; j < eles.length; j++ ){
          var ele = eles[j];

          ele._private.scratch.breadthfirst = {
            depth: i,
            index: j
          };
        }
      }
    };
    assignDepthsToEles();

    var intersectsDepth = function( node ){ // returns true if has edges pointing in from a higher depth
      var edges = node.connectedEdges(function(){
        return this.data('target') === node.id();
      });
      var thisInfo = node._private.scratch.breadthfirst;
      var highestDepthOfOther = 0;
      var highestOther;
      for( var i = 0; i < edges.length; i++ ){
        var edge = edges[i];
        var otherNode = edge.source()[0];
        var otherInfo = otherNode._private.scratch.breadthfirst;

        if( thisInfo.depth <= otherInfo.depth && highestDepthOfOther < otherInfo.depth ){
          highestDepthOfOther = otherInfo.depth;
          highestOther = otherNode;
        }
      }

      return highestOther;
    };

     // make maximal if so set by adjusting depths
    for( var adj = 0; adj < options.maximalAdjustments; adj++ ){

      var nDepths = depths.length;
      var elesToMove = [];
      for( var i = 0; i < nDepths; i++ ){
        var depth = depths[i];

        var nDepth = depth.length;
        for( var j = 0; j < nDepth; j++ ){
          var ele = depth[j];
          var info = ele._private.scratch.breadthfirst;
          var intEle = intersectsDepth(ele);

          if( intEle ){
            info.intEle = intEle;
            elesToMove.push( ele );
          }
        }
      }

      for( var i = 0; i < elesToMove.length; i++ ){
        var ele = elesToMove[i];
        var info = ele._private.scratch.breadthfirst;
        var intEle = info.intEle;
        var intInfo = intEle._private.scratch.breadthfirst;

        depths[ info.depth ].splice( info.index, 1 ); // remove from old depth & index

        // add to end of new depth
        var newDepth = intInfo.depth + 1;
        while( newDepth > depths.length - 1 ){
          depths.push([]);
        }
        depths[ newDepth ].push( ele );

        info.depth = newDepth;
        info.index = depths[newDepth].length - 1;
      }

      assignDepthsToEles();
    }

    // find min distance we need to leave between nodes
    var minDistance = 0;
    if( options.avoidOverlap ){
      for( var i = 0; i < nodes.length; i++ ){
        var w = nodes[i].outerWidth();
        var h = nodes[i].outerHeight();

        minDistance = Math.max(minDistance, w, h);
      }
      minDistance *= options.spacingFactor; // just to have some nice spacing
    }

    // get the weighted percent for an element based on its connectivity to other levels
    var cachedWeightedPercent = {};
    var getWeightedPercent = function( ele ){
      if( cachedWeightedPercent[ ele.id() ] ){
        return cachedWeightedPercent[ ele.id() ];
      }

      var eleDepth = ele._private.scratch.breadthfirst.depth;
      var neighbors = ele.neighborhood().nodes().not(':parent');
      var percent = 0;
      var samples = 0;

      for( var i = 0; i < neighbors.length; i++ ){
        var neighbor = neighbors[i];
        var bf = neighbor._private.scratch.breadthfirst;
        var index = bf.index;
        var depth = bf.depth;
        var nDepth = depths[depth].length;

        if( eleDepth > depth || eleDepth === 0 ){ // only get influenced by elements above
          percent += index / nDepth;
          samples++;
        }
      }

      samples = Math.max(1, samples);
      percent = percent / samples;

      if( samples === 0 ){ // so lone nodes have a "don't care" state in sorting
        percent = undefined;
      }

      cachedWeightedPercent[ ele.id() ] = percent;
      return percent;
    };

    // rearrange the indices in each depth level based on connectivity

    var sortFn = function(a, b){
      var apct = getWeightedPercent( a );
      var bpct = getWeightedPercent( b );

      return apct - bpct;
    };

    for( var times = 0; times < 3; times++ ){ // do it a few times b/c the depths are dynamic and we want a more stable result

      for( var i = 0; i < depths.length; i++ ){
        depths[i] = depths[i].sort( sortFn );
      }
      assignDepthsToEles(); // and update

    }

    var biggestDepthSize = 0;
    for( var i = 0; i < depths.length; i++ ){
      biggestDepthSize = Math.max( depths[i].length, biggestDepthSize );
    }

    var center = {
      x: bb.x1 + bb.w/2,
      y: bb.x1 + bb.h/2
    };

    var getPosition = function( ele, isBottomDepth ){
      var info = ele._private.scratch.breadthfirst;
      var depth = info.depth;
      var index = info.index;
      var depthSize = depths[depth].length;

      var distanceX = Math.max( bb.w / (depthSize + 1), minDistance );
      var distanceY = Math.max( bb.h / (depths.length + 1), minDistance );
      var radiusStepSize = Math.min( bb.w / 2 / depths.length, bb.h / 2 / depths.length );
      radiusStepSize = Math.max( radiusStepSize, minDistance );

      if( !options.circle ){

        var epos = {
          x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
          y: (depth + 1) * distanceY
        };

        if( isBottomDepth ){
          return epos;
        }

        // var succs = successors[ ele.id() ];
        // if( succs ){
        //   epos.x = 0;
        //
        //   for( var i = 0 ; i < succs.length; i++ ){
        //     var spos = pos[ succs[i].id() ];
        //
        //     epos.x += spos.x;
        //   }
        //
        //   epos.x /= succs.length;
        // } else {
        //   //debugger;
        // }

        return epos;

      } else {
        if( options.circle ){
          var radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize/2 : 0);
          var theta = 2 * Math.PI / depths[depth].length * index;

          if( depth === 0 && depths[0].length === 1 ){
            radius = 1;
          }

          return {
            x: center.x + radius * Math.cos(theta),
            y: center.y + radius * Math.sin(theta)
          };

        } else {
          return {
            x: center.x + (index + 1 - (depthSize + 1)/2) * distanceX,
            y: (depth + 1) * distanceY
          };
        }
      }

    };

    // get positions in reverse depth order
    var pos = {};
    for( var i = depths.length - 1; i >=0; i-- ){
      var depth = depths[i];

      for( var j = 0; j < depth.length; j++ ){
        var node = depth[j];

        pos[ node.id() ] = getPosition( node, i === depths.length - 1 );
      }
    }

    nodes.layoutPositions(this, options, function(){
      return pos[ this.id() ];
    });

    return this; // chaining
  };

  $$('layout', 'breadthfirst', BreadthFirstLayout);

})( cytoscape );
<|endoftext|>


<commit_before>import React from 'react';
import {
  StyleSheet,
  View,
  ScrollView,
  Text,
  TextInput,
  TouchableHighlight,
  Image,
} from 'react-native';
import { Actions } from 'react-native-router-flux';
import { List } from 'antd-mobile';
import { APIS, COMPONENTS } from '../demoList';

export default class RnIndex extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      searchText: '',
      APIS,
      COMPONENTS,
    };

    this.search = this.search.bind(this);
  }

  componentDidMount() {
    this.search(this.state.searchText);
  }

  onPressRow(rowData) {
    if (rowData.title) {
      Actions[rowData.title]();
    } else {
      console.log('demoList.js 中配置的组件必须要有 title');
    }
  }

  search(text) {
    const regex = new RegExp(String(text), 'i');
    const filter = (component) => regex.test(component.title);

    this.setState({
      APIS: APIS.filter(filter),
      COMPONENTS: COMPONENTS.filter(filter),
      searchText: text,
    });
  }

  render() {
    const { APIS, COMPONENTS } = this.state;
    return (
      <ScrollView style={styles.container}>
        <View style={styles.searchRow}>
          <TextInput
            style={styles.searchTextInput}
            autoCapitalize="none"
            autoCorrect={false}
            clearButtonMode="always"
            onChangeText={this.search}
            placeholder="Search..."
            value={this.state.searchText}
          />
        </View>
        <List
          title="APIS"
          style={{
            marginTop: 0,
            marginBottom: 0,
          }}
        >
          <List.Body>
            {APIS.map((el, index) => {
              return (<List.Item
                thumb={el.icon}
                onClick={() => { this.onPressRow(el); }}
                arrow="horizontal"
                key={`APIS-${index}`}
              >{`${el.title} ${el.description}`}</List.Item>);
            })}
          </List.Body>
        </List>
        <List
          title="COMPONENTS"
          style={{
            marginTop: 0,
            marginBottom: 0,
          }}
        >
          <List.Body>
            {COMPONENTS.map((el, index) => {
              return (<List.Item
                thumb={el.icon}
                onClick={() => { this.onPressRow(el); }}
                arrow="horizontal"
                key={`COMPONENTS-${index}`}
              >{`${el.title} ${el.description}`}</List.Item>);
            })}
          </List.Body>
        </List>
      </ScrollView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  searchRow: {
    backgroundColor: '#eeeeee',
    paddingTop: 75,
    paddingHorizontal: 10,
    paddingBottom: 10,
  },
  searchTextInput: {
    height: 36,
    backgroundColor: 'white',
    borderColor: '#cccccc',
    borderRadius: 3,
    borderWidth: 0.5,
    paddingLeft: 8,
  },
});
<commit_msg>update rnIndex<commit_after>import React from 'react';
import {
  StyleSheet,
  View,
  ScrollView,
  Platform,
} from 'react-native';
import { Actions } from 'react-native-router-flux';
import { List, SearchBar } from 'antd-mobile';
import { APIS, COMPONENTS } from '../demoList';

export default class RnIndex extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      searchText: '',
      APIS,
      COMPONENTS,
    };

    this.search = this.search.bind(this);
  }

  componentDidMount() {
    this.search(this.state.searchText);
  }

  onPressRow(rowData) {
    if (rowData.title) {
      Actions[rowData.title]();
    } else {
      console.log('demoList.js 中配置的组件必须要有 title');
    }
  }

  search(text) {
    const regex = new RegExp(String(text), 'i');
    const filter = (component) => regex.test(component.title);

    this.setState({
      APIS: APIS.filter(filter),
      COMPONENTS: COMPONENTS.filter(filter),
      searchText: text,
    });
  }

  render() {
    const { APIS, COMPONENTS } = this.state;
    return (
      <View style={styles.container}>
        <SearchBar
          onChange={(text) => {this.search(text); }}
        />
        <ScrollView>
          <List
            title="APIS"
            style={{
              marginTop: 0,
              marginBottom: 0,
            }}
          >
            <List.Body>
              {APIS.map((el, index) => {
                return (<List.Item
                  thumb={el.icon}
                  onClick={() => { this.onPressRow(el); }}
                  arrow="horizontal"
                  key={`APIS-${index}`}
                >{`${el.title} ${el.description}`}</List.Item>);
              })}
            </List.Body>
          </List>
          <List
            title="COMPONENTS"
            style={{
              marginTop: 0,
              marginBottom: 0,
            }}
          >
            <List.Body>
              {COMPONENTS.map((el, index) => {
                return (<List.Item
                  thumb={el.icon}
                  onClick={() => { this.onPressRow(el); }}
                  arrow="horizontal"
                  key={`COMPONENTS-${index}`}
                >{`${el.title} ${el.description}`}</List.Item>);
              })}
            </List.Body>
          </List>
        </ScrollView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: Platform.OS === 'ios' ? 64 : 54,
  },
});
<|endoftext|>


<commit_before>"use strict";
/*
 Created by Zihao Zhao on 2016/12/1
 */
const dbConnection = require("../config/mongoConnection");
const uuid = require("node-uuid");
const blogData = require("../data/blog");
console.log(blogData);
dbConnection().then(db => {
    return db.collection("blog").drop().then(function(status) {
        console.log(status);
        return db;
    }, function(error) {
        console.log(error);
    }).then((db) => {
        return db.createCollection("blog");
    }).then(function(blogCollection) {
        blogData.addBlog(title, content, createTime, mainImage, conclusions, type, tag, userId, siteId)
        var createBlog = (title, content, mainImage, conclusions,type, tag, userId, siteId) => {
            return {
                _id: uuid.v4(),
                title: title,
                content: content,
                createTime: new Date("<YYYY-mm-dd>"),
                mainImage: mainImage,
                conclusions: conclusions,
                type: type,
                tag: tag,
                userId: userId,
                siteId: siteId
            }
        }

        var list = [];

        // blog_1 Beijing
        var blog1 = createBlog("blog1", "content1",tag = ["tag1","tag2"]);

        // blog_2 Shanghai
        var blog2 = createBlog("blog2", "content2",tag = ["tag1","tag2"]);

        // blod_3 Shenzhen
        var blog3 = createBlog("blog3", "content3",tag = ["tag1","tag2"]);

        list.push(blog1, blog2, blog3);

        return blogCollection.insertMany(list).then(() => {
            return blogCollection.find().toArray();
        });
    });
});

<commit_msg>commit<commit_after>"use strict";
/*
 Created by Zihao Zhao on 2016/12/1
 */
const dbConnection = require("../config/mongoConnection");
const uuid = require("node-uuid");
const blogData = require("../data/blog");
//console.log(blogData);
dbConnection().then(db => {
    return db.collection("blog").drop().then(function(status) {
        console.log("should be true: ",status);
        return db;
    }, function(error) {
        console.log("error in drop blog!")
        //console.log(error);
        return db;
    }).then((db) => {
        console.log("create blog collection!")
        return db.createCollection("blog");
    }).then(function(blogCollection) {
        console.log("in blogCollection");
        //blogData.addBlog(title, content, createTime, mainImage, conclusions, type, tag, userId, siteId)
        var createBlog = function(title, content, mainImage, conclusions,type, tag, userId, siteId){
            console.log("create blog data with", title);
            return {
                _id: uuid.v4(),
                title: title,
                content: content,
                createTime: new Date("<YYYY-mm-dd>"),
                mainImage: mainImage,
                conclusions: conclusions,
                type: type,
                tag: tag,
                userId: userId,
                siteId: siteId
            }
        };

        var list = [];
        // blog_1 Beijing
        var blog1 = createBlog("blog1", "content1",tag = ["tag1","tag2"]);

        // blog_2 Shanghai
        var blog2 = createBlog("blog2", "content2",tag = ["tag1","tag2"]);

        // blod_3 Shenzhen
        var blog3 = createBlog("blog3", "content3",tag = ["tag1","tag2"]);

        list.push(blog1, blog2, blog3);
        console.log(list);
        return blogCollection.insertMany(list).then(() => {
            console.log("insertMany");
            return blogCollection.find().toArray();
        });
    })
    .then(list=>{
    console.log(list);
});
});

<|endoftext|>


<commit_before><commit_msg>Where is the button?<commit_after><|endoftext|>


<commit_before>import optionsStorage from '../options';
import ContextExtractor from '../ContextExtractor';

const IFRAME_ID = 'leoTranslateIFrame';

let mouseX = 0;
let mouseY = 0;
let options = {};

// Fetch options from local storage
optionsStorage.getAllOptions().then(data => options = data);

document.body.addEventListener('mousedown', e => {
  if (e.button === 0) {
    hideIFrame();
  }

  if (e.button === 2 || e.button === 0) {
    mouseX = e.pageX;
    mouseY = e.pageY;
  }
});

document.body.addEventListener('dblclick', e => {
  if (options['double-click']) {
    // If there's a key constraint.
    if (options['double-click-ctrl'] || options['double-click-alt']) {

      // If there's no a condition that has passed a check.
      if (! (isAltClick() || isCtrlClick())) {
        return;
      }
    }

    const iFrame = getIFrame();

    showIFrame(iFrame);
    sendDataToIFrame(iFrame);

    function isAltClick () {
      return options['double-click-alt'] && e.altKey;
    }

    function isCtrlClick () {
      return options['double-click-ctrl'] && e.ctrlKey;
    }
  }
});

// Listen for messages from the iFrame
window.addEventListener('message', e => {
  if (chrome.extension.getURL('') === e.origin+'/') {
    const iFrame = getIFrame();

    if (e.data.id === 'vue-popup-resized') {
      iFrame.width  = iFrame.contentWindow.document.body.scrollWidth;
      iFrame.height = iFrame.contentWindow.document.body.scrollHeight;
    } else if (e.data.id === 'vue-popup-get-data') {
      sendDataToIFrame(iFrame);
    } else if (e.data.id === 'vue-translate-close') {
      hideIFrame();
    }
  }
});

chrome.runtime.onMessage.addListener(message => {
  if (message.id === 'context-menu-clicked') {
    const iFrame = getIFrame();

    showIFrame(iFrame);
    sendDataToIFrame(iFrame);
  }
});

function getIFrame () {
  let container = document.getElementById(IFRAME_ID);

  if (container === null) {
    container = document.createElement('iframe');

    const defaultStyles = {
      position: 'absolute',
      display: 'none',
      border: 'none',
      zIndex: 10000,
      boxShadow: '0 0 1px 0'
    };

    container.id = IFRAME_ID;

    for (const styleName in defaultStyles) {
      container.style[styleName] = defaultStyles[styleName];
    }

    document.body.appendChild(container);

    container.src = chrome.extension.getURL('/templates/context-popup.html');
  }

  return container;
}

function showIFrame (iFrame = null) {
  const container = iFrame || getIFrame();

  container.style.display = 'block';
  container.style.top = mouseY+'px';
  container.style.left = mouseX+'px';
}

function hideIFrame() {
  const container = document.getElementById(IFRAME_ID);

  if (container !== null) {
    container.style.display = 'none';
  }
}

function sendDataToIFrame (iFrame) {
  const selection = getSelection();

  const message = {
    id: 'content-data',
    url: document.URL,
    text: selection.toString(),
    title: document.title,
    context: ''
  };

  if (options['context-capturing']) {
    message['context'] = new ContextExtractor(selection).getContext().getSentence();
  }

  iFrame.contentWindow.postMessage(message, chrome.extension.getURL(''));
}
<commit_msg>add limit to the selection length.<commit_after>import optionsStorage from '../options';
import ContextExtractor from '../ContextExtractor';

const IFRAME_ID = 'leoTranslateIFrame';

let mouseX = 0;
let mouseY = 0;
let options = {};

// Fetch options from local storage
optionsStorage.getAllOptions().then(data => options = data);

document.body.addEventListener('mousedown', e => {
  if (e.button === 0) {
    hideIFrame();
  }

  if (e.button === 2 || e.button === 0) {
    mouseX = e.pageX;
    mouseY = e.pageY;
  }
});

document.body.addEventListener('dblclick', e => {
  if (options['double-click']) {
    // If there's a key constraint.
    if (options['double-click-ctrl'] || options['double-click-alt']) {

      // If there's no a condition that has passed a check.
      if (! (isAltClick() || isCtrlClick())) {
        return;
      }
    }

    callTranslatePopup();

    function isAltClick () {
      return options['double-click-alt'] && e.altKey;
    }

    function isCtrlClick () {
      return options['double-click-ctrl'] && e.ctrlKey;
    }
  }
});

// Listen for messages from the iFrame
window.addEventListener('message', e => {
  if (chrome.extension.getURL('') === e.origin+'/') {
    const iFrame = getIFrame();

    if (e.data.id === 'vue-popup-resized') {
      iFrame.width  = iFrame.contentWindow.document.body.scrollWidth;
      iFrame.height = iFrame.contentWindow.document.body.scrollHeight;
    } else if (e.data.id === 'vue-popup-get-data') {
      sendDataToIFrame(iFrame);
    } else if (e.data.id === 'vue-translate-close') {
      hideIFrame();
    }
  }
});

chrome.runtime.onMessage.addListener(message => {
  if (message.id === 'context-menu-clicked') {
    callTranslatePopup();
  }
});

function callTranslatePopup () {
  const maxLength = ContextExtractor.LIMIT * 2;

  if (getSelection().toString().length > maxLength) {
    chrome.runtime.sendMessage({
      id: 'show-notification',
      text: 'The selection is too long! It must be less than '+maxLength+' characters.'
    });
  } else {
    const iFrame = getIFrame();

    showIFrame(iFrame);
    sendDataToIFrame(iFrame);
  }
}

function getIFrame () {
  let container = document.getElementById(IFRAME_ID);

  if (container === null) {
    container = document.createElement('iframe');

    const defaultStyles = {
      position: 'absolute',
      display: 'none',
      border: 'none',
      zIndex: 10000,
      boxShadow: '0 0 1px 0'
    };

    container.id = IFRAME_ID;

    for (const styleName in defaultStyles) {
      container.style[styleName] = defaultStyles[styleName];
    }

    document.body.appendChild(container);

    container.src = chrome.extension.getURL('/templates/context-popup.html');
  }

  return container;
}

function showIFrame (iFrame = null) {
  const container = iFrame || getIFrame();

  container.style.display = 'block';
  container.style.top = mouseY+'px';
  container.style.left = mouseX+'px';
}

function hideIFrame() {
  const container = document.getElementById(IFRAME_ID);

  if (container !== null) {
    container.style.display = 'none';
  }
}

function sendDataToIFrame (iFrame) {
  const selection = getSelection();

  const message = {
    id: 'content-data',
    url: document.URL,
    text: selection.toString(),
    title: document.title,
    context: ''
  };

  if (options['context-capturing']) {
    message['context'] = new ContextExtractor(selection).getContext().getSentence();
  }

  iFrame.contentWindow.postMessage(message, chrome.extension.getURL(''));
}
<|endoftext|>


<commit_before>// nothing here yet :)
var models = module.exports = {
	process: process
}

function process(modelDescriptions) {
	for (var modelName in modelDescriptions) {
		_validateModel(modelName, modelDescriptions[modelName])
		_createModel(modelName, modelDescriptions[modelName])
	}
}

var _validateModel = function(modelName, properties) {
	var firstLetterCode = modelName.charCodeAt(0)
	assert(65 <= firstLetterCode && firstLetterCode <= 90, 'Model names should start with an upper case letter. "'+modelName+'" does not.')
	assert(!models[modelName], 'Model "'+modelName+'" already exists')
	var propertyIDs = {}
	for (propertyName in properties) {
		firstLetterCode = propertyName.charCodeAt(0)
		var property = properties[propertyName]
		assert(97 <= firstLetterCode && firstLetterCode <= 122, 'Property names should start with a lowercase letter. "'+propertyName+'" does not.')
		assert(typeof property.id == 'number', 'Properties need an id. "'+propertyName+'" does not')
		assert(!propertyIDs[property.id], 'Property IDs need to be unique. "'+modelName+'" has two properties with the id '+property.id+'')
	}
}

var _createModel = function(modelName, modelProperties) {
	var model = models[modelName] = function modelInstantiator() {
		this._instantiate.apply(this, arguments)
	}

	model.prototype._instantiate = function(instanceProperties) {
		// for (var propertyName in instanceProperties) {
		// 	// TODO check that each instance property is present in modelProperties
		// }

		for (var propertyName in modelProperties) {
			// TODO check that instanceProperties fullfill "type" & "required" in modelProperties
			var modelProperty = modelProperties[propertyName],
				valueModel = instanceProperties[propertyName]
			if (typeof valueModel == 'object') {
				this[propertyName] = valueModel
			} else {
				this[propertyName] = new rootModels[modelProperty.type](propertyName, modelName, modelProperty.id, modelProperty.type, this, valueModel)
			}
		}
	}
}

// UTILS
function assert(isOK, msg) {
	if (isOK) { return }
	throw new Error(msg)
}

var RootModel = function(propertyName, modelName, propertyID, propertyType, parentModel, value) {
	console.log('Instantiate', propertyType, propertyName, '('+propertyID+')', value, 'for', modelName, parentModel)
	this._value = value
}

var rootModels = {
	"Text": RootModel,
	"Number": RootModel
}

/* TODO
 - add on, observe and promise to RootModel
 - have Text and Number extend RootModel with set
 - have Set and List extend RootModel and publish on('add') and on('remove')
 - to implement on/observe/promise, climb the parent models to create the observation chain
 - call fin.create in initializer
 - add fin.transact
*/<commit_msg>Straighten out the model references a bit. There are two types of models - CustomModels and PropertyModels. Custom models are the ones that users define. They support typical methods by default such as create and destroy. Property models reflect our data structures: Text, Number, Set, List, Hash. They support a different set of methods, such as set for Texts, increment and add for Numbers, add and remove for Sets, push, pop, shift and unshift for Lists, etc.<commit_after>var util = require('../fin/util'),
	map = util.map,
	bind = util.bind

// nothing here yet :)
var customModels = module.exports = {
	process: process
}

function process(modelDescriptions) {
	for (var modelName in modelDescriptions) {
		_validateModel(modelName, modelDescriptions[modelName])
		_createModel(modelName, modelDescriptions[modelName])
	}
}

var _validateModel = function(modelName, properties) {
	var firstLetterCode = modelName.charCodeAt(0)
	assert(65 <= firstLetterCode && firstLetterCode <= 90, 'Model names should start with an upper case letter. "'+modelName+'" does not.')
	assert(!customModels[modelName], 'Model "'+modelName+'" already exists')
	var propertyIDs = {}
	for (propertyName in properties) {
		firstLetterCode = propertyName.charCodeAt(0)
		var property = properties[propertyName]
		assert(97 <= firstLetterCode && firstLetterCode <= 122, 'Property names should start with a lowercase letter. "'+propertyName+'" does not.')
		assert(typeof property.id == 'number', 'Properties need an id. "'+propertyName+'" does not')
		assert(!propertyIDs[property.id], 'Property IDs need to be unique. "'+modelName+'" has two properties with the id '+property.id+'')
		assert(!CustomModelPrototype[propertyName], 'Certain property names would overwrite important model methods. "'+propertyName+'" on "'+modelName+'" is such a property - pick a different property name.')
	}
}

var _createModel = function(modelName, modelDescription) {
	var modelConstructor = customModels[modelName] = function(idOrValues) {
		this._constructor = customModels[modelName]
		this._instantiate.call(this, idOrValues)
	}
	var modelPropertiesID = []
	for (var propertyName in modelDescription) {
		modelPropertiesID.push(modelDescription[propertyName].id)
	}
	modelConstructor.prototype = CustomModelPrototype
	modelConstructor.description = modelDescription
	modelConstructor.properties = map(modelDescription, function(propDescr) { return propDescr.id })
}

var CustomModelPrototype = {
	_instantiate: instantiateModel,
	create: createModel
}

function instantiateModel(idOrValues) {
	var values
	if (typeof idOrValues == 'number') { this._id = idOrValues }
	else { values = idOrValues || {} }

	for (var propertyName in this._constructor.description) {
		var propertyDescription = this._constructor.description[propertyName],
			valueType = propertyDescription.type,
			Model = propertyModels[valueType] || customModels[valueType],
			value = values[propertyName]

		this[propertyName] = new Model(value)
	}
}

function createModel() {
	// TODO sync with server
}

// UTILS
function assert(isOK, msg) {
	if (isOK) { return }
	throw new Error(msg)
}

var PropertyModel = function(value) {
	this._value = value
}

var propertyModels = {
	"Text": PropertyModel,
	"Number": PropertyModel
}

/* TODO
 - add on, observe and promise to RootModel
 - have Text and Number extend RootModel with set
 - have Set and List extend RootModel and publish on('add') and on('remove')
 - to implement on/observe/promise, climb the parent models to create the observation chain
 - call fin.create in initializer
 - add fin.transact
*/<|endoftext|>


<commit_before>import * as util from '../../util';
import * as math from '../../math';
import * as is from '../../is';

/* eslint-disable no-unused-vars */
const defaults = {
  fit: true, // whether to fit the viewport to the graph
  directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
  padding: 30, // padding on fit
  circle: false, // put depths in concentric circles if true, put depths top down if false
  grid: false, // whether to create an even grid into which the DAG is placed (circle:false only)
  spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)
  boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
  avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
  nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm
  roots: undefined, // the roots of the trees
  maximal: false, // whether to shift nodes down their natural BFS depths in order to avoid upwards edges (DAGS only)
  animate: false, // whether to transition the node positions
  animationDuration: 500, // duration of animation in ms if enabled
  animationEasing: undefined, // easing of animation if enabled,
  animateFilter: function ( node, i ){ return true; }, // a function that determines whether the node should be animated.  All nodes animated by default on animate enabled.  Non-animated nodes are positioned immediately when the layout starts
  ready: undefined, // callback on layoutready
  stop: undefined, // callback on layoutstop
  transform: function (node, position ){ return position; } // transform a given node position. Useful for changing flow direction in discrete layouts
};
/* eslint-enable */

const getInfo = ele => ele.scratch('breadthfirst');
const setInfo = (ele, obj) => ele.scratch('breadthfirst', obj);

function BreadthFirstLayout( options ){
  this.options = util.extend( {}, defaults, options );
}

BreadthFirstLayout.prototype.run = function(){
  let params = this.options;
  let options = params;

  let cy = params.cy;
  let eles = options.eles;
  let nodes = eles.nodes().filter( n => !n.isParent() );
  let graph = eles;
  let directed = options.directed;
  let maximal = options.maximal || options.maximalAdjustments > 0; // maximalAdjustments for compat. w/ old code

  let bb = math.makeBoundingBox( options.boundingBox ? options.boundingBox : {
    x1: 0, y1: 0, w: cy.width(), h: cy.height()
  } );

  let roots;
  if( is.elementOrCollection( options.roots ) ){
    roots = options.roots;
  } else if( is.array( options.roots ) ){
    let rootsArray = [];

    for( let i = 0; i < options.roots.length; i++ ){
      let id = options.roots[ i ];
      let ele = cy.getElementById( id );
      rootsArray.push( ele );
    }

    roots = cy.collection( rootsArray );
  } else if( is.string( options.roots ) ){
    roots = cy.$( options.roots );

  } else {
    if( directed ){
      roots = nodes.roots();
    } else {
      let components = eles.components();

      roots = cy.collection();
      for( let i = 0; i < components.length; i++ ){
        let comp = components[i];
        let maxDegree = comp.maxDegree( false );
        let compRoots = comp.filter( function( ele ){
          return ele.degree( false ) === maxDegree;
        } );

        roots = roots.add( compRoots );
      }

    }
  }

  let depths = [];
  let foundByBfs = {};

  let addToDepth = ( ele, d ) => {
    if( depths[d] == null ){
      depths[d] = [];
    }

    let i = depths[d].length;

    depths[d].push( ele );

    setInfo( ele, {
      index: i,
      depth: d
    } );
  };

  let changeDepth = ( ele, newDepth ) => {
    let { depth, index } = getInfo( ele );

    depths[ depth ][ index ] = null;

    addToDepth( ele, newDepth );
  };

  // find the depths of the nodes
  graph.bfs( {
    roots: roots,
    directed: options.directed,
    visit: function( node, edge, pNode, i, depth ){
      let ele = node[0];
      let id = ele.id();

      addToDepth( ele, depth );
      foundByBfs[ id ] = true;
    }
  } );

  // check for nodes not found by bfs
  let orphanNodes = [];
  for( let i = 0; i < nodes.length; i++ ){
    let ele = nodes[ i ];

    if( foundByBfs[ ele.id() ] ){
      continue;
    } else {
      orphanNodes.push( ele );
    }
  }

  // assign the nodes a depth and index

  let assignDepthsAt = function( i ){
    let eles = depths[ i ];

    for( let j = 0; j < eles.length; j++ ){
      let ele = eles[ j ];

      if( ele == null ){
        eles.splice( j, 1 );
        j--;
        continue;
      }

      setInfo(ele, {
        depth: i,
        index: j
      });
    }
  };

  let assignDepths = function(){
    for( let i = 0; i < depths.length; i++ ){
      assignDepthsAt( i );
    }
  };

  let adjustMaximally = function( ele, shifted ){
    let eInfo = getInfo( ele );
    let incomers = ele.incomers().filter( el => el.isNode() && eles.has(el) );
    let maxDepth = -1;
    let id = ele.id();

    for( let k = 0; k < incomers.length; k++ ){
      let incmr = incomers[k];
      let iInfo = getInfo( incmr );

      maxDepth = Math.max( maxDepth, iInfo.depth );
    }

    if( eInfo.depth <= maxDepth ){
      if( shifted[id] ){
        return null;
      }

      changeDepth( ele, maxDepth + 1 );
      shifted[id] = true;

      return true;
    }

    return false;
  };

  // for the directed case, try to make the edges all go down (i.e. depth i => depth i + 1)
  if( directed && maximal ){
    let Q = [];
    let shifted = {};

    let enqueue = n => Q.push(n);
    let dequeue = () => Q.shift();

    nodes.forEach( n => Q.push(n) );

    while( Q.length > 0 ){
      let ele = dequeue();
      let didShift = adjustMaximally( ele, shifted );

      if( didShift ){
        ele.outgoers().filter( el => el.isNode() && eles.has(el) ).forEach( enqueue );
      } else if( didShift === null ){
        util.warn('Detected double maximal shift for node `' + ele.id() + '`.  Bailing maximal adjustment due to cycle.  Use `options.maximal: true` only on DAGs.');

        break; // exit on failure
      }
    }
  }

  assignDepths(); // clear holes

  // find min distance we need to leave between nodes
  let minDistance = 0;
  if( options.avoidOverlap ){
    for( let i = 0; i < nodes.length; i++ ){
      let n = nodes[ i ];
      let nbb = n.layoutDimensions( options );
      let w = nbb.w;
      let h = nbb.h;

      minDistance = Math.max( minDistance, w, h );
    }
  }

  // get the weighted percent for an element based on its connectivity to other levels
  let cachedWeightedPercent = {};
  let getWeightedPercent = function( ele ){
    if( cachedWeightedPercent[ ele.id() ] ){
      return cachedWeightedPercent[ ele.id() ];
    }

    let eleDepth = getInfo( ele ).depth;
    let neighbors = ele.neighborhood();
    let percent = 0;
    let samples = 0;

    for( let i = 0; i < neighbors.length; i++ ){
      let neighbor = neighbors[ i ];

      if( neighbor.isEdge() || neighbor.isParent() || !nodes.has( neighbor ) ){
        continue;
      }

      let bf = getInfo( neighbor );
      let index = bf.index;
      let depth = bf.depth;

      // unassigned neighbours shouldn't affect the ordering
      if( index == null || depth == null ){
        continue;
      }

      let nDepth = depths[ depth ].length;

      if( depth < eleDepth ){ // only get influenced by elements above
        percent += index / nDepth;
        samples++;
      }
    }

    samples = Math.max( 1, samples );
    percent = percent / samples;

    if( samples === 0 ){ // put lone nodes at the start
      percent = 0;
    }

    cachedWeightedPercent[ ele.id() ] = percent;
    return percent;
  };

  // rearrange the indices in each depth level based on connectivity

  let sortFn = function( a, b ){
    let apct = getWeightedPercent( a );
    let bpct = getWeightedPercent( b );

    let diff = apct - bpct;

    if( diff === 0 ){
      return util.sort.ascending( a.id(), b.id() ); // make sure sort doesn't have don't-care comparisons
    } else {
      return diff;
    }
  };

  // sort each level to make connected nodes closer
  for( let i = 0; i < depths.length; i++ ){
    depths[ i ].sort( sortFn );
    assignDepthsAt( i );
  }

  // assign orphan nodes to a new top-level depth
  let orphanDepth = [];
  for( let i = 0; i < orphanNodes.length; i++ ){
    orphanDepth.push( orphanNodes[i] );
  }
  depths.unshift( orphanDepth );

  assignDepths();

  let biggestDepthSize = 0;
  for( let i = 0; i < depths.length; i++ ){
    biggestDepthSize = Math.max( depths[ i ].length, biggestDepthSize );
  }

  let center = {
    x: bb.x1 + bb.w / 2,
    y: bb.x1 + bb.h / 2
  };

  let maxDepthSize = depths.reduce( (max, eles) => Math.max(max, eles.length), 0 );

  let getPosition = function( ele ){
    let { depth, index } = getInfo( ele );
    let depthSize = depths[ depth ].length;

    let distanceX = Math.max( bb.w / ( (options.grid ? maxDepthSize : depthSize) + 1 ), minDistance );
    let distanceY = Math.max( bb.h / (depths.length + 1), minDistance );
    let radiusStepSize = Math.min( bb.w / 2 / depths.length, bb.h / 2 / depths.length );
    radiusStepSize = Math.max( radiusStepSize, minDistance );

    if( !options.circle ){
      let epos = {
        x: center.x + (index + 1 - (depthSize + 1) / 2) * distanceX,
        y: (depth + 1) * distanceY
      };

      return epos;
    } else {
      let radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize / 2 : 0);
      let theta = 2 * Math.PI / depths[ depth ].length * index;

      if( depth === 0 && depths[0].length === 1 ){
        radius = 1;
      }

      return {
        x: center.x + radius * Math.cos( theta ),
        y: center.y + radius * Math.sin( theta )
      };
    }

  };

  eles.nodes().layoutPositions( this, options, getPosition );

  return this; // chaining
};

export default BreadthFirstLayout;
<commit_msg>Layout not calculating correctly (breadthfirst, directed) #2821<commit_after>import * as util from '../../util';
import * as math from '../../math';
import * as is from '../../is';

/* eslint-disable no-unused-vars */
const defaults = {
  fit: true, // whether to fit the viewport to the graph
  directed: false, // whether the tree is directed downwards (or edges can point in any direction if false)
  padding: 30, // padding on fit
  circle: false, // put depths in concentric circles if true, put depths top down if false
  grid: false, // whether to create an even grid into which the DAG is placed (circle:false only)
  spacingFactor: 1.75, // positive spacing factor, larger => more space between nodes (N.B. n/a if causes overlap)
  boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }
  avoidOverlap: true, // prevents node overlap, may overflow boundingBox if not enough space
  nodeDimensionsIncludeLabels: false, // Excludes the label when calculating node bounding boxes for the layout algorithm
  roots: undefined, // the roots of the trees
  maximal: false, // whether to shift nodes down their natural BFS depths in order to avoid upwards edges (DAGS only)
  animate: false, // whether to transition the node positions
  animationDuration: 500, // duration of animation in ms if enabled
  animationEasing: undefined, // easing of animation if enabled,
  animateFilter: function ( node, i ){ return true; }, // a function that determines whether the node should be animated.  All nodes animated by default on animate enabled.  Non-animated nodes are positioned immediately when the layout starts
  ready: undefined, // callback on layoutready
  stop: undefined, // callback on layoutstop
  transform: function (node, position ){ return position; } // transform a given node position. Useful for changing flow direction in discrete layouts
};
/* eslint-enable */

const getInfo = ele => ele.scratch('breadthfirst');
const setInfo = (ele, obj) => ele.scratch('breadthfirst', obj);

function BreadthFirstLayout( options ){
  this.options = util.extend( {}, defaults, options );
}

BreadthFirstLayout.prototype.run = function(){
  let params = this.options;
  let options = params;

  let cy = params.cy;
  let eles = options.eles;
  let nodes = eles.nodes().filter( n => !n.isParent() );
  let graph = eles;
  let directed = options.directed;
  let maximal = options.maximal || options.maximalAdjustments > 0; // maximalAdjustments for compat. w/ old code

  let bb = math.makeBoundingBox( options.boundingBox ? options.boundingBox : {
    x1: 0, y1: 0, w: cy.width(), h: cy.height()
  } );

  let roots;
  if( is.elementOrCollection( options.roots ) ){
    roots = options.roots;
  } else if( is.array( options.roots ) ){
    let rootsArray = [];

    for( let i = 0; i < options.roots.length; i++ ){
      let id = options.roots[ i ];
      let ele = cy.getElementById( id );
      rootsArray.push( ele );
    }

    roots = cy.collection( rootsArray );
  } else if( is.string( options.roots ) ){
    roots = cy.$( options.roots );

  } else {
    if( directed ){
      roots = nodes.roots();
    } else {
      let components = eles.components();

      roots = cy.collection();
      for( let i = 0; i < components.length; i++ ){
        let comp = components[i];
        let maxDegree = comp.maxDegree( false );
        let compRoots = comp.filter( function( ele ){
          return ele.degree( false ) === maxDegree;
        } );

        roots = roots.add( compRoots );
      }

    }
  }

  let depths = [];
  let foundByBfs = {};

  let addToDepth = ( ele, d ) => {
    if( depths[d] == null ){
      depths[d] = [];
    }

    let i = depths[d].length;

    depths[d].push( ele );

    setInfo( ele, {
      index: i,
      depth: d
    } );
  };

  let changeDepth = ( ele, newDepth ) => {
    let { depth, index } = getInfo( ele );

    depths[ depth ][ index ] = null;

    addToDepth( ele, newDepth );
  };

  // find the depths of the nodes
  graph.bfs( {
    roots: roots,
    directed: options.directed,
    visit: function( node, edge, pNode, i, depth ){
      let ele = node[0];
      let id = ele.id();

      addToDepth( ele, depth );
      foundByBfs[ id ] = true;
    }
  } );

  // check for nodes not found by bfs
  let orphanNodes = [];
  for( let i = 0; i < nodes.length; i++ ){
    let ele = nodes[ i ];

    if( foundByBfs[ ele.id() ] ){
      continue;
    } else {
      orphanNodes.push( ele );
    }
  }

  // assign the nodes a depth and index

  let assignDepthsAt = function( i ){
    let eles = depths[ i ];

    for( let j = 0; j < eles.length; j++ ){
      let ele = eles[ j ];

      if( ele == null ){
        eles.splice( j, 1 );
        j--;
        continue;
      }

      setInfo(ele, {
        depth: i,
        index: j
      });
    }
  };

  let assignDepths = function(){
    for( let i = 0; i < depths.length; i++ ){
      assignDepthsAt( i );
    }
  };

  let adjustMaximally = function( ele, shifted ){
    let eInfo = getInfo( ele );
    let incomers = ele.incomers().filter( el => el.isNode() && eles.has(el) );
    let maxDepth = -1;
    let id = ele.id();

    for( let k = 0; k < incomers.length; k++ ){
      let incmr = incomers[k];
      let iInfo = getInfo( incmr );

      maxDepth = Math.max( maxDepth, iInfo.depth );
    }

    if( eInfo.depth <= maxDepth ){
      if( shifted[id] ){
        return null;
      }

      changeDepth( ele, maxDepth + 1 );
      shifted[id] = true;

      return true;
    }

    return false;
  };

  // for the directed case, try to make the edges all go down (i.e. depth i => depth i + 1)
  if( directed && maximal ){
    let Q = [];
    let shifted = {};

    let enqueue = n => Q.push(n);
    let dequeue = () => Q.shift();

    nodes.forEach( n => Q.push(n) );

    while( Q.length > 0 ){
      let ele = dequeue();
      let didShift = adjustMaximally( ele, shifted );

      if( didShift ){
        ele.outgoers().filter( el => el.isNode() && eles.has(el) ).forEach( enqueue );
      } else if( didShift === null ){
        util.warn('Detected double maximal shift for node `' + ele.id() + '`.  Bailing maximal adjustment due to cycle.  Use `options.maximal: true` only on DAGs.');

        break; // exit on failure
      }
    }
  }

  assignDepths(); // clear holes

  // find min distance we need to leave between nodes
  let minDistance = 0;
  if( options.avoidOverlap ){
    for( let i = 0; i < nodes.length; i++ ){
      let n = nodes[ i ];
      let nbb = n.layoutDimensions( options );
      let w = nbb.w;
      let h = nbb.h;

      minDistance = Math.max( minDistance, w, h );
    }
  }

  // get the weighted percent for an element based on its connectivity to other levels
  let cachedWeightedPercent = {};
  let getWeightedPercent = function( ele ){
    if( cachedWeightedPercent[ ele.id() ] ){
      return cachedWeightedPercent[ ele.id() ];
    }

    let eleDepth = getInfo( ele ).depth;
    let neighbors = ele.neighborhood();
    let percent = 0;
    let samples = 0;

    for( let i = 0; i < neighbors.length; i++ ){
      let neighbor = neighbors[ i ];

      if( neighbor.isEdge() || neighbor.isParent() || !nodes.has( neighbor ) ){
        continue;
      }

      let bf = getInfo( neighbor );

      if (bf == null){ continue; }

      let index = bf.index;
      let depth = bf.depth;

      // unassigned neighbours shouldn't affect the ordering
      if( index == null || depth == null ){
        continue;
      }

      let nDepth = depths[ depth ].length;

      if( depth < eleDepth ){ // only get influenced by elements above
        percent += index / nDepth;
        samples++;
      }
    }

    samples = Math.max( 1, samples );
    percent = percent / samples;

    if( samples === 0 ){ // put lone nodes at the start
      percent = 0;
    }

    cachedWeightedPercent[ ele.id() ] = percent;
    return percent;
  };

  // rearrange the indices in each depth level based on connectivity

  let sortFn = function( a, b ){
    let apct = getWeightedPercent( a );
    let bpct = getWeightedPercent( b );

    let diff = apct - bpct;

    if( diff === 0 ){
      return util.sort.ascending( a.id(), b.id() ); // make sure sort doesn't have don't-care comparisons
    } else {
      return diff;
    }
  };

  // sort each level to make connected nodes closer
  for( let i = 0; i < depths.length; i++ ){
    depths[ i ].sort( sortFn );
    assignDepthsAt( i );
  }

  // assign orphan nodes to a new top-level depth
  let orphanDepth = [];
  for( let i = 0; i < orphanNodes.length; i++ ){
    orphanDepth.push( orphanNodes[i] );
  }
  depths.unshift( orphanDepth );

  assignDepths();

  let biggestDepthSize = 0;
  for( let i = 0; i < depths.length; i++ ){
    biggestDepthSize = Math.max( depths[ i ].length, biggestDepthSize );
  }

  let center = {
    x: bb.x1 + bb.w / 2,
    y: bb.x1 + bb.h / 2
  };

  let maxDepthSize = depths.reduce( (max, eles) => Math.max(max, eles.length), 0 );

  let getPosition = function( ele ){
    let { depth, index } = getInfo( ele );
    let depthSize = depths[ depth ].length;

    let distanceX = Math.max( bb.w / ( (options.grid ? maxDepthSize : depthSize) + 1 ), minDistance );
    let distanceY = Math.max( bb.h / (depths.length + 1), minDistance );
    let radiusStepSize = Math.min( bb.w / 2 / depths.length, bb.h / 2 / depths.length );
    radiusStepSize = Math.max( radiusStepSize, minDistance );

    if( !options.circle ){
      let epos = {
        x: center.x + (index + 1 - (depthSize + 1) / 2) * distanceX,
        y: (depth + 1) * distanceY
      };

      return epos;
    } else {
      let radius = radiusStepSize * depth + radiusStepSize - (depths.length > 0 && depths[0].length <= 3 ? radiusStepSize / 2 : 0);
      let theta = 2 * Math.PI / depths[ depth ].length * index;

      if( depth === 0 && depths[0].length === 1 ){
        radius = 1;
      }

      return {
        x: center.x + radius * Math.cos( theta ),
        y: center.y + radius * Math.sin( theta )
      };
    }

  };

  eles.nodes().layoutPositions( this, options, getPosition );

  return this; // chaining
};

export default BreadthFirstLayout;
<|endoftext|>


<commit_before>/*
 * grunt-photoBox
 * https://github.com/stefan/grunt-photoBox
 *
 * Copyright (c) 2013 stefan judis
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function( grunt ) {
  grunt.registerTask(
    'photoBox',
    'Take screenshots for different url\'s and compare them.',
    function() {
      var done     = this.async(),
          options  = this.options( {
            indexPath   : 'photoBox/',
            screensizes : [ {
              width  : 400,
              height : 900
            } ],
            urls        : [ 'http://google.com' ]
          } ),
          PhotoBox = require( './lib/photoBox' ),
          pb       = new PhotoBox( grunt, options, done );

      pb.startPhotoSession();
    }
  );
};
<commit_msg>added "better" defaults to task<commit_after>/*
 * grunt-photoBox
 * https://github.com/stefan/grunt-photoBox
 *
 * Copyright (c) 2013 stefan judis
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function( grunt ) {
  grunt.registerTask(
    'photoBox',
    'Take screenshots for different url\'s and compare them.',
    function() {
      var done     = this.async(),
          options  = this.options( {
            indexPath   : 'photoBox/',
            screensizes : [ {
              width  : 800,
              height : 900
            } ],
            urls        : [ 'http://4waisenkinder.de' ]
          } ),
          PhotoBox = require( './lib/photoBox' ),
          pb       = new PhotoBox( grunt, options, done );

      pb.startPhotoSession();
    }
  );
};
<|endoftext|>


<commit_before>function clearFilters(){
  $(".closing-icon").remove();
  $(".active_tag").removeClass('active_tag');
  $('.card').show();
}

function toggleTags(button, tag){
  if(button.attr('class').indexOf('active_tag') > -1){
    button.removeClass("active_tag");
    button.html(tag);
  } else {
    button.html(tag + 'close');
    button.addClass("active_tag");
  }
}

function addActiveTags(buttons){
  var active_tags = [];
  for(var j=0; j < buttons.length; j++){
    current_button = $(buttons[j]);
    if(current_button.attr('class').indexOf('active_tag') > -1){
      active_tags.push(current_button.attr('val'));
    }
  }
  return active_tags;
}

function showProjects(projects, active_tags){
  projects.each(function(i){
    var project = $(projects[i]);
    project.hide();

    $.each(active_tags, function(k){
      var active_tag = active_tags[k],
      projectContainsTag = project.attr('tags').indexOf(active_tag) > -1,
      activeTagsAreEmpty = active_tags == [];

      if( projectContainsTag || activeTagsAreEmpty){
        project.show();
      }
    })
  })
}

$(document).ready(function(){
  $(".button-collapse").sideNav({
    menuWidth: 200,
    edge: 'left',
    closeOnClick: true,
    draggable: true
  });

  var colors = {
        'about': 'rgb(142,85,114)',
        'projects': '#F46036',
        'algorithms': '#2E294E'
      },
      address = window.location.href.split('/'),
      pagename = address[address.length - 1];

  $('body').css('background-color', colors[pagename]);
  $('.card-action a').css('color', colors[pagename]);
  $('nav a').attr('style', 'color: ' + colors[pagename] + '');
  $("a:contains('" + pagename + "')").parent().css('background-color', colors[pagename]);
  $("a:contains('" + pagename + "')").css('color', "white");

  $('.tag').click(function(event){
    event.preventDefault();

    $(this).children().remove('i');

    var button = $(this),
        tag = $(this).attr('val'),
        projects = $('.card'),
        buttons = $('.btn'),
        active_tags = [],
        needToClearFilters = tag === "clear-filters";

    if(needToClearFilters){
      clearFilters();
    } else{
      toggleTags(button, tag);
      active_tags = addActiveTags(buttons);
      showProjects(projects, active_tags);
    }
  })
});
<commit_msg>add functionality to display all projects if tags are empty<commit_after>function clearFilters(){
  $(".closing-icon").remove();
  $(".active_tag").removeClass('active_tag');
  $('.card').show();
}

function toggleTags(button, tag){
  if(button.attr('class').indexOf('active_tag') > -1){
    button.removeClass("active_tag");
    button.html(tag);
  } else {
    button.html(tag + 'close');
    button.addClass("active_tag");
  }
}

function addActiveTags(buttons){
  var active_tags = [];
  for(var j=0; j < buttons.length; j++){
    current_button = $(buttons[j]);
    if(current_button.attr('class').indexOf('active_tag') > -1){
      active_tags.push(current_button.attr('val'));
    }
  }
  return active_tags;
}

function showProjects(projects, active_tags){
  projects.each(function(i){
    var project = $(projects[i]);
    project.hide();

    $.each(active_tags, function(k){
      var active_tag = active_tags[k],
      projectContainsTag = project.attr('tags').indexOf(active_tag) > -1;

      if( projectContainsTag){
        project.show();
      }
    })
  })

  var activeTagsAreEmpty = active_tags.length === 0;

  if(activeTagsAreEmpty){
    projects.show();
  }
}

$(document).ready(function(){
  $(".button-collapse").sideNav({
    menuWidth: 200,
    edge: 'left',
    closeOnClick: true,
    draggable: true
  });

  var colors = {
        'about': 'rgb(142,85,114)',
        'projects': '#F46036',
        'algorithms': '#2E294E'
      },
      address = window.location.href.split('/'),
      pagename = address[address.length - 1];

  $('body').css('background-color', colors[pagename]);
  $('.card-action a').css('color', colors[pagename]);
  $('nav a').attr('style', 'color: ' + colors[pagename] + '');
  $("a:contains('" + pagename + "')").parent().css('background-color', colors[pagename]);
  $("a:contains('" + pagename + "')").css('color', "white");

  $('.tag').click(function(event){
    event.preventDefault();

    $(this).children().remove('i');

    var button = $(this),
        tag = $(this).attr('val'),
        projects = $('.card'),
        buttons = $('.btn'),
        active_tags = [],
        needToClearFilters = tag === "clear-filters";

    if(needToClearFilters){
      clearFilters();
    } else{
      toggleTags(button, tag);
      active_tags = addActiveTags(buttons);
      showProjects(projects, active_tags);
    }
  })
});
<|endoftext|>


<commit_before>var logParams = require('../config.js').getLogOpt();
var log = require('log4js').getLogger(logParams.output);
var _ = require('underscore');

module.exports.getPostgresType = function(type){
  if (type =='coords')
    return 'geometry(Point,4326)';
  else if (type == 'string')
    return 'text'
  else if (type == 'integer')
    return 'integer'
  else if (type == 'float')
    return 'double precision'
  else if (type == 'ISO8601' || type == 'timestamp')
    return 'timestamp without time zone';
}

module.exports.getValueForType = function(value,type){
  if (type=='coords'){
    var s = value.split(',');
    return 'ST_SetSRID(ST_MakePoint(' + s[1].trim() + ',' + s[0].trim() + '),4326)';
  }
  else if (type == 'string' || type == 'ISO8601' || type == 'integer' || type == 'float' || type == 'timestamp')
    return value;
  else{
    log.error('Unknown type: ' + type);
    throw Error('Unknown type: ' + type);
  }
}

module.exports.isTypeQuoted = function(type){
  if (type=='coords' || type == 'integer' || type == 'float')
    return false;
  else if (type == 'string' || type == 'ISO8601' || type == 'timestamp')
    return true;
  else{
    log.error('Unknown type: ' + type);
    throw Error('Unknown type: ' + type);
  }
}

module.exports.wrapStrings = function(value,wrap) {
  if (wrap.length == 1)
    return [wrap[0],value,wrap[0]].join('')
  else if (wrap.length == 2)
    return [wrap[0],value,wrap[1]].join('')
  else{
    log.error('Wrap length must be 1 or 2');
    throw Error('Wrap length must be 1 or 2');
  }
}

module.exports.parseLatLon = function(subattr) {
  if (_.find(subattr,{namedb:'lat',type:'coords'}) && _.find(subattr,{namedb:'lon',type:'coords'}) &&
      (!_.find(subattr,{name:'position',type:'coords'}) || !_.find(subattr,{namedb:'position',type:'coords'}))){
        subattr.push({name:'position',type:'coords',cartodb:true});
        subattr = _.without(subattr,_.find(subattr,{namedb:'lat'}),_.find(subattr,{namedb:'lon'}));
  }
  return subattr;
}
<commit_msg>Added GeoJSON feature, but it\'s untested yet<commit_after>var logParams = require('../config.js').getLogOpt();
var log = require('log4js').getLogger(logParams.output);
var _ = require('underscore');

module.exports.getPostgresType = function(type){
  if (type === 'coords' || type === 'geojson')
    return 'geometry(Point,4326)';
  else if (type === 'string')
    return 'text';
  else if (type === 'integer')
    return 'integer';
  else if (type === 'float')
    return 'double precision';
  else if (type === 'ISO8601' || type === 'timestamp')
    return 'timestamp without time zone';
}

module.exports.getValueForType = function(value,type){
  if (type === 'coords') {
    var s = value.split(',');
    return 'ST_SetSRID(ST_MakePoint(' + s[1].trim() + ',' + s[0].trim() + '),4326)';

  } else if (type == 'geojson') {
    if (typeof value !== 'object') {
      value = JSON.parse(value);
    }

    if (!value.hasOwnProperty('type') ||
        !value.hasOwnProperty('coordinates') ||
        value.coordinates.constructor !== Array) {
      log.error(type + 'isn\'t a valid GeoJSON');
      throw Error(type + 'isn\'t a valid GeoJSON');
    }

    // Isn't worth it to check if they are floats...
    value.coordinates[0] = parseFloat(value.coordinates[0]);
    value.coordinates[1] = parseFloat(value.coordinates[1]);

    value = JSON.stringify(value);
    return 'ST_SetSRID(ST_GeomFromGeoJSON(\'' + value + '\'))';

  } else if (type === 'string' || type === 'ISO8601' || type === 'integer' || type === 'float' || type === 'timestamp') {
    return value;

  } else {
    log.error('Unknown type: ' + type);
    throw Error('Unknown type: ' + type);
  }
};

module.exports.isTypeQuoted = function(type){
  if (type === 'coords' || type === 'geojson' || type === 'integer' || type === 'float') {
    return false;

  } else if (type === 'string' || type === 'ISO8601' || type === 'timestamp') {
    return true;

  } else {
    log.error('Unknown type: ' + type);
    throw Error('Unknown type: ' + type);
  }
};

module.exports.wrapStrings = function(value,wrap) {
  if (wrap.length == 1)
    return [wrap[0],value,wrap[0]].join('')
  else if (wrap.length == 2)
    return [wrap[0],value,wrap[1]].join('')
  else{
    log.error('Wrap length must be 1 or 2');
    throw Error('Wrap length must be 1 or 2');
  }
}

module.exports.parseLatLon = function(subattr) {
  if (_.find(subattr,{namedb:'lat',type:'coords'}) && _.find(subattr,{namedb:'lon',type:'coords'}) &&
      (!_.find(subattr,{name:'position',type:'coords'}) || !_.find(subattr,{namedb:'position',type:'coords'}))){
        subattr.push({name:'position',type:'coords',cartodb:true});
        subattr = _.without(subattr,_.find(subattr,{namedb:'lat'}),_.find(subattr,{namedb:'lon'}));
  }
  return subattr;
}
<|endoftext|>


<commit_before>'use strict';

var piedmont = require('piedmont'),
  process = require('process');

module.exports = function (grunt) {

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

  grunt.registerMultiTask('piedmont', 'Generate a Living Styleguide based on a Frontend Prototype', function () {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
        dest: './styling-guidelines',
        docs: './docs',
        src: './dist',
        styles: './src/sass',
        tmp: '.tmp/styleguide'
      }),
      done = this.async();

    piedmont({
      cwd: process.cwd(),
      dest: options.dest,
      docs: options.docs,
      src: options.src,
      styles: options.styles,
      tmp: options.tmp
    }, done);

    grunt.log.writeln('Waiting for the files to be written...');
  });
};
<commit_msg>Better code style<commit_after>'use strict';

var piedmont = require('piedmont');
var process = require('process');

module.exports = function (grunt) {

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

  grunt.registerMultiTask('piedmont', 'Generate a Living Styleguide based on a Frontend Prototype', function () {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
        dest: './styling-guidelines',
        docs: './docs',
        src: './dist',
        styles: './src/sass',
        tmp: '.tmp/styleguide'
      });
    var done = this.async();

    piedmont({
      cwd: process.cwd(),
      dest: options.dest,
      docs: options.docs,
      src: options.src,
      styles: options.styles,
      tmp: options.tmp
    }, done);

    grunt.log.writeln('Waiting for the files to be written...');
  });
};
<|endoftext|>