<commit_before>
var DAY = 1000 * 60 * 60 * 24;
var daysStoreArticles = 2;
var updateInterval = 1000 * 60 * 15;
var intervalProcesses = {};
var articlePubLimit = 300;

Accounts.config({sendVerificationEmail: true});

var Feeds = new Meteor.Collection("feeds");
var Articles = new Meteor.Collection("articles");
Articles._ensureIndex( {"date": 1} );

Meteor.publish("feeds", function () {
               var self = this;
               return Feeds.find({subscribers: self.userId }, {_id: 1, title: 1, url:1, last_date:1});
               });

Meteor.publish( "articles", function(){
               var self= this;
               var feed_ids = [];
               Feeds.find({subscribers: self.userId }, {_id: 1}).observeChanges({
                                                                                added: function (id){
                                                                                feed_ids.push(id);
                                                                                },

                                                                                removed: function (id){
                                                                                var ax;
                                                                                while (( ax = feed_ids.indexOf(id)) !== -1) {
                                                                                feed_ids.splice(ax, 1);
                                                                                }

                                                                                }

                                        });

               return Articles.find({feed_id: {$in: feed_ids}}, {sort: {date: -1}, limit: articlePubLimit, fields: {title: 1, source:1, date:1, summary:1, link:1}} );

               });

Articles.allow({
               insert: function ( doc ) {
               return false //(userId && doc.owner === userId);
               },
               update: function (userId, doc, fieldNames, modifier ) {
               return false;
               },

               remove: function ( doc ) {
               // can only remove your own documents
               return false //doc.owner === userId;
               }
               //fetch: ['owner']
               });

Feeds.allow({
            insert: function (userId, doc) {
            return doc.subscribers[0] === userId;
            },

            update: function (doc, fields, modifier) {
            // can only change your own documents
            return false //doc.owner === userId;
            },

            remove: function(userId, doc){
            if(doc.subscribers.length > 1){
            console.log(JSON.stringify (doc) );
            Feeds.update(doc._id, {$pull: {subscribers: userId}} );
            return false;
            }
            else{
            return doc.subscribers[0] === userId;
            }
            }

            //fetch: ['owner']
            });

Feeds.deny({
           insert: function(userId, doc){
           var existingFeed = Feeds.findOne({url: doc.url});
           if( existingFeed ){
            Feeds.update(existingFeed._id, {$addToSet: {subscribers: userId}});
            return true;
           }

           var rssResult = syncFP( doc.url);
           if (rssResult.meta === null || rssResult.meta === undefined){
           console.log(doc.url + " has no data to insert");
           return true;
           }
           else if (rssResult.meta.url && doc.url !== rssResult.meta.url ) { doc.url = rssResult.meta.url; }
           existingFeed = Feeds.findOne( {url: doc.url} );

           if( existingFeed ){
           Feeds.update(existingFeed._id, {$addToSet: {subscribers: userId}});
           return true;
           }
           else{
           console.log(doc.url + " not in db - adding");
           doc.title = rssResult.meta.title;
           doc.last_date = rssResult.meta.date;
           doc.articles = rssResult.articles;
           doc.subscribers = [];
           doc.subscribers.push(userId);
           return false;
           }

           }

});

Meteor.startup( function(){

               if ( !intervalProcesses[ "removeOldArticles"] ){
               var process = Meteor.setInterval(function (){
                                                Meteor.call('removeOldArticles'); },
                                                DAY);
               intervalProcesses["removeOldArticles"] = process;
               }

               if ( !intervalProcesses[ "findArticles"] ){
               var process = Meteor.setInterval( function(){
                                                console.log( Meteor.call('findArticles') + " added to db" );
                                                },
                                                updateInterval);
               intervalProcesses[ "findArticles"] = process;
               console.log("updating on");
               }

               });

var newArticlesToDb = function(articlesFromWeb, meta){ //using metadata rather than feed from database -> feed should be up to date and passed if needed
  var existingArticles={};
  var last_dates = {};
  var article_count=0;
  var feed = Feeds.findOne({url: meta.url}); // see comment above
  Articles.find({feed_id: feed._id},{guid:1, date:1}).forEach(function(article){
                                                               existingArticles[article.guid]=1;

                                                              });
  maxDate = meta.date || 0;
  articlesFromWeb.forEach(function (article) {

                          var date = article.date || new Date();
                          date = new Date(date);
                          maxDate = (date > maxDate) ? date : maxDate;
                          if ( (new Date() - date) / DAY <= daysStoreArticles ){
                          var new_article = {
                          title: article.title,
                          guid: article.guid,
                          summary: cleanSummary( article.description ),
                          date: date,
                          author: article.author,
                          link: article.link,
                          source: meta.title,
                          feed_id: feed._id
                          };
                          if(existingArticles[new_article.guid] != 1){
                          Articles.insert(new_article);

                          article_count++;
                          console.log('%s: %s', meta.title, article.title || article.description);
                          }
                          }
                          });
  if (article_count > 0){
    var feed_date = feed.last_date;
    if (feed_date === null || maxDate > feed_date){
      Feeds.update(feed._id, {$set:{last_date: maxDate}});
    }
  }
  return article_count;
}

var cleanSummary = function (text){
  var $ = cheerio.load(text);  //relies on cheerio package

  $('img').remove();
  $('table').remove();
  $('script').remove();
  $('iframe').remove();
  $('.feedflare').remove();

  if( $('p').length )
    {
    text = $('p').eq(0).html() + ( $('p').eq(1).html() || '');
    }
  else if( $('li').length ){
    text = '
';
    $('ul li').slice(0,6).each( function(){
                               text += "
" + $(this).html() + "
";
                               });
    text += "
";
  }

  else{
    if ( $.html() ){
        text = $.html();
    }
    if ( text.indexOf('<br') !== -1 ){
      text = text.substring(0, text.indexOf('<br'));
    }

    text = text.substring(0, 500);
  }

  if (text === null || text === undefined || text === "null") {
    text = '';
  }
  return text;
}

  //recursively read javascript object tree looking for urls of rss feeds
var eachRecursive = function (obj, resultArr) {
  for (var k in obj)
    {

    if (typeof obj[k] === "object"){
      eachRecursive(obj[k], resultArr);
    }
    else{
      if (k === 'xmlUrl'){
        resultArr.push( obj['xmlUrl'] );
      }
    }
    }
}

/** a first effort at parsing rss.  probably not much need for it if feedParser works

var rssUrlHandler = function(urls){
  var futures = _.map(urls, function(url){
                      var future = new Future();
                      var onComplete = future.resolver();

                      if ( url.indexOf('http://') === -1 && url.indexOf('https://') === -1 ) {
                      console.log(url);
                      url = 'http://' + url;
                      }

                      Meteor.http.get(url, function (error, result) {
                                      if( error){
                                      console.log( error );
                                      }
                                      if ( result.statusCode === 200 ){
                                      var $ = cheerio.load (result.content);
                                      console.log( $('channel').find('title').text() );
                                      var meta = {};

                                      meta['title'] = $('channel').title;
                                      meta['date'] = $('channel').pubDate || $('channel').PubDate;
                                      meta['xmlUrl'] = $('channel').xmlUrl || url;

                                      var articles = $('item');
                                      var object = {};
                                      console.log(url + " : " + meta.title);
                                      object["meta"] = meta;
                                      object["articles"] = articles;

                                      onComplete( object );
                                      }

                          });
                      return future;
                      });
  Future.wait(futures);

  console.log('finished reading feeds');
  return _.invoke(futures,'get');
}
 **/

var handle = Feeds.find({}, {sort:{_id: 1}}).observe({
                                                     _suppress_initial: true,

                                                     added: function(doc){
                                                     if (doc.articles) {
                                                     console.log( "found " + newArticlesToDb(doc.articles, doc) + " for new feed - " + doc.title);
                                                     Feeds.update(doc._id, {$unset: {articles: 1}});
                                                     }
                                                     else{
                                                     result = syncFP(doc.url);
                                                     console.log( "found " + newArticlesToDb(result.articles, doc) + " for new feed - " + doc.title);
                                                     }

                                                     },

                                                     removed: function(doc){

                                                     Articles.find({source: doc.title}, {_id:1}).forEach( function (article){
                                                                                console.log("removing article " + article._id);
                                                                                Articles.remove(article._id);
                                                                                });

                                                     }

                                                     });

Meteor.methods({

               findArticles: function() {
               console.log("looking for new articles");
               var article_count = 0;
               /**
               Feeds.find({}).forEach( function(feed){
                                      if ( feed.url !== null && feed.url !== undefined && feed.url !== "null" ){

                                      var rssResult = syncFP( feed.url);
                                      if (rssResult && rssResult.articles && rssResult.meta){
                                      article_count += newArticlesToDb (rssResult.articles, rssResult.meta);
                                      }
                                      else{
                                      console.log( "feed returned no data : " + feed.url);
                                      }

                                      }
                                      else{
                                      console.log( "feed with no URL - removing : " + JSON.stringify (feed));
                                      Feeds.remove( feed._id );
                                      }
                                      });
               **/

               var urls = [];
               Feeds.find({}).forEach( function(feed){
                                      if ( feed.url !== null && feed.url !== undefined && feed.url !== "null" ){
                                      urls.push( feed.url);
                                      }
                                      else{
                                      console.log( "feed with no URL - removing : " + JSON.stringify (feed));
                                           Feeds.remove( feed._id );
                                      }
                                      });

               var rssResults = multipleSyncFP (urls);

               rssResults.forEach(function(rssResult){
                                  if (rssResult && rssResult.articles && rssResult.meta){
                                  article_count += newArticlesToDb (rssResult.articles, rssResult.meta);
                                  }
                                  else{
                                  console.log( "a feed returned no data");
                                  }
                                  });

               console.log("finished find articles");
               return article_count;
               },

               removeOldArticles: function(){
                 console.log("removeOldArticles method called on server");
                 var dateLimit = new Date(new Date() - (daysStoreArticles* DAY));

                 var error = Articles.remove({date:  {$lt: dateLimit} }, function(error){ return error;});

                 return error || 'success';
               },

               addSubscriberToFeeds: function(){
               var self = this;
               Feeds.find({}).forEach( function (feed){
                                      console.log("adding subscriber " + self.userId);
                                       Feeds.update( feed._id,{ $addToSet: { subscribers: self.userId }});
                                       });
               },

               addFeed_idToArticles: function(){
               Articles.find({}).forEach( function (article){
                                         var feed_id = Feeds.findOne({title: article.source})._id;
                                         Articles.update(article._id,{$set: {feed_id: feed_id}});
                                         });

               },

               cleanUrls: function(){
               Feeds.find({}).forEach( function(feed){
                                      var result = syncFP(feed.url);
                                      if (result.meta.url && feed.url !== result.meta.url ){
                                      console.log("changing url " + feed.url + " to " + result.meta.url);
                                      Feeds.update(feed._id, {$set: {url: result.meta.url }});
                                      }
                                      });
               },

               importOPML: function(upload){
               var self = this;
               var opml = XML2JS.parse(upload);
               var xmlToAdd = [];
               eachRecursive(opml, xmlToAdd);
               var fpResults = [];

               xmlToAdd.forEach( function(url){
                                try{
                                if (url !== null && url !== undefined){
                                fpResults.push( syncFP(url) );
                                }
                                }
                                catch(e){
                                console.log( e + " parsing url " + url);
                                }
                                });
               console.log( "finished with feedparser");
               if ( fpResults ){
               fpResults.forEach( function (rssResult){

                                 var doc = {url: rssResult.meta.url, title: rssResult.meta.title, last_date: rssResult.meta.date, subscribers: [] };
                                 doc.subscribers.push(self.userId);

                                 var existingFeed = Feeds.findOne( {url: doc.url} );
                                 if( existingFeed ){
                                 Feeds.update(existingFeed._id, {$addToSet: {subscribers: self.userId} } );
                                 console.log( rssResult.meta.title +" in db - subscribing user");
                                 }

                                else {
                                 console.log(doc.url + " not in db - adding");
                                 doc.articles = rssResult.articles;
                                 Feeds.insert(doc);
                                 }

                                });
               }
               },

               clientSyncFP : function(url){
               try{

               return syncFP(url);

               }
               catch(e){

               return e;
               }
               }

               });

<commit_msg>speed findArticles by checking if guid already exists sooner<commit_after>
var DAY = 1000 * 60 * 60 * 24;
var daysStoreArticles = 2;
var updateInterval = 1000 * 60 * 15;
var intervalProcesses = {};
var articlePubLimit = 300;

Accounts.config({sendVerificationEmail: true});

var Feeds = new Meteor.Collection("feeds");
var Articles = new Meteor.Collection("articles");
Articles._ensureIndex( {"date": 1} );

Meteor.publish("feeds", function () {
               var self = this;
               return Feeds.find({subscribers: self.userId }, {_id: 1, title: 1, url:1, last_date:1});
               });

Meteor.publish( "articles", function(){
               var self= this;
               var feed_ids = [];
               Feeds.find({subscribers: self.userId }, {_id: 1}).observeChanges({
                                                                                added: function (id){
                                                                                feed_ids.push(id);
                                                                                },

                                                                                removed: function (id){
                                                                                var ax;
                                                                                while (( ax = feed_ids.indexOf(id)) !== -1) {
                                                                                feed_ids.splice(ax, 1);
                                                                                }

                                                                                }

                                        });

               return Articles.find({feed_id: {$in: feed_ids}}, {sort: {date: -1}, limit: articlePubLimit, fields: {title: 1, source:1, date:1, summary:1, link:1}} );

               });

Articles.allow({
               insert: function ( doc ) {
               return false //(userId && doc.owner === userId);
               },
               update: function (userId, doc, fieldNames, modifier ) {
               return false;
               },

               remove: function ( doc ) {
               // can only remove your own documents
               return false //doc.owner === userId;
               }
               //fetch: ['owner']
               });

Feeds.allow({
            insert: function (userId, doc) {
            return doc.subscribers[0] === userId;
            },

            update: function (doc, fields, modifier) {
            // can only change your own documents
            return false //doc.owner === userId;
            },

            remove: function(userId, doc){
            if(doc.subscribers.length > 1){
            console.log(JSON.stringify (doc) );
            Feeds.update(doc._id, {$pull: {subscribers: userId}} );
            return false;
            }
            else{
            return doc.subscribers[0] === userId;
            }
            }

            //fetch: ['owner']
            });

Feeds.deny({
           insert: function(userId, doc){
           var existingFeed = Feeds.findOne({url: doc.url});
           if( existingFeed ){
            Feeds.update(existingFeed._id, {$addToSet: {subscribers: userId}});
            return true;
           }

           var rssResult = syncFP( doc.url);
           if (rssResult.meta === null || rssResult.meta === undefined){
           console.log(doc.url + " has no data to insert");
           return true;
           }
           else if (rssResult.meta.url && doc.url !== rssResult.meta.url ) { doc.url = rssResult.meta.url; }
           existingFeed = Feeds.findOne( {url: doc.url} );

           if( existingFeed ){
           Feeds.update(existingFeed._id, {$addToSet: {subscribers: userId}});
           return true;
           }
           else{
           console.log(doc.url + " not in db - adding");
           doc.title = rssResult.meta.title;
           doc.last_date = rssResult.meta.date;
           doc.articles = rssResult.articles;
           doc.subscribers = [];
           doc.subscribers.push(userId);
           return false;
           }

           }

});

Meteor.startup( function(){

               if ( !intervalProcesses[ "removeOldArticles"] ){
               var process = Meteor.setInterval(function (){
                                                Meteor.call('removeOldArticles'); },
                                                DAY);
               intervalProcesses["removeOldArticles"] = process;
               }

               if ( !intervalProcesses[ "findArticles"] ){
               var process = Meteor.setInterval( function(){
                                                console.log( Meteor.call('findArticles') + " added to db" );
                                                },
                                                updateInterval);
               intervalProcesses[ "findArticles"] = process;
               console.log("updating on");
               }

               });

var newArticlesToDb = function(articlesFromWeb, meta){ //using metadata rather than feed from database -> feed should be up to date and passed if needed
  var existingArticles={};
  var last_dates = {};
  var article_count=0;
  var feed = Feeds.findOne({url: meta.url}); // see comment above
  Articles.find({feed_id: feed._id},{guid:1, date:1}).forEach(function(article){
                                                               existingArticles[article.guid]=1;

                                                              });
  maxDate = meta.date || 0;
  articlesFromWeb.forEach(function (article) {

                          if(existingArticles[article.guid] != 1){
                          var date = article.date || new Date();
                          date = new Date(date);
                          maxDate = (date > maxDate) ? date : maxDate;
                          if ( (new Date() - date) / DAY <= daysStoreArticles ){
                          var new_article = {
                          title: article.title,
                          guid: article.guid,
                          summary: cleanSummary( article.description ),
                          date: date,
                          author: article.author,
                          link: article.link,
                          source: meta.title,
                          feed_id: feed._id
                          };

                          Articles.insert(new_article);

                          article_count++;
                          console.log('%s: %s', meta.title, article.title || article.description);
                          }
                          }
                          });
  if (article_count > 0){
    var feed_date = feed.last_date;
    if (feed_date === null || maxDate > feed_date){
      Feeds.update(feed._id, {$set:{last_date: maxDate}});
    }
  }
  return article_count;
}

var cleanSummary = function (text){
  var $ = cheerio.load(text);  //relies on cheerio package

  $('img').remove();
  $('table').remove();
  $('script').remove();
  $('iframe').remove();
  $('.feedflare').remove();

  if( $('p').length )
    {
    text = $('p').eq(0).html() + ( $('p').eq(1).html() || '');
    }
  else if( $('li').length ){
    text = '
';
    $('ul li').slice(0,6).each( function(){
                               text += "
" + $(this).html() + "
";
                               });
    text += "
";
  }

  else{
    if ( $.html() ){
        text = $.html();
    }
    if ( text.indexOf('<br') !== -1 ){
      text = text.substring(0, text.indexOf('<br'));
    }

    text = text.substring(0, 500);
  }

  if (text === null || text === undefined || text === "null") {
    text = '';
  }
  return text;
}

  //recursively read javascript object tree looking for urls of rss feeds
var eachRecursive = function (obj, resultArr) {
  for (var k in obj)
    {

    if (typeof obj[k] === "object"){
      eachRecursive(obj[k], resultArr);
    }
    else{
      if (k === 'xmlUrl'){
        resultArr.push( obj['xmlUrl'] );
      }
    }
    }
}

/** a first effort at parsing rss.  probably not much need for it if feedParser works

var rssUrlHandler = function(urls){
  var futures = _.map(urls, function(url){
                      var future = new Future();
                      var onComplete = future.resolver();

                      if ( url.indexOf('http://') === -1 && url.indexOf('https://') === -1 ) {
                      console.log(url);
                      url = 'http://' + url;
                      }

                      Meteor.http.get(url, function (error, result) {
                                      if( error){
                                      console.log( error );
                                      }
                                      if ( result.statusCode === 200 ){
                                      var $ = cheerio.load (result.content);
                                      console.log( $('channel').find('title').text() );
                                      var meta = {};

                                      meta['title'] = $('channel').title;
                                      meta['date'] = $('channel').pubDate || $('channel').PubDate;
                                      meta['xmlUrl'] = $('channel').xmlUrl || url;

                                      var articles = $('item');
                                      var object = {};
                                      console.log(url + " : " + meta.title);
                                      object["meta"] = meta;
                                      object["articles"] = articles;

                                      onComplete( object );
                                      }

                          });
                      return future;
                      });
  Future.wait(futures);

  console.log('finished reading feeds');
  return _.invoke(futures,'get');
}
 **/

var handle = Feeds.find({}, {sort:{_id: 1}}).observe({
                                                     _suppress_initial: true,

                                                     added: function(doc){
                                                     if (doc.articles) {
                                                     console.log( "found " + newArticlesToDb(doc.articles, doc) + " for new feed - " + doc.title);
                                                     Feeds.update(doc._id, {$unset: {articles: 1}});
                                                     }
                                                     else{
                                                     result = syncFP(doc.url);
                                                     console.log( "found " + newArticlesToDb(result.articles, doc) + " for new feed - " + doc.title);
                                                     }

                                                     },

                                                     removed: function(doc){

                                                     Articles.find({source: doc.title}, {_id:1}).forEach( function (article){
                                                                                console.log("removing article " + article._id);
                                                                                Articles.remove(article._id);
                                                                                });

                                                     }

                                                     });

Meteor.methods({

               findArticles: function() {
               console.log("looking for new articles");
               var article_count = 0;
               /**
               Feeds.find({}).forEach( function(feed){
                                      if ( feed.url !== null && feed.url !== undefined && feed.url !== "null" ){

                                      var rssResult = syncFP( feed.url);
                                      if (rssResult && rssResult.articles && rssResult.meta){
                                      article_count += newArticlesToDb (rssResult.articles, rssResult.meta);
                                      }
                                      else{
                                      console.log( "feed returned no data : " + feed.url);
                                      }

                                      }
                                      else{
                                      console.log( "feed with no URL - removing : " + JSON.stringify (feed));
                                      Feeds.remove( feed._id );
                                      }
                                      });
               **/

               var urls = [];
               Feeds.find({}).forEach( function(feed){
                                      if ( feed.url !== null && feed.url !== undefined && feed.url !== "null" ){
                                      urls.push( feed.url);
                                      }
                                      else{
                                      console.log( "feed with no URL - removing : " + JSON.stringify (feed));
                                           Feeds.remove( feed._id );
                                      }
                                      });

               var rssResults = multipleSyncFP (urls);

               rssResults.forEach(function(rssResult){
                                  if (rssResult && rssResult.articles && rssResult.meta){
                                  article_count += newArticlesToDb (rssResult.articles, rssResult.meta);
                                  }
                                  else{
                                  console.log( "a feed returned no data");
                                  }
                                  });

               console.log("finished find articles");
               return article_count;
               },

               removeOldArticles: function(){
                 console.log("removeOldArticles method called on server");
                 var dateLimit = new Date(new Date() - (daysStoreArticles* DAY));

                 var error = Articles.remove({date:  {$lt: dateLimit} }, function(error){ return error;});

                 return error || 'success';
               },

               addSubscriberToFeeds: function(){
               var self = this;
               Feeds.find({}).forEach( function (feed){
                                      console.log("adding subscriber " + self.userId);
                                       Feeds.update( feed._id,{ $addToSet: { subscribers: self.userId }});
                                       });
               },

               addFeed_idToArticles: function(){
               Articles.find({}).forEach( function (article){
                                         var feed_id = Feeds.findOne({title: article.source})._id;
                                         Articles.update(article._id,{$set: {feed_id: feed_id}});
                                         });

               },

               cleanUrls: function(){
               Feeds.find({}).forEach( function(feed){
                                      var result = syncFP(feed.url);
                                      if (result.meta.url && feed.url !== result.meta.url ){
                                      console.log("changing url " + feed.url + " to " + result.meta.url);
                                      Feeds.update(feed._id, {$set: {url: result.meta.url }});
                                      }
                                      });
               },

               importOPML: function(upload){
               var self = this;
               var opml = XML2JS.parse(upload);
               var xmlToAdd = [];
               eachRecursive(opml, xmlToAdd);
               var fpResults = [];

               xmlToAdd.forEach( function(url){
                                try{
                                if (url !== null && url !== undefined){
                                fpResults.push( syncFP(url) );
                                }
                                }
                                catch(e){
                                console.log( e + " parsing url " + url);
                                }
                                });
               console.log( "finished with feedparser");
               if ( fpResults ){
               fpResults.forEach( function (rssResult){

                                 var doc = {url: rssResult.meta.url, title: rssResult.meta.title, last_date: rssResult.meta.date, subscribers: [] };
                                 doc.subscribers.push(self.userId);

                                 var existingFeed = Feeds.findOne( {url: doc.url} );
                                 if( existingFeed ){
                                 Feeds.update(existingFeed._id, {$addToSet: {subscribers: self.userId} } );
                                 console.log( rssResult.meta.title +" in db - subscribing user");
                                 }

                                else {
                                 console.log(doc.url + " not in db - adding");
                                 doc.articles = rssResult.articles;
                                 Feeds.insert(doc);
                                 }

                                });
               }
               },

               clientSyncFP : function(url){
               try{

               return syncFP(url);

               }
               catch(e){

               return e;
               }
               }

               });

<|endoftext|>


<commit_before>const { makeExecutableSchema } = require('graphql-tools')
const { getItem, getUser, getTopStories } = require('../hnclient')

const typeDefs = [`
  type User {
    about: String
    created: Int
    delay: Int,
    id: String!
    karma: Int!
    submitted: [Item]
  }

  enum ItemType {
    story
  }

  type Item {
    id: Int!
    by: User!
    kids: [Item]
    score: Int!
    time: Int
    title: String!
    type: ItemType
    url: String
  }

  type Query {
    item(id: Int!): Item
    stories: [Item]
    user(id: String!): User
  }

  schema {
    query: Query
  }
`]

const resolvers = {
  Query: {
    item (_, { id }) {
      return getItem(id)
    },

    async stories () {
      const stories = await getTopStories()
      return stories.map(getItem)
    },

    user (_, { id }) {
      return getUser(id)
    }
  },
  Item: {
    by: function({ by }) {
      return getUser(by)
    },
    kids: function ({ kids }) {
      return kids.map(getItem)
    }
  },
  User: {
    submitted ({ submitted }) {
      return submitted.map(getItem)
    }
  }
}

module.exports = makeExecutableSchema({ typeDefs, resolvers })
<commit_msg>Fix enum<commit_after>const { makeExecutableSchema } = require('graphql-tools')
const { getItem, getUser, getTopStories } = require('../hnclient')

const typeDefs = [`
  type User {
    about: String
    created: Int
    delay: Int,
    id: String!
    karma: Int!
    submitted: [Item]
  }

  enum ITEM_TYPE {
    JOB
    STORY
    COMMENT
    POLL
    POLLOPT
  }

  type Item {
    id: Int!
    by: User!
    kids: [Item]
    score: Int!
    time: Int
    title: String!
    type: ITEM_TYPE
    url: String
  }

  type Query {
    item(id: Int!): Item
    stories: [Item]
    user(id: String!): User
  }

  schema {
    query: Query
  }
`]

const resolvers = {
  Query: {
    item (_, { id }) {
      return getItem(id)
    },

    async stories () {
      const stories = await getTopStories()
      return stories.map(getItem)
    },

    user (_, { id }) {
      return getUser(id)
    }
  },
  Item: {
    by: function({ by }) {
      return getUser(by)
    },
    kids: function ({ kids }) {
      return kids.map(getItem)
    },
    type: function({ type }) {
      return type.toUpperCase()
    }
  },
  User: {
    submitted ({ submitted }) {
      return submitted.map(getItem)
    }
  }
}

module.exports = makeExecutableSchema({ typeDefs, resolvers })
<|endoftext|>


<commit_before>var url     = require('url');
var http    = require('http');
var https   = require('https');
var request = require('request');
var copy    = require('request/lib/copy');

/**
 * Return an application url.
 *
 * @param  {Object} app
 * @param  {String} path
 * @return {String}
 */
var serverAddress = function (app, path) {
  // Ensure the passed in path is in string format.
  if (typeof path === 'object') {
    path = url.format(path);
  }

  // If the application url is a string, all direct requests.
  if (typeof app === 'string') {
    return url.resolve(app, path);
  }

  // The application has not been mounted to a port yet, assign a random port.
  if (!app.address()) {
    app.listen(0);
  }

  var port     = app.address().port;
  var protocol = app instanceof https.Server ? 'https' : 'http';

  return url.resolve(protocol + '://localhost:' + port, path);
};

/**
 * Create a request instance for a particular application.
 *
 * @param  {Object}   app
 * @return {Function}
 */
var retest = function (app) {
  /**
   * Returns a function that maps to request expections.
   *
   * @param  {String}   uri
   * @param  {Object}   options
   * @param  {Function} done
   * @return {Object}
   */
  return function (uri, options, done) {
    if (typeof uri === 'undefined') {
      throw new Error('undefined is not a valid uri or options object');
    }

    if (typeof options === 'function' && !done) {
      done = options;
    }

    if (options && typeof options === 'object') {
      options.uri = uri;
    } else if (typeof uri === 'string') {
      options = { uri: uri };
    } else {
      options = uri;
    }

    options = copy(options);

    if (done) {
      options.callback = done;
    }

    // Correct the request uri.
    options.uri = serverAddress(app, options.uri);

    return new request.Request(options);
  };
};

/**
 * Generate an instance of the application for testing with request. Pass a
 * custom request instance as the second parameter.
 *
 * @param  {Object}   app
 * @param  {Object}   opts
 * @return {Function}
 */
exports = module.exports = function (app, opts) {
  if (typeof app === 'function') {
    app = http.createServer(app);
  }

  return request.defaults(opts || {}, retest(app));
};

/**
 * Create a retest agent for keeping cookies.
 *
 * @param  {Object}   app
 * @return {Function}
 */
exports.agent = function (app) {
  return exports(app, {
    jar: request.jar()
  });
};
<commit_msg>Pass options through agent.<commit_after>var url     = require('url');
var http    = require('http');
var https   = require('https');
var request = require('request');
var copy    = require('request/lib/copy');

/**
 * Return an application url.
 *
 * @param  {Object} app
 * @param  {String} path
 * @return {String}
 */
var serverAddress = function (app, path) {
  // Ensure the passed in path is in string format.
  if (typeof path === 'object') {
    path = url.format(path);
  }

  // If the application url is a string, all direct requests.
  if (typeof app === 'string') {
    return url.resolve(app, path);
  }

  // The application has not been mounted to a port yet, assign a random port.
  if (!app.address()) {
    app.listen(0);
  }

  var port     = app.address().port;
  var protocol = app instanceof https.Server ? 'https' : 'http';

  return url.resolve(protocol + '://localhost:' + port, path);
};

/**
 * Create a request instance for a particular application.
 *
 * @param  {Object}   app
 * @return {Function}
 */
var retest = function (app) {
  /**
   * Returns a function that maps to request expections.
   *
   * @param  {String}   uri
   * @param  {Object}   options
   * @param  {Function} done
   * @return {Object}
   */
  return function (uri, options, done) {
    if (typeof uri === 'undefined') {
      throw new Error('undefined is not a valid uri or options object');
    }

    if (typeof options === 'function' && !done) {
      done = options;
    }

    if (options && typeof options === 'object') {
      options.uri = uri;
    } else if (typeof uri === 'string') {
      options = { uri: uri };
    } else {
      options = uri;
    }

    options = copy(options);

    if (done) {
      options.callback = done;
    }

    // Correct the request uri.
    options.uri = serverAddress(app, options.uri);

    return new request.Request(options);
  };
};

/**
 * Generate an instance of the application for testing with request. Pass a
 * custom request instance as the second parameter.
 *
 * @param  {Object}   app
 * @param  {Object}   opts
 * @return {Function}
 */
exports = module.exports = function (app, opts) {
  if (typeof app === 'function') {
    app = http.createServer(app);
  }

  return request.defaults(opts || {}, retest(app));
};

/**
 * Create a retest agent for keeping cookies.
 *
 * @param  {Object}   app
 * @param  {Object}   opts
 * @return {Function}
 */
exports.agent = function (app, opts) {
  var options = opts ? copy(opts) : {};
  options.jar || (options.jar = request.jar());

  return exports(app, options);
};
<|endoftext|>


<commit_before>// map is the google.maps.Map on which this game will be drawn
function Game(map) {
  var map = map;
  var first_location_fixed = false;
  var player = false;
  var zombies = false;

  this.firstLocation = function(position) {
    var location = latLngFromPosition(position);

    player = new Player(map, location);

    var zombieLatLng = latLngTowardTarget(location, new google.maps.LatLng(100, 100), 50);
    zombies = new Array();
    zombies[0] = new Zombie(map, zombieLatLng);

    map.set_center(location);
    map.set_zoom(15);

    first_location_fixed = true;
  }

  this.locationChanged = function(position) {
    alert("Location changed.");
    if (!first_location_fixed) {
      return;
    }
    player.locationChanged(position);
    for (var i; i < zombies.length; ++i) {
      zombies[i].locationChanged(position);
    }
  }

  this.locationError = function(error) {
    // TODO: Count errors, if there are enough then show the user an issue.
    alert("location error: " + error.message);
  }

  this.initialize = function() {
    // Get our intial position, and initialize the map at that point.
    navigator.geolocation.getCurrentPosition(
        this.firstLocation,
        this.locationError,
        { enableHighAccuracy:true, maximumAge:0, timeout:0 });

    // Get updates of the user's location at least every 10 seconds.
    navigator.geolocation.watchPosition(
        this.locationChanged,
        this.locationError,
        { enableHighAccuracy:true, maximumAge: 10 * 1000, timeout:0 });
  }
}
<commit_msg>Oops, left in an alert.<commit_after>// map is the google.maps.Map on which this game will be drawn
function Game(map) {
  var map = map;
  var first_location_fixed = false;
  var player = false;
  var zombies = false;

  this.firstLocation = function(position) {
    var location = latLngFromPosition(position);

    player = new Player(map, location);

    var zombieLatLng = latLngTowardTarget(location, new google.maps.LatLng(100, 100), 50);
    zombies = new Array();
    zombies[0] = new Zombie(map, zombieLatLng);

    map.set_center(location);
    map.set_zoom(15);

    first_location_fixed = true;
  }

  this.locationChanged = function(position) {
    if (!first_location_fixed) {
      return;
    }
    player.locationChanged(position);
    for (var i; i < zombies.length; ++i) {
      zombies[i].locationChanged(position);
    }
  }

  this.locationError = function(error) {
    // TODO: Count errors, if there are enough then show the user an issue.
    alert("location error: " + error.message);
  }

  this.initialize = function() {
    // Get our intial position, and initialize the map at that point.
    navigator.geolocation.getCurrentPosition(
        this.firstLocation,
        this.locationError,
        { enableHighAccuracy:true, maximumAge:0, timeout:0 });

    // Get updates of the user's location at least every 10 seconds.
    navigator.geolocation.watchPosition(
        this.locationChanged,
        this.locationError,
        { enableHighAccuracy:true, maximumAge: 10 * 1000, timeout:0 });
  }
}
<|endoftext|>


<commit_before>// @flow

import { getEnv } from "./helpers/environment";
import path from "path";
import micromatch from "micromatch";
import buildDebug from "debug";

const debug = buildDebug("babel:config:config-chain");

import { findConfigs, loadConfig, type ConfigFile } from "./loading/files";

type ConfigItem = {
  type: "options" | "arguments",
  options: {},
  dirname: string,
  alias: string,
  loc: string,
};

export default function buildConfigChain(opts: {}): Array<ConfigItem> | null {
  if (typeof opts.filename !== "string" && opts.filename != null) {
    throw new Error(".filename must be a string, null, or undefined");
  }

  const filename = opts.filename ? path.resolve(opts.filename) : null;
  const builder = new ConfigChainBuilder(
    filename ? new LoadedFile(filename) : null,
  );

  try {
    builder.mergeConfigArguments(opts, process.cwd());

    // resolve all .babelrc files
    if (opts.babelrc !== false && filename) {
      findConfigs(path.dirname(filename)).forEach(configFile =>
        builder.mergeConfigFile(configFile),
      );
    }
  } catch (e) {
    if (e.code !== "BABEL_IGNORED_FILE") throw e;

    return null;
  }

  return builder.configs.reverse();
}

class ConfigChainBuilder {
  file: LoadedFile | null;
  configs: Array<ConfigItem> = [];

  constructor(file: LoadedFile | null) {
    this.file = file;
  }

  mergeConfigArguments(opts, dirname) {
    this.mergeConfig({
      type: "arguments",
      options: opts,
      alias: "base",
      dirname,
    });
  }

  mergeConfigFile(file: ConfigFile) {
    const { filepath, dirname, options } = file;

    this.mergeConfig({
      type: "options",
      options,
      alias: filepath,
      dirname,
    });
  }

  mergeConfig({ type, options: rawOpts, alias, dirname }) {
    if (rawOpts.ignore != null && !Array.isArray(rawOpts.ignore)) {
      throw new Error(
        `.ignore should be an array, ${JSON.stringify(rawOpts.ignore)} given`,
      );
    }
    if (rawOpts.only != null && !Array.isArray(rawOpts.only)) {
      throw new Error(
        `.only should be an array, ${JSON.stringify(rawOpts.only)} given`,
      );
    }

    // Bail out ASAP if this file is ignored so that we run as little logic as possible on ignored files.
    if (
      this.file &&
      this.file.shouldIgnore(rawOpts.ignore, rawOpts.only, dirname)
    ) {
      // TODO(logan): This is a really cross way to bail out. Avoid this in rewrite.
      throw Object.assign((new Error("This file has been ignored."): any), {
        code: "BABEL_IGNORED_FILE",
      });
    }

    const options = Object.assign({}, rawOpts);
    delete options.env;
    delete options.extends;

    const envKey = getEnv();

    if (
      rawOpts.env != null &&
      (typeof rawOpts.env !== "object" || Array.isArray(rawOpts.env))
    ) {
      throw new Error(".env block must be an object, null, or undefined");
    }

    const envOpts = rawOpts.env && rawOpts.env[envKey];

    if (
      envOpts != null &&
      (typeof envOpts !== "object" || Array.isArray(envOpts))
    ) {
      throw new Error(".env[...] block must be an object, null, or undefined");
    }

    if (envOpts) {
      this.mergeConfig({
        type,
        options: envOpts,
        alias: `${alias}.env.${envKey}`,
        dirname: dirname,
      });
    }

    this.configs.push({
      type,
      options,
      alias,
      loc: alias,
      dirname,
    });

    if (rawOpts.extends) {
      if (typeof rawOpts.extends !== "string") {
        throw new Error(".extends must be a string");
      }

      const extendsConfig = loadConfig(rawOpts.extends, dirname);

      const existingConfig = this.configs.some(config => {
        return config.alias === extendsConfig.filepath;
      });
      if (!existingConfig) {
        this.mergeConfig({
          type: "options",
          alias: extendsConfig.filepath,
          options: extendsConfig.options,
          dirname: extendsConfig.dirname,
        });
      }
    }
  }
}

/**
 * Track a given file and expose function to check if it should be ignored.
 */
class LoadedFile {
  filename: string;
  possibleDirs: null | Array<string> = null;

  constructor(filename) {
    this.filename = filename;
  }

  /**
   * Tests if a filename should be ignored based on "ignore" and "only" options.
   */
  shouldIgnore(
    ignore: ?Array<mixed>,
    only: ?Array<mixed>,
    dirname: string,
  ): boolean {
    if (ignore) {
      if (this._matchesPatterns(ignore, dirname)) {
        debug(
          "Ignored %o because it matched one of %O from %o",
          this.filename,
          ignore,
          dirname,
        );
        return true;
      }
    }

    if (only) {
      if (!this._matchesPatterns(only, dirname)) {
        debug(
          "Ignored %o because it failed to match one of %O from %o",
          this.filename,
          only,
          dirname,
        );
        return true;
      }
    }

    return false;
  }

  /**
   * Returns result of calling function with filename if pattern is a function.
   * Otherwise returns result of matching pattern Regex with filename.
   */
  _matchesPatterns(patterns: Array<mixed>, dirname: string): boolean {
    const res = [];
    const strings = [];
    const fns = [];

    patterns.forEach(pattern => {
      if (typeof pattern === "string") strings.push(pattern);
      else if (typeof pattern === "function") fns.push(pattern);
      else if (pattern instanceof RegExp) res.push(pattern);
      else {
        throw new Error(
          "Patterns must be a string, function, or regular expression",
        );
      }
    });

    const filename = this.filename;
    if (res.some(re => re.test(filename))) return true;
    if (fns.some(fn => fn(filename))) return true;

    if (strings.length > 0) {
      let possibleDirs = this.possibleDirs;
      // Lazy-init so we don't initialize this for files that have no glob patterns.
      if (!possibleDirs) {
        possibleDirs = this.possibleDirs = [];

        possibleDirs.push(filename);

        let current = filename;
        while (true) {
          const previous = current;
          current = path.dirname(current);
          if (previous === current) break;

          possibleDirs.push(current);
        }
      }

      const absolutePatterns = strings.map(pattern => {
        // Preserve the "!" prefix so that micromatch can use it for negation.
        const negate = pattern[0] === "!";
        if (negate) pattern = pattern.slice(1);

        return (negate ? "!" : "") + path.resolve(dirname, pattern);
      });

      if (
        micromatch(possibleDirs, absolutePatterns, { nocase: true }).length > 0
      ) {
        return true;
      }
    }

    return false;
  }
}
<commit_msg>Reuse config file merge.<commit_after>// @flow

import { getEnv } from "./helpers/environment";
import path from "path";
import micromatch from "micromatch";
import buildDebug from "debug";

const debug = buildDebug("babel:config:config-chain");

import { findConfigs, loadConfig, type ConfigFile } from "./loading/files";

type ConfigItem = {
  type: "options" | "arguments",
  options: {},
  dirname: string,
  alias: string,
  loc: string,
};

export default function buildConfigChain(opts: {}): Array<ConfigItem> | null {
  if (typeof opts.filename !== "string" && opts.filename != null) {
    throw new Error(".filename must be a string, null, or undefined");
  }

  const filename = opts.filename ? path.resolve(opts.filename) : null;
  const builder = new ConfigChainBuilder(
    filename ? new LoadedFile(filename) : null,
  );

  try {
    builder.mergeConfigArguments(opts, process.cwd());

    // resolve all .babelrc files
    if (opts.babelrc !== false && filename) {
      findConfigs(path.dirname(filename)).forEach(configFile =>
        builder.mergeConfigFile(configFile),
      );
    }
  } catch (e) {
    if (e.code !== "BABEL_IGNORED_FILE") throw e;

    return null;
  }

  return builder.configs.reverse();
}

class ConfigChainBuilder {
  file: LoadedFile | null;
  configs: Array<ConfigItem> = [];

  constructor(file: LoadedFile | null) {
    this.file = file;
  }

  mergeConfigArguments(opts, dirname) {
    this.mergeConfig({
      type: "arguments",
      options: opts,
      alias: "base",
      dirname,
    });
  }

  mergeConfigFile(file: ConfigFile) {
    const { filepath, dirname, options } = file;

    this.mergeConfig({
      type: "options",
      options,
      alias: filepath,
      dirname,
    });
  }

  mergeConfig({ type, options: rawOpts, alias, dirname }) {
    if (rawOpts.ignore != null && !Array.isArray(rawOpts.ignore)) {
      throw new Error(
        `.ignore should be an array, ${JSON.stringify(rawOpts.ignore)} given`,
      );
    }
    if (rawOpts.only != null && !Array.isArray(rawOpts.only)) {
      throw new Error(
        `.only should be an array, ${JSON.stringify(rawOpts.only)} given`,
      );
    }

    // Bail out ASAP if this file is ignored so that we run as little logic as possible on ignored files.
    if (
      this.file &&
      this.file.shouldIgnore(rawOpts.ignore, rawOpts.only, dirname)
    ) {
      // TODO(logan): This is a really cross way to bail out. Avoid this in rewrite.
      throw Object.assign((new Error("This file has been ignored."): any), {
        code: "BABEL_IGNORED_FILE",
      });
    }

    const options = Object.assign({}, rawOpts);
    delete options.env;
    delete options.extends;

    const envKey = getEnv();

    if (
      rawOpts.env != null &&
      (typeof rawOpts.env !== "object" || Array.isArray(rawOpts.env))
    ) {
      throw new Error(".env block must be an object, null, or undefined");
    }

    const envOpts = rawOpts.env && rawOpts.env[envKey];

    if (
      envOpts != null &&
      (typeof envOpts !== "object" || Array.isArray(envOpts))
    ) {
      throw new Error(".env[...] block must be an object, null, or undefined");
    }

    if (envOpts) {
      this.mergeConfig({
        type,
        options: envOpts,
        alias: `${alias}.env.${envKey}`,
        dirname: dirname,
      });
    }

    this.configs.push({
      type,
      options,
      alias,
      loc: alias,
      dirname,
    });

    if (rawOpts.extends) {
      if (typeof rawOpts.extends !== "string") {
        throw new Error(".extends must be a string");
      }

      const extendsConfig = loadConfig(rawOpts.extends, dirname);

      const existingConfig = this.configs.some(config => {
        return config.alias === extendsConfig.filepath;
      });
      if (!existingConfig) {
        this.mergeConfigFile(extendsConfig);
      }
    }
  }
}

/**
 * Track a given file and expose function to check if it should be ignored.
 */
class LoadedFile {
  filename: string;
  possibleDirs: null | Array<string> = null;

  constructor(filename) {
    this.filename = filename;
  }

  /**
   * Tests if a filename should be ignored based on "ignore" and "only" options.
   */
  shouldIgnore(
    ignore: ?Array<mixed>,
    only: ?Array<mixed>,
    dirname: string,
  ): boolean {
    if (ignore) {
      if (this._matchesPatterns(ignore, dirname)) {
        debug(
          "Ignored %o because it matched one of %O from %o",
          this.filename,
          ignore,
          dirname,
        );
        return true;
      }
    }

    if (only) {
      if (!this._matchesPatterns(only, dirname)) {
        debug(
          "Ignored %o because it failed to match one of %O from %o",
          this.filename,
          only,
          dirname,
        );
        return true;
      }
    }

    return false;
  }

  /**
   * Returns result of calling function with filename if pattern is a function.
   * Otherwise returns result of matching pattern Regex with filename.
   */
  _matchesPatterns(patterns: Array<mixed>, dirname: string): boolean {
    const res = [];
    const strings = [];
    const fns = [];

    patterns.forEach(pattern => {
      if (typeof pattern === "string") strings.push(pattern);
      else if (typeof pattern === "function") fns.push(pattern);
      else if (pattern instanceof RegExp) res.push(pattern);
      else {
        throw new Error(
          "Patterns must be a string, function, or regular expression",
        );
      }
    });

    const filename = this.filename;
    if (res.some(re => re.test(filename))) return true;
    if (fns.some(fn => fn(filename))) return true;

    if (strings.length > 0) {
      let possibleDirs = this.possibleDirs;
      // Lazy-init so we don't initialize this for files that have no glob patterns.
      if (!possibleDirs) {
        possibleDirs = this.possibleDirs = [];

        possibleDirs.push(filename);

        let current = filename;
        while (true) {
          const previous = current;
          current = path.dirname(current);
          if (previous === current) break;

          possibleDirs.push(current);
        }
      }

      const absolutePatterns = strings.map(pattern => {
        // Preserve the "!" prefix so that micromatch can use it for negation.
        const negate = pattern[0] === "!";
        if (negate) pattern = pattern.slice(1);

        return (negate ? "!" : "") + path.resolve(dirname, pattern);
      });

      if (
        micromatch(possibleDirs, absolutePatterns, { nocase: true }).length > 0
      ) {
        return true;
      }
    }

    return false;
  }
}
<|endoftext|>


<commit_before>'use strict';

function draw_body(body){
    // Calculate offset.
    var offset_x = 0;
    var offset_y = 0;
    if(body['parent'] !== void 0){
        offset_x += bodies[body['parent']]['x'];
        offset_y += bodies[body['parent']]['y'];
    }

    // Bodies orbit around their parent.
    body['rotation'] += body['speed'];
    if(body['rotation'] > 360){
        body['rotation'] -= 360;
    }else if(body['rotation'] < 0){
        body['rotation'] += 360;
    }
    body['x'] = body['orbit'] * Math.cos(body['rotation']) + offset_x;
    body['y'] = body['orbit'] * Math.sin(body['rotation']) + offset_y;

    // Draw body.
    buffer.fillStyle = body['color'];
    buffer.beginPath();
    buffer.arc(
      body['x'],
      body['y'],
      body['radius'],
      0,
      tau,
      1
    );
    buffer.closePath();
    buffer.fill();

    // Draw orbit path and line to parent, if player allows it.
    if(settings['line-orbit']
      || settings['line-parent']){
        buffer.strokeStyle = body['color'];
        buffer.lineWidth = Math.ceil(body['radius'] / 10) / zoom;

        buffer.beginPath();
        if(settings['line-orbit']){
            buffer.arc(
              offset_x,
              offset_y,
              body['orbit'],
              0,
              tau,
              1
            );
        }
        if(settings['line-parent']){
            buffer.moveTo(
              body['x'],
              body['y']
            );
            buffer.lineTo(
              offset_x,
              offset_y
            );
        }
        buffer.closePath();
        buffer.stroke();
    }

    // If no moons, we're done here.
    if(body['moons'] == void 0){
        return;
    }

    // Draw moons.
    var moonloop_counter = body['moons'].length - 1;
    do{
        draw_body(body['moons'][moonloop_counter]);
    }while(moonloop_counter--);
}

function draw(){
    buffer.clearRect(
      0,
      0,
      width,
      height
    );

    // Save the current buffer state.
    buffer.save();

    // Setup camera offset.
    buffer.translate(
      x,
      y
    );
    buffer.scale(
      zoom,
      zoom
    );
    buffer.translate(
      camera_x,
      camera_y
    );

    // Draw bodies.
    var loop_counter = bodies.length - 1;
    if(loop_counter >= 0){
        do{
            draw_body(bodies[loop_counter]);
        }while(loop_counter--);
    }

    // Draw the star.
    buffer.fillStyle = settings['solar-color'];
    buffer.beginPath();
    buffer.arc(
      0,
      0,
      settings['solar-radius'],
      0,
      tau,
      1
    );
    buffer.closePath();
    buffer.fill();

    // Restore the buffer state.
    buffer.restore();

    // Draw zoom.
    buffer.fillStyle = '#fff';
    buffer.fillText(
      zoom,
      0,
      25
    );

    canvas.clearRect(
      0,
      0,
      width,
      height
    );
    canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );

    window.requestAnimationFrame(draw);
}

function generate_solarsystem(){
    bodies.length = 0;

    var bodyloop_counter = random_number(5) + 1;
    var moonloop_counter = 0;
    var radius = 0;
    do{
        radius = random_number(10) + 3;

        // Create body.
        bodies.push({
          'color': '#'
            + (random_number(5) + 4)
            + (random_number(5) + 4)
            + (random_number(5) + 4),
          'orbit': random_number(2323) + 232,
          'radius': radius,
          'rotation': random_number(360),
          'speed': Math.random() / 100,
          'x': 0,
          'y': 0,
        });

        // Should this new body have moons?
        if(Math.random() < .5){
            continue;
        }

        bodies[bodies.length - 1]['moons'] = [];

        moonloop_counter = random_number(2) + 1;
        do{
            radius = random_number(5) + 2;

            // Create moon for this new body.
            bodies[bodies.length - 1]['moons'].push({
              'color': '#'
                + (random_number(5) + 4)
                + (random_number(5) + 4)
                + (random_number(5) + 4),
              'orbit': random_number(100) + 15,
              'parent': bodyloop_counter,
              'radius': radius,
              'rotation': random_number(360),
              'speed': (Math.random() - .5) / 5,
              'x': 0,
              'y': 0,
            });
        }while(moonloop_counter--);
    }while(bodyloop_counter--);

    settings['solar-color'] = '#'
      + (random_number(4) + 5)
      + (random_number(4) + 5)
      + (random_number(4) + 5);
    settings['solar-radius'] = random_number(99) + 5;
}

function logic(){
    // Update camera position.
    if(key_down){
        camera_y -= settings['camera-speed'] / zoom;
    }
    if(key_left){
        camera_x += settings['camera-speed'] / zoom;
    }
    if(key_right){
        camera_x -= settings['camera-speed'] / zoom;
    }
    if(key_up){
        camera_y += settings['camera-speed'] / zoom;
    }
}

function mouse_wheel(e){
    zoom += (e.wheelDelta || -e.detail) > 0
      ? .05
      : -.05;

    if(zoom < .1){
        zoom = .1;

    }else if(zoom > 3){
        zoom = 3;
    }

    zoom = parseFloat(zoom.toFixed(2));
}

function random_number(i){
    return Math.floor(Math.random() * i);
}

function resize(){
    height = window.innerHeight;
    document.getElementById('buffer').height = height;
    document.getElementById('canvas').height = height;
    y = height / 2;

    width = window.innerWidth;
    document.getElementById('buffer').width = width;
    document.getElementById('canvas').width = width;
    x = width / 2;

    buffer.font = '23pt sans-serif';
}

var bodies = [];
var buffer = document.getElementById('buffer').getContext('2d', {
  'alpha': false,
});
var camera_x = 0;
var camera_y = 0;
var canvas = document.getElementById('canvas').getContext('2d', {
  'alpha': false,
});
var drag = false;
var drag_x = 0;
var drag_y = 0;
var height = 0;
var key_down = false;
var key_left = false;
var key_right = false;
var key_up = false;
var settings = {
  'camera-speed': 10,
  'line-keys': 'LO',
  'line-orbit': true,
  'line-parent': true,
  'movement-keys': 'WASD',
  'restart-key': 'H',
  'solar-color': '#fff',
  'solar-radius': 1,
};
var tau = Math.PI * 2;
var width = 0;
var x = 0;
var y = 0;
var zoom = 1;

window.onkeydown = function(e){
    var key = String.fromCharCode(e.keyCode || e.which);

    if(key === settings['movement-keys'][1]){
        key_left = true;

    }else if(key === settings['movement-keys'][3]){
        key_right = true;

    }else if(key === settings['movement-keys'][2]){
        key_down = true;

    }else if(key === settings['movement-keys'][0]){
        key_up = true;

    }else if(key === settings['line-keys'][0]){
        settings['line-parent'] = !settings['line-parent'];

    }else if(key === settings['line-keys'][1]){
        settings['line-orbit'] = !settings['line-orbit'];

    }else if(key === settings['restart-key']){
        generate_solarsystem();
    }
};

window.onkeyup = function(e){
    var key = String.fromCharCode(e.keyCode || e.which);

    if(key === settings['movement-keys'][1]){
        key_left = false;

    }else if(key === settings['movement-keys'][3]){
        key_right = false;

    }else if(key === settings['movement-keys'][2]){
        key_down = false;

    }else if(key === settings['movement-keys'][0]){
        key_up = false;
    }
};

window.onload = function(){
    resize();
    generate_solarsystem();

    if('onmousewheel' in window){
        window.onmousewheel = mouse_wheel;

    }else{
        document.addEventListener(
          'DOMMouseScroll',
          mouse_wheel,
          false
        );
    }

    window.requestAnimationFrame(draw);
    window.setInterval(
      'logic()',
      35
    );
};

window.onmousedown =
  window.ontouchstart = function(e){
    drag = true;
    drag_x = e.pageX;
    drag_y = e.pageY;
};

window.onmousemove =
  window.ontouchmove = function(e){
    if(!drag){
        return;
    }

    camera_x -= (drag_x - e.pageX) / zoom;
    camera_y -= (drag_y - e.pageY) / zoom;
    drag_x = e.pageX;
    drag_y = e.pageY;
};

window.onmouseup =
  window.ontouchend = function(e){
    drag = false;
};

window.onresize = resize;
<commit_msg>fixed window.setInterval() usage<commit_after>'use strict';

function draw_body(body){
    // Calculate offset.
    var offset_x = 0;
    var offset_y = 0;
    if(body['parent'] !== void 0){
        offset_x += bodies[body['parent']]['x'];
        offset_y += bodies[body['parent']]['y'];
    }

    // Bodies orbit around their parent.
    body['rotation'] += body['speed'];
    if(body['rotation'] > 360){
        body['rotation'] -= 360;
    }else if(body['rotation'] < 0){
        body['rotation'] += 360;
    }
    body['x'] = body['orbit'] * Math.cos(body['rotation']) + offset_x;
    body['y'] = body['orbit'] * Math.sin(body['rotation']) + offset_y;

    // Draw body.
    buffer.fillStyle = body['color'];
    buffer.beginPath();
    buffer.arc(
      body['x'],
      body['y'],
      body['radius'],
      0,
      tau,
      1
    );
    buffer.closePath();
    buffer.fill();

    // Draw orbit path and line to parent, if player allows it.
    if(settings['line-orbit']
      || settings['line-parent']){
        buffer.strokeStyle = body['color'];
        buffer.lineWidth = Math.ceil(body['radius'] / 10) / zoom;

        buffer.beginPath();
        if(settings['line-orbit']){
            buffer.arc(
              offset_x,
              offset_y,
              body['orbit'],
              0,
              tau,
              1
            );
        }
        if(settings['line-parent']){
            buffer.moveTo(
              body['x'],
              body['y']
            );
            buffer.lineTo(
              offset_x,
              offset_y
            );
        }
        buffer.closePath();
        buffer.stroke();
    }

    // If no moons, we're done here.
    if(body['moons'] == void 0){
        return;
    }

    // Draw moons.
    var moonloop_counter = body['moons'].length - 1;
    do{
        draw_body(body['moons'][moonloop_counter]);
    }while(moonloop_counter--);
}

function draw(){
    buffer.clearRect(
      0,
      0,
      width,
      height
    );

    // Save the current buffer state.
    buffer.save();

    // Setup camera offset.
    buffer.translate(
      x,
      y
    );
    buffer.scale(
      zoom,
      zoom
    );
    buffer.translate(
      camera_x,
      camera_y
    );

    // Draw bodies.
    var loop_counter = bodies.length - 1;
    if(loop_counter >= 0){
        do{
            draw_body(bodies[loop_counter]);
        }while(loop_counter--);
    }

    // Draw the star.
    buffer.fillStyle = settings['solar-color'];
    buffer.beginPath();
    buffer.arc(
      0,
      0,
      settings['solar-radius'],
      0,
      tau,
      1
    );
    buffer.closePath();
    buffer.fill();

    // Restore the buffer state.
    buffer.restore();

    // Draw zoom.
    buffer.fillStyle = '#fff';
    buffer.fillText(
      zoom,
      0,
      25
    );

    canvas.clearRect(
      0,
      0,
      width,
      height
    );
    canvas.drawImage(
      document.getElementById('buffer'),
      0,
      0
    );

    window.requestAnimationFrame(draw);
}

function generate_solarsystem(){
    bodies.length = 0;

    var bodyloop_counter = random_number(5) + 1;
    var moonloop_counter = 0;
    var radius = 0;
    do{
        radius = random_number(10) + 3;

        // Create body.
        bodies.push({
          'color': '#'
            + (random_number(5) + 4)
            + (random_number(5) + 4)
            + (random_number(5) + 4),
          'orbit': random_number(2323) + 232,
          'radius': radius,
          'rotation': random_number(360),
          'speed': Math.random() / 100,
          'x': 0,
          'y': 0,
        });

        // Should this new body have moons?
        if(Math.random() < .5){
            continue;
        }

        bodies[bodies.length - 1]['moons'] = [];

        moonloop_counter = random_number(2) + 1;
        do{
            radius = random_number(5) + 2;

            // Create moon for this new body.
            bodies[bodies.length - 1]['moons'].push({
              'color': '#'
                + (random_number(5) + 4)
                + (random_number(5) + 4)
                + (random_number(5) + 4),
              'orbit': random_number(100) + 15,
              'parent': bodyloop_counter,
              'radius': radius,
              'rotation': random_number(360),
              'speed': (Math.random() - .5) / 5,
              'x': 0,
              'y': 0,
            });
        }while(moonloop_counter--);
    }while(bodyloop_counter--);

    settings['solar-color'] = '#'
      + (random_number(4) + 5)
      + (random_number(4) + 5)
      + (random_number(4) + 5);
    settings['solar-radius'] = random_number(99) + 5;
}

function logic(){
    // Update camera position.
    if(key_down){
        camera_y -= settings['camera-speed'] / zoom;
    }
    if(key_left){
        camera_x += settings['camera-speed'] / zoom;
    }
    if(key_right){
        camera_x -= settings['camera-speed'] / zoom;
    }
    if(key_up){
        camera_y += settings['camera-speed'] / zoom;
    }
}

function mouse_wheel(e){
    zoom += (e.wheelDelta || -e.detail) > 0
      ? .05
      : -.05;

    if(zoom < .1){
        zoom = .1;

    }else if(zoom > 3){
        zoom = 3;
    }

    zoom = parseFloat(zoom.toFixed(2));
}

function random_number(i){
    return Math.floor(Math.random() * i);
}

function resize(){
    height = window.innerHeight;
    document.getElementById('buffer').height = height;
    document.getElementById('canvas').height = height;
    y = height / 2;

    width = window.innerWidth;
    document.getElementById('buffer').width = width;
    document.getElementById('canvas').width = width;
    x = width / 2;

    buffer.font = '23pt sans-serif';
}

var bodies = [];
var buffer = document.getElementById('buffer').getContext('2d', {
  'alpha': false,
});
var camera_x = 0;
var camera_y = 0;
var canvas = document.getElementById('canvas').getContext('2d', {
  'alpha': false,
});
var drag = false;
var drag_x = 0;
var drag_y = 0;
var height = 0;
var key_down = false;
var key_left = false;
var key_right = false;
var key_up = false;
var settings = {
  'camera-speed': 10,
  'line-keys': 'LO',
  'line-orbit': true,
  'line-parent': true,
  'movement-keys': 'WASD',
  'restart-key': 'H',
  'solar-color': '#fff',
  'solar-radius': 1,
};
var tau = Math.PI * 2;
var width = 0;
var x = 0;
var y = 0;
var zoom = 1;

window.onkeydown = function(e){
    var key = String.fromCharCode(e.keyCode || e.which);

    if(key === settings['movement-keys'][1]){
        key_left = true;

    }else if(key === settings['movement-keys'][3]){
        key_right = true;

    }else if(key === settings['movement-keys'][2]){
        key_down = true;

    }else if(key === settings['movement-keys'][0]){
        key_up = true;

    }else if(key === settings['line-keys'][0]){
        settings['line-parent'] = !settings['line-parent'];

    }else if(key === settings['line-keys'][1]){
        settings['line-orbit'] = !settings['line-orbit'];

    }else if(key === settings['restart-key']){
        generate_solarsystem();
    }
};

window.onkeyup = function(e){
    var key = String.fromCharCode(e.keyCode || e.which);

    if(key === settings['movement-keys'][1]){
        key_left = false;

    }else if(key === settings['movement-keys'][3]){
        key_right = false;

    }else if(key === settings['movement-keys'][2]){
        key_down = false;

    }else if(key === settings['movement-keys'][0]){
        key_up = false;
    }
};

window.onload = function(){
    resize();
    generate_solarsystem();

    if('onmousewheel' in window){
        window.onmousewheel = mouse_wheel;

    }else{
        document.addEventListener(
          'DOMMouseScroll',
          mouse_wheel,
          false
        );
    }

    window.requestAnimationFrame(draw);
    window.setInterval(
      logic,
      35
    );
};

window.onmousedown =
  window.ontouchstart = function(e){
    drag = true;
    drag_x = e.pageX;
    drag_y = e.pageY;
};

window.onmousemove =
  window.ontouchmove = function(e){
    if(!drag){
        return;
    }

    camera_x -= (drag_x - e.pageX) / zoom;
    camera_y -= (drag_y - e.pageY) / zoom;
    drag_x = e.pageX;
    drag_y = e.pageY;
};

window.onmouseup =
  window.ontouchend = function(e){
    drag = false;
};

window.onresize = resize;
<|endoftext|>


<commit_before>$(document).ready(function() {

  var s = new sigma('graph-container');
  var tagTemplateString = "<h3> {{noteTitle}} </h3> <ul> {{#each tags}} <li> {{title}}, {{weight}} </li> {{/each}} </ul>"
  var tagTemplate = Handlebars.compile(tagTemplateString);

  s.settings({
    defaultLabelColor: '#000',
    defaultLabelSize: 10,
    drawEdges : true,
    batchEdgesDrawing : true,
    defaultLabelBGColor: '#fff',
    defaultLabelHoverColor: '#000',
    defaultEdgeColor:'#ddd',
    defaultNodeColor:'#00CCFF',
    labelThreshold: 7,
    defaultEdgeType: 'curve',
    minNodeSize: 1,
    maxNodeSize: 3,
    minEdgeSize: 0,
    maxEdgeSize: .1
  });

  s.bind('clickNode', function(e) {
    var tags = JSON.parse(e.data.node.tags)
    if (tags.length > 8) {
      tags = tags.slice(0,8);
    }
    tags.forEach(function(tag) {
      tag.weight = Math.round(tag.weight*100);
    });
    tagNames = tags.map(function(tag) { return tag.title});
    window.drawGraphForTags(tagNames);
    $('#tagList').html(tagTemplate({noteTitle : e.data.node.label, tags : tags}));
  });

  sigma.parsers.gexf('./network.gexf', s, function (s) {
    $('#loading').remove();
    s.refresh();
  });

});<commit_msg>update tag chart on hover node<commit_after>$(document).ready(function() {

  var s = new sigma('graph-container');
  var tagTemplateString = "<h3> {{noteTitle}} </h3> <ul> {{#each tags}} <li> {{title}}, {{weight}} </li> {{/each}} </ul>"
  var tagTemplate = Handlebars.compile(tagTemplateString);

  s.settings({
    defaultLabelColor: '#000',
    defaultLabelSize: 10,
    drawEdges : true,
    batchEdgesDrawing : true,
    defaultLabelBGColor: '#fff',
    defaultLabelHoverColor: '#000',
    defaultEdgeColor:'#ddd',
    defaultNodeColor:'#00CCFF',
    labelThreshold: 7,
    defaultEdgeType: 'curve',
    minNodeSize: 1,
    maxNodeSize: 3,
    minEdgeSize: 0,
    maxEdgeSize: .1
  });

  s.bind('clickNode overNode', function(e) {
    var tags = JSON.parse(e.data.node.tags)
    if (tags.length > 8) {
      tags = tags.slice(0,8);
    }
    tags.forEach(function(tag) {
      tag.weight = Math.round(tag.weight*100);
    });
    tagNames = tags.map(function(tag) { return tag.title});
    window.drawGraphForTags(tagNames);
    $('#tagList').html(tagTemplate({noteTitle : e.data.node.label, tags : tags}));
  });

  sigma.parsers.gexf('./network.gexf', s, function (s) {
    $('#loading').remove();
    s.refresh();
  });

});<|endoftext|>


<commit_before>// Localisation
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
import locales from './locales'

const i18n = new VueI18n({
  locale: 'fr',
  fallbackLocale: 'en',
  messages: locales
})

export default i18n
<commit_msg>Set default language to English<commit_after>// Localisation
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
import locales from './locales'

const i18n = new VueI18n({
  locale: 'en',
  fallbackLocale: 'en',
  messages: locales
})

export default i18n
<|endoftext|>


<commit_before>import {Timer} from 'animationClasses/commons/utils';
import RotateElement from '../single/RotateElement';

/**
 * Парная анимация для продвижения с вращением
 * @param {Object} animation   Объект анимации
 * @param {String} pathStrings Строковое описание траекторий в формате [позиция: траектория, ...]
 * @param {Number} rotateAngle Угол поворота
 */
export default class RotatePairElement extends PairElement {
	constructor(animation, pathStrings, rotateAngle) {
		super(animation, pathStrings, rotateAngle);

		this.manDanceAnimationElement = new RotateElement(animation, pathStrings, 'man', undefined, rotateAngle);
		this.womanDanceAnimationElement = new RotateElement(animation, pathStrings, 'woman', undefined, rotateAngle);
	}

	startAnimation(lengthS, beats, startAngleMan, startAngleWoman, direction, delay, startPart, stopPart) {
		this.manDanceAnimationElement.startAnimation(lengthS, beats, startAngleMan, direction, delay, startPart, stopPart);
		this.womanDanceAnimationElement.startAnimation(lengthS, beats, startAngleWoman, direction, delay, startPart, stopPart);
	}

	fullAnimation(lengthS, beats, startAngleMan, startAngleWoman, manPosition, direction, delay, startPart, stopPart) {

		const fullAnimationFunc = () => {
			this.animation.clearPaths();
			this.drawPath(manPosition);
			this.startAnimation(lengthS, beats, startAngleMan, startAngleWoman, direction, 0, startPart, stopPart);
		};

		if ((!delay) || (delay <= 0)) {
			fullAnimationFunc();
		} else {
			this.animation.timeouts.push(new Timer(fullAnimationFunc, delay * 1000));
		}
	}
}
<commit_msg>Fixed import<commit_after>import {Timer} from 'animationClasses/commons/utils';
import PairElement from './PairElement';

/**
 * Парная анимация для продвижения с вращением
 * @param {Object} animation   Объект анимации
 * @param {String} pathStrings Строковое описание траекторий в формате [позиция: траектория, ...]
 * @param {Number} rotateAngle Угол поворота
 */
export default class RotatePairElement extends PairElement {
	constructor(animation, pathStrings, rotateAngle) {
		super(animation, pathStrings, rotateAngle);

		this.manDanceAnimationElement = new RotateElement(animation, pathStrings, 'man', undefined, rotateAngle);
		this.womanDanceAnimationElement = new RotateElement(animation, pathStrings, 'woman', undefined, rotateAngle);
	}

	startAnimation(lengthS, beats, startAngleMan, startAngleWoman, direction, delay, startPart, stopPart) {
		this.manDanceAnimationElement.startAnimation(lengthS, beats, startAngleMan, direction, delay, startPart, stopPart);
		this.womanDanceAnimationElement.startAnimation(lengthS, beats, startAngleWoman, direction, delay, startPart, stopPart);
	}

	fullAnimation(lengthS, beats, startAngleMan, startAngleWoman, manPosition, direction, delay, startPart, stopPart) {

		const fullAnimationFunc = () => {
			this.animation.clearPaths();
			this.drawPath(manPosition);
			this.startAnimation(lengthS, beats, startAngleMan, startAngleWoman, direction, 0, startPart, stopPart);
		};

		if ((!delay) || (delay <= 0)) {
			fullAnimationFunc();
		} else {
			this.animation.timeouts.push(new Timer(fullAnimationFunc, delay * 1000));
		}
	}
}
<|endoftext|>


<commit_before>function DemoEngine(selector, width, height) {

	// hack for safari
	window.AudioContext = window.AudioContext || window.webkitAudioContext;

	this.partdata = [];
	this.assets = { urls: {} };
	this.renderers = {};
	this.rendertargets = {};
	this.audio = null;
	this.analyzer = null;
	this.audiocontext = null;
	this.audiosource = null;
	this.frequencyByteData = null;
	this.frequencyFloatData = null;
	this.frequencyBinCount = 0;
	this.selectorstr = selector;
	this.fftsupport = true;

	var tmpelement = $(selector);
	if (tmpelement.length != 1) {
		console.log('Selector "' + selector + '" returned more than one element. ');
		return null;
	}
	this.element = tmpelement[0];

	if (navigator.userAgent.toLowerCase().indexOf('firefox') != -1 ||
		!!navigator.userAgent.match(/Trident.*[ :]*11\./)) {
		this.fftsupport = false;
	}

	this.width = window.innerWidth;
	this.height = window.innerHeight;

	if (width && height) {
		this.width = width;
		this.height = height;
	}

	this.setAudioLooping = function(loop) {
		this.audio.loop = loop;
	}

	this.supportsFFT = function() {
		return this.fftsupport;
	}

	this.setAudio = function(a) {
		this.audiocontext = new AudioContext();
		this.audio = a;
		$(this.selectorstr).append(this.audio);

		if (this.fftsupport) {
			this.audiosource = this.audiocontext.createMediaElementSource(this.audio);
			this.analyzer = this.audiocontext.createAnalyser();
			this.analyzer.fftSize = Math.pow(2,9);
			this.audiosource.connect(this.analyzer);
			this.analyzer.connect(this.audiocontext.destination);
			this.frequencyBinCount = this.analyzer.frequencyBinCount;
			this.frequencyByteData = new Uint8Array(this.frequencyBinCount);
			this.frequencyFloatData = new Float32Array(this.frequencyBinCount);
		} else {
			log("Using Firefox on windows, no FFT support");
		}
	}

	this.getFrequencyBinCount = function() {
		return this.frequencyBinCount;
	}

	this.getByteFFTData = function(smoothing) {
		var tmpsmoothing = smoothing;
		if (!smoothing) {
			tmpsmoothing = 0.5;
		}

		this.analyzer.smoothingTimeConstant = tmpsmoothing;
		this.analyzer.getByteFrequencyData(this.frequencyByteData);

		return this.frequencyByteData;
	}

	this.getFloatFFTData = function(smoothing) {
		var tmpsmoothing = smoothing;
		if (!smoothing) {
			tmpsmoothing = 0.5;
		}

		this.analyzer.smoothingTimeConstant = tmpsmoothing;
		this.analyzer.getFloatFrequencyData(this.frequencyFloatData);

		return this.frequencyFloatData;
	}

 	this.play = function() {
		this.audio.play();
		this.audio.controls = true;
	}

	this.showControls = function(show) {
		this.audio.controls = show;
	}

	this.getTick = function() {
		return Math.floor(this.audio.currentTime * 1000);
	}

	this.getAspectRatio = function() {
		return this.width/this.height;
	}

	this.getWidth = function() {
		return this.width;
	}

	this.getHeight = function() {
		return this.height;
	}

	this.addPart = function(data) {
		this.partdata[this.partdata.length] = data;
	}

	this.draw = function(tick) {
		var parttick = tick;
		var prevpartlengths = 0;
		for (var i=0; i<this.partdata.length; i++) {

			if (i>0) {
				parttick -= this.partdata[i-1].data.partlength;
				prevpartlengths += this.partdata[i-1].data.partlength;
			}

			if (tick<this.partdata[i].data.partlength + prevpartlengths) {
				this.partdata[i].data.player(this.partdata[i], parttick, tick);
				break;
			}
		}
	}

	this.addRenderTarget = function(name, width, height) {
		var w = width || this.getWidth();
		var h = height || this.getHeight();

		this.rendertargets[name] = {};
		this.rendertargets[name].target = new THREE.WebGLRenderTarget( Math.floor(width), Math.floor(height), { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat } );
		this.rendertargets[name].width = Math.floor(width);
		this.rendertargets[name].height = Math.floor(height);

		this.rendertargets[name].getAspectRatio = function(){
			return this.width/this.height;
		}
	}

	this.addRenderer = function(name, antialias, shadowmap, width, height) {
		this.renderers[name] = new THREE.WebGLRenderer( { antialias: antialias } );
		this.renderers[name].shadowMapEnabled = shadowmap;

		if (width && height) {
			this.renderers[name].setSize(width, height);
		} else {
			this.renderers[name].setSize(this.getWidth(), this.getHeight());
		}

		this.renderers[name].setClearColor(0x000000, 1.0);
		this.renderers[name].clear();
	}

	this.addRenderer('main', true, true);

	$(selector).append(this.renderers['main'].domElement);
	this.renderers['main'].domElement.display = 'block';
}
<commit_msg>Added centralized THREE.Clock and some maintenance...<commit_after>function DemoEngine(selector, width, height) {

	// hack for safari
	window.AudioContext = window.AudioContext || window.webkitAudioContext;

	this.partdata = [];
	this.assets = { urls: {} };
	this.renderers = {};
	this.rendertargets = {};
	this.audio = null;
	this.analyzer = null;
	this.audiocontext = null;
	this.audiosource = null;
	this.frequencyByteData = null;
	this.frequencyFloatData = null;
	this.frequencyBinCount = 0;
	this.selectorstr = selector;
	this.fftsupport = true;
	this.clock = new THREE.Clock();

	var tmpelement = $(selector);
	if (tmpelement.length != 1) {
		console.log('Selector "' + selector + '" returned more than one element. ');
		return null;
	}
	this.element = tmpelement[0];

	if (navigator.userAgent.toLowerCase().indexOf('firefox') != -1 ||
		!!navigator.userAgent.match(/Trident.*[ :]*11\./)) {
		this.fftsupport = false;
	}

	this.width = window.innerWidth;
	this.height = window.innerHeight;

	if (width && height) {
		this.width = width;
		this.height = height;
	}

	this.setAudioLooping = function(loop) {
		this.audio.loop = loop;
	}

	this.supportsFFT = function() {
		return this.fftsupport;
	}

	this.setAudio = function(a) {
		this.audiocontext = new AudioContext();
		this.audio = a;
		$(this.selectorstr).append(this.audio);

		if (this.fftsupport) {
			this.audiosource = this.audiocontext.createMediaElementSource(this.audio);
			this.analyzer = this.audiocontext.createAnalyser();
			this.analyzer.fftSize = Math.pow(2,9);
			this.audiosource.connect(this.analyzer);
			this.analyzer.connect(this.audiocontext.destination);
			this.frequencyBinCount = this.analyzer.frequencyBinCount;
			this.frequencyByteData = new Uint8Array(this.frequencyBinCount);
			this.frequencyFloatData = new Float32Array(this.frequencyBinCount);
		} else {
			log("Using Firefox on windows, no FFT support");
		}
	}

	this.getFrequencyBinCount = function() {
		return this.frequencyBinCount;
	}

	this.getByteFFTData = function(smoothing) {
		this.analyzer.smoothingTimeConstant = smoothing || 0.5;
		this.analyzer.getByteFrequencyData(this.frequencyByteData);

		return this.frequencyByteData;
	}

	this.getFloatFFTData = function(smoothing) {
		this.analyzer.smoothingTimeConstant = smoothing || 0.5;
		this.analyzer.getFloatFrequencyData(this.frequencyFloatData);

		return this.frequencyFloatData;
	}

 	this.play = function() {
		this.audio.play();
		this.audio.controls = true;
	}

	this.showControls = function(show) {
		this.audio.controls = show;
	}

	this.getTick = function() {
		return Math.floor(this.audio.currentTime * 1000);
	}

	this.getAspectRatio = function() {
		return this.width/this.height;
	}

	this.getWidth = function() {
		return this.width;
	}

	this.getHeight = function() {
		return this.height;
	}

	this.addPart = function(data) {
		this.partdata[this.partdata.length] = data;
	}

	this.draw = function(tick) {
		var parttick = tick;
		var prevpartlengths = 0;
		for (var i=0; i<this.partdata.length; i++) {

			if (i>0) {
				parttick -= this.partdata[i-1].data.partlength;
				prevpartlengths += this.partdata[i-1].data.partlength;
			}

			if (tick<this.partdata[i].data.partlength + prevpartlengths) {
				this.partdata[i].data.player(this.partdata[i], parttick, tick);
				break;
			}
		}
	}

	this.addRenderTarget = function(name, width, height) {
		var w = width || this.getWidth();
		var h = height || this.getHeight();

		this.rendertargets[name] = {};
		this.rendertargets[name].target = new THREE.WebGLRenderTarget( Math.floor(width), Math.floor(height), { minFilter: THREE.LinearFilter, magFilter: THREE.NearestFilter, format: THREE.RGBAFormat } );
		this.rendertargets[name].width = Math.floor(width);
		this.rendertargets[name].height = Math.floor(height);

		this.rendertargets[name].getAspectRatio = function(){
			return this.width/this.height;
		}
	}

	this.addRenderer = function(name, antialias, shadowmap, width, height) {
		this.renderers[name] = new THREE.WebGLRenderer( { antialias: antialias } );
		this.renderers[name].shadowMapEnabled = shadowmap;

		if (width && height) {
			this.renderers[name].setSize(width, height);
		} else {
			this.renderers[name].setSize(this.getWidth(), this.getHeight());
		}

		this.renderers[name].setClearColor(0x000000, 1.0);
		this.renderers[name].clear();
	}

	this.addRenderer('main', true, true);

	$(selector).append(this.renderers['main'].domElement);
	this.renderers['main'].domElement.display = 'block';
}
<|endoftext|>


<commit_before>define(function(require) {

    'use strict';

    var _       = require('underscore');
    var PIXI    = require('pixi');
    var Vector2 = require('common/math/vector2');
    var PiecewiseCurve = require('common/math/piecewise-curve');

    var ElementView = require('views/element');
    var EnergyChunkView = require('views/energy-chunk');
    var EnergyChunkContainerSliceView = require('views/energy-chunk-container-slice');

    var Constants = require('constants');

    /**
     * A view that represents a block model
     */
    var ThermalElementView = ElementView.extend({

        /**
         *
         */
        initialize: function(options) {
            ElementView.prototype.initialize.apply(this, [options]);
        },

        initEnergyChunks: function(energyChunkLayer) {
            energyChunkLayer.visible = false;

            _.each(this.model.slices, function(slice) {
                var view = new EnergyChunkContainerSliceView({
                    slice: slice,
                    mvt: this.mvt
                });
                energyChunkLayer.addChild(view.displayObject);
            }, this);

            this.approachingEnergyChunkViews = [];
            this.approachingEnergyChunkLayer = new PIXI.DisplayObjectContainer();
            energyChunkLayer.addChild(this.approachingEnergyChunkLayer);

            this.listenTo(this.model.approachingEnergyChunks, 'add',    this.approachingEnergyChunkAdded);
            this.listenTo(this.model.approachingEnergyChunks, 'remove', this.approachingEnergyChunkRemoved);
        },

        approachingEnergyChunkAdded: function(chunk) {
            var view = new EnergyChunkView({
                model: chunk,
                mvt: this.mvt
            });
            this.approachingEnergyChunkLayer.addChild(view.displayObject);
            this.approachingEnergyChunkViews.push(view);
        },

        approachingEnergyChunkRemoved: function(chunk) {
            for (var i = 0; i < this.approachingEnergyChunkViews.length; i++) {
                if (this.approachingEnergyChunkViews[i].model === chunk) {
                    this.approachingEnergyChunkViews[i].stopListening();
                    this.approachingEnergyChunkViews.splice(i, 1);
                    this.approachingEnergyChunkLayer.removeChild(this.approachingEnergyChunkViews[i].displayObject);
                    return;
                }
            }
        }

    });

    return ThermalElementView;
});<commit_msg>This makes the tests work on that first Trello card about unit tests.<commit_after>define(function(require) {

    'use strict';

    var _       = require('underscore');
    var PIXI    = require('pixi');

    var ElementView = require('views/element');
    var EnergyChunkView = require('views/energy-chunk');
    var EnergyChunkContainerSliceView = require('views/energy-chunk-container-slice');

    /**
     * A view that represents a block model
     */
    var ThermalElementView = ElementView.extend({

        /**
         *
         */
        initialize: function(options) {
            ElementView.prototype.initialize.apply(this, [options]);
        },

        initEnergyChunks: function(energyChunkLayer) {
            energyChunkLayer.visible = false;

            _.each(this.model.slices, function(slice) {
                var view = new EnergyChunkContainerSliceView({
                    slice: slice,
                    mvt: this.mvt
                });
                energyChunkLayer.addChild(view.displayObject);
            }, this);

            this.approachingEnergyChunkViews = [];
            this.approachingEnergyChunkLayer = new PIXI.DisplayObjectContainer();
            energyChunkLayer.addChild(this.approachingEnergyChunkLayer);

            this.listenTo(this.model.approachingEnergyChunks, 'add',    this.approachingEnergyChunkAdded);
            this.listenTo(this.model.approachingEnergyChunks, 'remove', this.approachingEnergyChunkRemoved);
        },

        approachingEnergyChunkAdded: function(chunk) {
            var view = new EnergyChunkView({
                model: chunk,
                mvt: this.mvt
            });
            this.approachingEnergyChunkLayer.addChild(view.displayObject);
            this.approachingEnergyChunkViews.push(view);
        },

        approachingEnergyChunkRemoved: function(chunk) {
            for (var i = 0; i < this.approachingEnergyChunkViews.length; i++) {
                if (this.approachingEnergyChunkViews[i].model === chunk) {
                    this.approachingEnergyChunkViews[i].stopListening();
                    this.approachingEnergyChunkViews.splice(i, 1);
                    this.approachingEnergyChunkLayer.removeChild(this.approachingEnergyChunkViews[i].displayObject);
                    return;
                }
            }
        }

    });

    return ThermalElementView;
});<|endoftext|>


<commit_before>var path = require('path');
var stringify = require('./test/support/');
var Scaffold = require('./');

/**
 * UI component
 */

var npm = new Scaffold('component', {
  cwd: '@/scaffolds-example/scaffolds',
  files: [
    {src: 'templates/*.hbs', dest: 'src/'},
    {src: 'scripts/*.js', dest: 'src/'},
    {src: 'styles/*.css', dest: 'src/'},
  ]
});
console.log(stringify(npm));

/**
 * Blog post
 */

var post = new Scaffold('post', {
  cwd: 'test/scaffolds',
  files: [
    {src: 'content/post.md', dest: 'src/posts/'},
    {src: 'scripts/ipsum.json', dest: 'src/data/'}
  ]
});
console.log(stringify(post));

/**
 * Dotfiles
 */

var dotfiles = new Scaffold('dotfiles', '.*', {
  filter: function (fp) {
    return !/DS_Store/.test(fp);
  }
});
console.log(stringify(dotfiles));

var foo = new Scaffold('foo', {
  // `~` tilde expands to the user's home directory
  options: {cwd: '~/scaffolds'},
  src: ['**/component*'],
  dest: 'local/src/'
});
console.log(stringify(foo))

var bar = new Scaffold('foo', {
  // `~` tilde expands to the user's home directory
  options: {cwd: '~', srcBase: 'scaffolds'},
  src: ['*/component.*'],
  dest: 'local/src/'
});
console.log(stringify(bar));

// function component(name) {
//   return new Scaffold(name, {
//     files: {src: ['*.js'], dest: 'src'},
//     rename: function(dest, src, opts) {
//       return path.join(dest, name, 'index') + path.extname(src);
//     }
//   });
// }

// component('foo')
// //=> 'src/foo/index.js'
// component('bar')
// //=> 'src/bar/index.js'
// component('baz')
// //=> 'src/baz/index.js'
<commit_msg>update examples<commit_after>var path = require('path');
var stringify = require('./test/support/');
var Scaffold = require('./');

/**
 * UI component
 */

var npm = new Scaffold({
  component: {
    cwd: '@/scaffolds-example/scaffolds',
    files: [
      {src: 'templates/*.hbs', dest: 'src/'},
      {src: 'scripts/*.js', dest: 'src/'},
      {src: 'styles/*.css', dest: 'src/'},
    ]
  }
});
console.log(stringify(npm));

/**
 * Blog posts
 */

var blog = new Scaffold({
  post: {
    cwd: 'test/scaffolds',
    files: [
      {src: 'content/post.md', dest: 'src/posts/'},
      {src: 'scripts/ipsum.json', dest: 'src/data/'}
    ]
  }
});
console.log(stringify(blog));

/**
 * Dotfiles
 */

var dotfiles = new Scaffold({
  root: {
    src: '.*',
    filter: function (fp) {
      return !/DS_Store/.test(fp);
    }
  }
});

console.log(stringify(dotfiles));

// `~` tilde expands to the user's home directory
var home = new Scaffold({
  foo: {
    options: {cwd: '~/scaffolds'},
    src: ['**/component*'],
    dest: 'local/src/'
  },
  bar: {
    options: {cwd: '~', srcBase: 'scaffolds'},
    src: ['*/component.*'],
    dest: 'local/src/'
  }
});
console.log(stringify(home))

function component(name) {
  var scaffold = {};
  scaffold[name] = {
    files: {
      src: ['*.js'],
      dest: 'src'
    },
    rename: function (dest, src, opts) {
      return path.join(dest, name, 'index') + path.extname(src);
    }
  };
  return new Scaffold(scaffold);
}

console.log(component('foo'));
//=> 'src/foo/index.js'
console.log(component('bar'));
//=> 'src/bar/index.js'
console.log(component('baz'));
//=> 'src/baz/index.js'
<|endoftext|>