<commit_before>const _ = require('lodash');
const Discord = require('discord.js');
const AsyncPolling = require('async-polling');
const cheerio = require('cheerio');
const axios = require('axios');
const http = require('http');
const math = require('mathjs');
const moment = require('moment-timezone');
const command = require('./command.js');
const pollingList = require('./polling.js');
const pkg = require('./package.json');
const config = require('./config.json');

moment.tz.setDefault('Asia/Shanghai');

// set default request timeout
axios.defaults.timeout = 10000;

class Bot {
    constructor() {
        this.client = new Discord.Client();
        this.pollingList = pollingList;

        // create pollings
        _.forOwn(this.pollingList, (o, k) => {
            let delay = _.isNumber(o.delay) ? o.delay : _.isFunction(o.delay) ? o.delay() : null;
            o.asyncPolling = AsyncPolling(end => {
                // save current time
                this.lastPollingTime = moment();
                let promise = null;

                if(_.isArray(o.url)) {
                    let all = o.url.map((url, i) => {
                        return axios.get(url, o.axiosOptions)
                            .then( res=> {
                                return o.parseData[i](this, res.data);
                            })
                    });

                    promise = axios.all(all)
                        .then(res => {
                            if(!o.latestChapter) {
                                o.latestChapter = res[0];
                                o.onLoadChapter(this);
                                o.lastChapterTime = moment();
                                return null;
                            } else {
                                let newData = null;
                                res.forEach(e => {
                                    if(e.title !== o.latestChapter.title) {
                                        newData = e;
                                    }
                                });
                                if(newData) {
                                    o.latestChapter = newData;
                                }
                                return newData ? o : null;
                            }
                        }, e => {
                            console.error(e);
                            end();
                        });
                }
                else {
                    promise = axios.get(o.url, o.axiosOptions)
                        .then(res => {
                            // return null if you don't want it to reports.
                            let newData = o.parseData(this, res.data);
                            if(!o.latestChapter) {
                                // first time
                                o.latestChapter = newData;
                                o.onLoadChapter(this);
                                o.lastChapterTime = moment();
                                return null;
                            } else {
                                if(o.latestChapter.url !== newData.url) {
                                    o.latestChapter = newData;
                                    return o;
                                }
                                return null;
                            }
                        }, e => {
                            console.error(e);
                            end();
                        });
                }

                promise.then(o => {
                    if(_.isObject(o)) {
                        let str = o.onNewChapter(this);
                        this.broadcast(str, 'notices');
                    }
                    end();
                }, e => {
                    console.error(e);
                    end();
                })
                .catch(e => {
                    console.error(e);
                    end();
                });
           },  delay);
        });

        this.changeDelayInterval = AsyncPolling(end => {
            _.forOwn(this.pollingList, o => {
                if(_.isFunction(o.delay)) {
                    let newDelay = o.delay();
                    if(newDelay !== o.asyncPolling._delay) {
                        o.asyncPolling._delay = newDelay;
                    }
                }
            });
        }, 60000 * 10);

        // on ready
        this.client.on('ready', () => {
            console.log('Bot is ready');
            console.log(`https://discordapp.com/api/oauth2/authorize?client_id=${config.client_id}&scope=bot&permissions=${config.permissions}`);

            this.startTime = moment();
            this.lastPollingTime = moment();
            this.runPoll();
            this.changeDelayInterval.run();
            this.broadcast('Hong\'er v' + pkg.version + ' is ready!!\nOhhh!!!');
        });

        // msg listener
        this.client.on('message', message => {
            // only this channel
            if(message.channel.name !== 'talk-to-honger') {
                return;
            }

            // only if Hong'er is mentioned
            if(!message.mentions.everyone && message.mentions.users.find('id', this.client.user.id)) {
                message.channel.send(':sleeping:');
            }

            // command start with !
            if(message.content.startsWith('!')) {
                let token = message.content.split(' '); //match(/(?:[^\s"]+|"[^"]*")+/g)
                let cmd = token[0].substr(1).toLowerCase();
                let args = token.slice(1);
                let result = _.pickBy(command, (v, k) => _.startsWith(k, cmd));
                let resultKeys = _.keys(result);
                let done = null;

                if(cmd.length === 0) {
                }
                else if(resultKeys.length === 1) {
                    done = result[resultKeys[0]].action(this, message, ...args);
                } else if(resultKeys.length > 1) {
                    let exact = _.find(resultKeys, (k) => parseInt(k.split('_')[1]) === args.length);

                    // exactly arg len
                    if(exact) {
                        done = result[exact].action(this, message, ...args);
                    } else {
                        // more than arg len
                        let more = _.reduce(resultKeys, (candidate, k) => {
                            let n = parseInt(k.split('_')[1]);
                            let c = parseInt(candidate.split('_')[1]);
                            if(c < n) {
                                return k;
                            }
                            return candidate;
                        }, resultKeys[0]);

                        done = result[more].action(this, message, ...args);
                    }
                }

                // error handling
                if(done === false) {
                    message.channel.send('Error: wrong conditions or arguments');
                }
                if(done === null) {
                    //message.channel.send('Error: cannot find command');
                }
            }
        });
    }
    broadcast(content, name) {
        this.client.guilds.array().forEach(g => {
            let channel = g.channels.find('name', name || 'talk-to-honger');
            if(channel) {
                channel.send(content);
            }
        });
    }
    connect() {
        // dummy http server
        http.createServer(function(req,res) {
            res.writeHead(200);
            res.write('Launched!');
            res.end();
        }).listen(process.env.PORT || 3000);

        // connect to discord
        this.client.login(config.token);
    }
    runPoll(name) {
        if(name) {
            this.pollingList[name].asyncPolling.run()
        }
        else {
            _.forOwn(this.pollingList, e => e.asyncPolling ? e.asyncPolling.run() : null);
        }
    }
    stopPoll(name) {
        if(name) {
            this.pollingList[name].asyncPolling.stop();
        }
        else {
            _.forOwn(this.pollingList, e => e.asyncPolling ? e.asyncPolling.stop() : null);
        }
    }
}

new Bot().connect();<commit_msg>Refix again<commit_after>const _ = require('lodash');
const Discord = require('discord.js');
const AsyncPolling = require('async-polling');
const cheerio = require('cheerio');
const axios = require('axios');
const http = require('http');
const math = require('mathjs');
const moment = require('moment-timezone');
const command = require('./command.js');
const pollingList = require('./polling.js');
const pkg = require('./package.json');
const config = require('./config.json');

moment.tz.setDefault('Asia/Shanghai');

// set default request timeout
axios.defaults.timeout = 5000;

class Bot {
    constructor() {
        this.client = new Discord.Client();
        this.pollingList = pollingList;

        // create pollings
        _.forOwn(this.pollingList, (o, k) => {
            let delay = _.isNumber(o.delay) ? o.delay : _.isFunction(o.delay) ? o.delay() : null;
            o.asyncPolling = AsyncPolling(end => {
                // save current time
                this.lastPollingTime = moment();
                let promise = null;

                if(_.isArray(o.url)) {
                    let all = o.url.map((url, i) => {
                        return axios.get(url, o.axiosOptions)
                            .then( res=> {
                                return o.parseData[i](this, res.data);
                            }, e => null)
                            .catch(e => e);
                    });

                    promise = axios.all(all)
                        .then(res => {
                            if(!o.latestChapter) {
                                o.latestChapter = res[0];
                                o.onLoadChapter(this);
                                o.lastChapterTime = moment();
                                return null;
                            } else {
                                let newData = null;
                                res.forEach(e => {
                                    if(e && e.title !== o.latestChapter.title) {
                                        newData = e;
                                    }
                                });
                                if(newData) {
                                    o.latestChapter = newData;
                                }
                                return newData ? o : null;
                            }
                        }, e => {
                            console.error(e);
                            end();
                        });
                }
                else {
                    promise = axios.get(o.url, o.axiosOptions)
                        .then(res => {
                            // return null if you don't want it to reports.
                            let newData = o.parseData(this, res.data);
                            if(!o.latestChapter) {
                                // first time
                                o.latestChapter = newData;
                                o.onLoadChapter(this);
                                o.lastChapterTime = moment();
                                return null;
                            } else {
                                if(o.latestChapter.url !== newData.url) {
                                    o.latestChapter = newData;
                                    return o;
                                }
                                return null;
                            }
                        }, e => {
                            console.error(e);
                            end();
                        });
                }

                promise.then(o => {
                    if(_.isObject(o)) {
                        let str = o.onNewChapter(this);
                        this.broadcast(str, 'notices');
                    }
                    end();
                }, e => {
                    console.error(e);
                    end();
                })
                .catch(e => {
                    console.error(e);
                    end();
                });
           },  delay);
        });

        this.changeDelayInterval = AsyncPolling(end => {
            _.forOwn(this.pollingList, o => {
                if(_.isFunction(o.delay)) {
                    let newDelay = o.delay();
                    if(newDelay !== o.asyncPolling._delay) {
                        o.asyncPolling._delay = newDelay;
                    }
                }
            });
        }, 60000 * 10);

        // on ready
        this.client.on('ready', () => {
            console.log('Bot is ready');
            console.log(`https://discordapp.com/api/oauth2/authorize?client_id=${config.client_id}&scope=bot&permissions=${config.permissions}`);

            this.startTime = moment();
            this.lastPollingTime = moment();
            this.runPoll();
            this.changeDelayInterval.run();
            this.broadcast('Hong\'er v' + pkg.version + ' is ready!!\nOhhh!!!');
        });

        // msg listener
        this.client.on('message', message => {
            // only this channel
            if(message.channel.name !== 'talk-to-honger') {
                return;
            }

            // only if Hong'er is mentioned
            if(!message.mentions.everyone && message.mentions.users.find('id', this.client.user.id)) {
                message.channel.send(':sleeping:');
            }

            // command start with !
            if(message.content.startsWith('!')) {
                let token = message.content.split(' '); //match(/(?:[^\s"]+|"[^"]*")+/g)
                let cmd = token[0].substr(1).toLowerCase();
                let args = token.slice(1);
                let result = _.pickBy(command, (v, k) => _.startsWith(k, cmd));
                let resultKeys = _.keys(result);
                let done = null;

                if(cmd.length === 0) {
                }
                else if(resultKeys.length === 1) {
                    done = result[resultKeys[0]].action(this, message, ...args);
                } else if(resultKeys.length > 1) {
                    let exact = _.find(resultKeys, (k) => parseInt(k.split('_')[1]) === args.length);

                    // exactly arg len
                    if(exact) {
                        done = result[exact].action(this, message, ...args);
                    } else {
                        // more than arg len
                        let more = _.reduce(resultKeys, (candidate, k) => {
                            let n = parseInt(k.split('_')[1]);
                            let c = parseInt(candidate.split('_')[1]);
                            if(c < n) {
                                return k;
                            }
                            return candidate;
                        }, resultKeys[0]);

                        done = result[more].action(this, message, ...args);
                    }
                }

                // error handling
                if(done === false) {
                    message.channel.send('Error: wrong conditions or arguments');
                }
                if(done === null) {
                    //message.channel.send('Error: cannot find command');
                }
            }
        });
    }
    broadcast(content, name) {
        this.client.guilds.array().forEach(g => {
            let channel = g.channels.find('name', name || 'talk-to-honger');
            if(channel) {
                channel.send(content);
            }
        });
    }
    connect() {
        // dummy http server
        http.createServer(function(req,res) {
            res.writeHead(200);
            res.write('Launched!');
            res.end();
        }).listen(process.env.PORT || 3000);

        // connect to discord
        this.client.login(config.token);
    }
    runPoll(name) {
        if(name) {
            this.pollingList[name].asyncPolling.run()
        }
        else {
            _.forOwn(this.pollingList, e => e.asyncPolling ? e.asyncPolling.run() : null);
        }
    }
    stopPoll(name) {
        if(name) {
            this.pollingList[name].asyncPolling.stop();
        }
        else {
            _.forOwn(this.pollingList, e => e.asyncPolling ? e.asyncPolling.stop() : null);
        }
    }
}

new Bot().connect();<|endoftext|>


<commit_before>/******** Project - Final *********************************
Authors: Eric Wooley, Tandra Felly, Lauryn Loudermilk
Description: Javascript automata engine.
**********************************************************/
// Start Automiton engine
var aut = new DFA();
// TODO: Hookup DFA STFF HERE
// Adds an html5 canvas to container
var stage = new Kinetic.Stage({
  container: 'canvas_container',
  width:$("#canvas_container").width(),
  height: $("#canvas_container").height()
});
// index, with the keys formatted as stateFromId-stateToId
// ex: if a state goes from state with id 1, to a state with id 3
// the index would be savedTransitions["1-3"]
var savedTransitions = {};

// Layer to preview gestuers on.
var gesture_preview = new Kinetic.Layer();

// Layer to have touch events on.
var touch_layer = new Kinetic.Layer();

// We want to mark the first state as starting, this will be set to false upon drawing a state.
var firstState = true;
// Layer to draw our shapes
var dfa_layer = new Kinetic.Layer();
stage.add(dfa_layer);

// layer for arcs
var transition_layer = new Kinetic.Layer();
stage.add(transition_layer);

var tooltip_layer = new Kinetic.Layer();
stage.add(tooltip_layer);

markerLayer = new Kinetic.Layer();
var startingMarker = new Kinetic.Wedge({
  radius: 70,
  angleDeg: 60,
  stroke: 'black',
  strokeWidth: 3,
  rotationDeg: 150
});
markerLayer.add(startingMarker);
stage.add(markerLayer);
// an empty stage does not emit mouse-events
// so fill the stage with a background rectangle
// that can emit mouse-events
var whiteboard = new Kinetic.Rect({
  x: 0,
  y: 0,
  width: stage.getWidth(),
  height: stage.getHeight(),
  stroke: 'black',
  strokeWidth: 1,
  });

// an array of all the states.
var states = {};
// these are the gesture events. when we get a circle call this event, etc...
var events = {
  circle: function(e){
    var state = new State(e);
    state.on('dragstart', function() {
      console.log('dragstart');
      this.setFill("grey");
      dfa_layer.draw();
    });
    state.on('dragend', function() {
      console.log('dragend');
      this.setFill("red");
      state.redrawTransitions();
      transition_layer.draw();
      dfa_layer.draw();
    });
    state.on('click', function(){
      console.log("you clicked the circle!");
      if (document.getElementById("move").checked){
        console.log('move is active')
      }
      else if (document.getElementById("initial").checked){
        console.log('make initial')
        aut.setStartingNode(state.node);
        moveStartingMarker(state);
        markerLayer.draw();
        aut.setStartingNode(state);

      }
      else if (document.getElementById("accepting").checked){
        console.log('make accepting')
        state.toggleAccepting(true);
        dfa_layer.draw();
      }
      else{
        console.log('delete is active')
        var answer = confirm("Would you like to delete this object?")
        if (answer){
          state.remove();
          dfa_layer.draw();
        }
        else{
          return;
        }
      }
    });
    if(firstState){
      firstState = false;
      moveStartingMarker(state);
      markerLayer.draw();
      aut.setStartingNode(state);
    }
    states[state.getId()] = state;

  },

  // This function is fired when there is a line drawn between two circles.
  // This funciton can be found in lib/transition.js
  line: function(e){
    transition(e);
  }
};

// Call the canvas gestures library.
gesturesController = canvas_gestures({
  whiteboard: whiteboard,
  stage: stage,
  preview: gesture_preview,
  events: events,
  // onClick:function(loc){
  //   console.log(JSON.stringify(loc))
  //   $.each(states, function(index, state){
  //     if(state.geo.intersects(loc)){
  //       return state.geo.fire("click");
  //     }
  //   });
  // }
});
gesturesController.enableGestures();
// to disable gestures controller:
// gesturesController.disableGestures();
touch_layer.add(whiteboard);
touch_layer.draw();

stage.add(touch_layer);
stage.add(gesture_preview);<commit_msg>Made state work on groups rather than with the circle object.<commit_after>/******** Project - Final *********************************
Authors: Eric Wooley, Tandra Felly, Lauryn Loudermilk
Description: Javascript automata engine.
**********************************************************/
// Start Automiton engine
var aut = new DFA();
// TODO: Hookup DFA STFF HERE
// Adds an html5 canvas to container
var stage = new Kinetic.Stage({
  container: 'canvas_container',
  width:$("#canvas_container").width(),
  height: $("#canvas_container").height()
});
// index, with the keys formatted as stateFromId-stateToId
// ex: if a state goes from state with id 1, to a state with id 3
// the index would be savedTransitions["1-3"]
var savedTransitions = {};

// Layer to preview gestuers on.
var gesture_preview = new Kinetic.Layer();

// Layer to have touch events on.
var touch_layer = new Kinetic.Layer();

// We want to mark the first state as starting, this will be set to false upon drawing a state.
var firstState = true;
// Layer to draw our shapes
var dfa_layer = new Kinetic.Layer();
stage.add(dfa_layer);

// layer for arcs
var transition_layer = new Kinetic.Layer();
stage.add(transition_layer);

var tooltip_layer = new Kinetic.Layer();
stage.add(tooltip_layer);

markerLayer = new Kinetic.Layer();
var startingState;
var startingMarker = new Kinetic.Wedge({
  radius: 40,
  angleDeg: 60,
  stroke: 'black',
  fill: "white",
  strokeWidth: 3,
  rotationDeg: 150
});
// an empty stage does not emit mouse-events
// so fill the stage with a background rectangle
// that can emit mouse-events
var whiteboard = new Kinetic.Rect({
  x: 0,
  y: 0,
  width: stage.getWidth(),
  height: stage.getHeight(),
  stroke: 'black',
  strokeWidth: 1,
  });

// an array of all the states.
var states = {};
// these are the gesture events. when we get a circle call this event, etc...
var events = {
  circle: function(e){
    var state = new State(e);
    state.on('dragstart', function() {
      state.setFill("grey");
      dfa_layer.draw();
    });
    state.on('dragend', function() {
      state.setFill("red");
      state.redrawTransitions();
      transition_layer.draw();
      dfa_layer.draw();
    });
    state.on('click', function(){
      console.log("you clicked the circle!");
      if (document.getElementById("move").checked){
        console.log('move is active')
      }
      else if (document.getElementById("initial").checked){
        console.log('make initial')
        aut.setStartingNode(state.node);
        moveStartingMarker(state);
        markerLayer.draw();
        aut.setStartingNode(state);

      }
      else if (document.getElementById("accepting").checked){
        console.log('make accepting')
        state.toggleAccepting(true);
        dfa_layer.draw();
      }
      else{
        console.log('delete is active')
        var answer = confirm("Would you like to delete this object?")
        if (answer){
          state.remove();
          dfa_layer.draw();
        }
        else{
          return;
        }
      }
    });
    if(firstState){
      firstState = false;
      moveStartingMarker(state);
      markerLayer.draw();
      aut.setStartingNode(state);
    }
    states[state.getId()] = state;
    dfa_layer.draw();

  },

  // This function is fired when there is a line drawn between two circles.
  // This funciton can be found in lib/transition.js
  line: function(e){
    transition(e);
  }
};

// Call the canvas gestures library.
gesturesController = canvas_gestures({
  whiteboard: whiteboard,
  stage: stage,
  preview: gesture_preview,
  events: events,
  // onClick:function(loc){
  //   console.log(JSON.stringify(loc))
  //   $.each(states, function(index, state){
  //     if(state.geo.intersects(loc)){
  //       return state.geo.fire("click");
  //     }
  //   });
  // }
});
gesturesController.enableGestures();
// to disable gestures controller:
// gesturesController.disableGestures();
touch_layer.add(whiteboard);
touch_layer.draw();

stage.add(touch_layer);
stage.add(gesture_preview);<|endoftext|>


<commit_before>//
// Loader for Strider extension modules.
//

var async = require('async'),
    connect = require('connect'),
    fs = require('fs'),
    path = require('path'),
    Step = require('step');

//
// ### Locate Strider Extensions
//
// Under a specified path **dir** look for directories containing file
// 'strider.json'.  These are considered Strider modules. **dir** may be either a string or a list of strings.
//
// **cb** is a function of signature cb(err, extensions) where extensions is an
// array of filesystems path on success and err is an error on failure.
//
function findExtensions(dir, cb) {

  var filename = "strider.json";

  var extensions = [];

  // fs.readdir list of paths in parallel.
  // used when `dir` arg is an array.
  function readEntries(dirs, cb) {
    var funcs = []
    dirs.forEach(function(dir) {
      funcs.push(function(c) {
        fs.readdir(dir, function(err, entries) {
          var l = [];
          entries.forEach(function(entry) {
            l.push(path.join(dir, entry))
          })
          c(err, l)
        })
      })
    })
    async.parallel(funcs, function(err, results) {
        if (err) {
          return cb(err, null);
        }
        // Flatten results and return
        var flat = [].concat.apply([], results);
        cb(null, flat);
      }
    );
  }

  Step(
    function() {
      // find top-level module dirs
      if (Array.isArray(dir)) {
        // dir is a list of paths
        readEntries(dir, this)
      } else {
        // dir is a single path value
        var self = this;
        fs.readdir(dir, function(err, entries) {
          if (err || !entries) {
            return self(err, entries);
          }
          var l = [];
          entries.forEach(function(entry) {
            l.push(path.join(dir, entry))
          });
          self(err, l);
        });
      }
    },
    function(err, entries) {
      if (err) {
        throw err;
      }
      // Stat extension files in parallel
      var group = this.group();
      entries.forEach(function(module) {
        var p = path.join(module, filename);
        var cb = group();
        fs.stat(p, function(err, stat) {
          cb(err,
            {stat:stat, path:module});
        });
      });
    },
    function(err, results) {
      if (!results)
        results = [];

      results.forEach(function(r) {
        if (!r.stat) {
          return;
        }
        // Ensure they are of type file not something else
        if (r.stat.isFile()) {
          extensions.push(r.path);
        }
      });
      cb(null, extensions);
    }
  );
}

var parseStriderData = function(json, typ,  ext){
  ext.id = ext.id || ((typ == "package") ? json.name : json.id)

  ext[typ] = json;

  for (var i in json){
    ext[i] = json[i];
  }
}

//
//### Load a Strider extension
//
// **moduleDir* is a directory containing a strider.json file and a package.json file.
//
// **cb** is a function of signature function(err, extension) where extension
// is an extension object on success and err is an error on failure.
//
// Note that this function does not initialize the extension.
//
function loadExtension(moduleDir, cb) {
  Step(
    function() {
      var striderFile = path.join(moduleDir, "strider.json");
      var packageFile = path.join(moduleDir, "package.json");
      fs.readFile(striderFile, this.parallel());
      fs.readFile(packageFile, this.parallel());
    },
    function(err, striderData, packageData) {
      if (err) return cb(err, null);

      // Parse extension JSON
      try {
        var extensionConfig = JSON.parse(striderData);
        var packageConfig = JSON.parse(packageData);
      } catch(e) {
        return cb(e, null);
      }

      var extension = {};

      parseStriderData(packageConfig, "package", extension);
      parseStriderData(extensionConfig, "strider", extension);

      if (!extension.id){
        console.error("\n\nExtension loaded that has no id. Extensions now require ID's",
          "- check if you're running an out of date plugin or contact the plugin author")
        return cb("No ID in " + moduleDir)
      }

      // load workers, webapps

      extensionConfig = extension.strider || {}
      if (extensionConfig.webapp) {
        var webapp = extensionConfig.webapp;
        extension.webapp = require(path.resolve(path.join(moduleDir, webapp)));
      }
      if (extensionConfig.worker) {
        var worker = extensionConfig.worker;
        extension.worker = require(path.resolve(path.join(moduleDir, worker)));
      }
      if (extensionConfig.templates){
        extension.templates = extensionConfig.templates;
      }
      cb(null, extension);
    }
  );
}

//
// ### Initialize Strider Extensions
//
// Find, load and initialize extenions of type ***type*** under extension
// directory ***extdir*** ***type*** may be one of "webapp" or "worker".
//
// Context should be a Strider context object with keys:
//  - config (strider config object)
//  - emitter (global eventemitter)
//  - extensionRoutes (list of webapp routes)
//  - registerTransportMiddleware (function)
//
// ***appInstance*** should be an ExpressJS app instance, and is only needed
// for webapp extensions. Can be left null/undefined for worker extensions.
//
// ***cb*** is a callback to be executed when all modules are initialized.
//
function initExtensions(extdir, type, context, appInstance, cb) {
  var  templates = {}

  Step(
    function() {
      console.log("Looking for %s-type extensions under %s", type, extdir);
      findExtensions(extdir, this);
    },
    function(err, extensions) {
      var group = this.group();
      extensions.forEach(function(ext) {
        var cb = group();
        loadExtension(ext, function(err, res) {
          cb(err, {ext:res, dir:ext});
        });
      });
    },
    function(err, loaded) {
      if (err) {
        console.error("Error loading extension: %s", err);
        process.exit(1);
      }
      var initCount = 0

      // now to initialize
      var self = this

      for (var i=0; i < loaded.length; i++) {
        var l = loaded[i];
        if (l.ext === null) {
          continue;
        }
        // Keep track of which extensions are using which routes.
        // Put this here to allow use of a closure over path and extension.
        if (type === 'webapp') {
          // Extensions should use context.route.<method>() to add routes
          context.route = {
            get:function(p, f) {
              context.extensionRoutes.push(
                {method:"get", path:p, extension:l.dir});
              appInstance.get.apply(appInstance, arguments);
            },
            post:function(p, f) {
              context.extensionRoutes.push(
                {method:"post", path:p, extension:l.dir});
              appInstance.post.apply(appInstance, arguments);
            },
            delete:function(p, f) {
              context.extensionRoutes.push(
                {method:"delete", path:p, extension:l.dir});
              appInstance.delete.apply(appInstance, arguments);
            },
            put:function(p, f) {
              context.extensionRoutes.push(
                {method:"put", path:p, extension:l.dir});
              appInstance.put.apply(appInstance, arguments);
            }
          };
          // Add a static fileserver mounted at /ext/$module/ which maps to
          // moduledir/static
          appInstance.use('/ext/' + path.basename(l.dir),
              connect.static(path.join(l.dir, "static")));
        }
        if (type === 'worker' && typeof(l.ext.worker) === 'function') {
          try {
            l.ext.worker(context, self.parallel());
          } catch (e) {
            console.log("Error loading extension: %s in directory: %s", e, l.dir)
            process.exit(1)

          }
          initCount++;
        }
        if (type === 'webapp' && typeof(l.ext.webapp) === 'function') {
          try {
            l.ext.webapp(context, self.parallel());
          } catch (e) {
            console.log("Error loading extension: %s in directory: %s", e, l.dir)
            process.exit(1)
          }
          initCount++;
        }
        if (l.ext.templates){
          for (var k in l.ext.templates){
            templates[k] = l.ext.templates[k]

            if (/\.html/.test(l.ext.templates[k])){
              templates[k] = l.dir + '/' + l.ext.templates[k];
            }
          }
        }
      }
      if (initCount === 0) {
        // Bit odd, but necessary.
        this(null, []);
      }
    },
    function(err, initialized) {
      if (err) {
        console.log("Error loading extensions: %s", err);
        process.exit(1);
      }
      cb(null, initialized, templates);
    }
  );
}

// Exported functions
module.exports = {
  findExtensions: findExtensions,
  initExtensions: initExtensions,
  loadExtension: loadExtension,
};
<commit_msg>put back in plugin ordering removed in commit 9351699f55271b45f5c1f7a009db5fe1102e2e22 unbreaks tests, ok @peterbraden<commit_after>//
// Loader for Strider extension modules.
//

var async = require('async'),
    connect = require('connect'),
    fs = require('fs'),
    path = require('path'),
    Step = require('step');

//
// ### Locate Strider Extensions
//
// Under a specified path **dir** look for directories containing file
// 'strider.json'.  These are considered Strider modules. **dir** may be either a string or a list of strings.
//
// **cb** is a function of signature cb(err, extensions) where extensions is an
// array of filesystems path on success and err is an error on failure.
//
function findExtensions(dir, cb) {

  var filename = "strider.json";

  var extensions = [];

  // fs.readdir list of paths in parallel.
  // used when `dir` arg is an array.
  function readEntries(dirs, cb) {
    var funcs = []
    dirs.forEach(function(dir) {
      funcs.push(function(c) {
        fs.readdir(dir, function(err, entries) {
          var l = [];
          entries.forEach(function(entry) {
            l.push(path.join(dir, entry))
          })
          c(err, l)
        })
      })
    })
    async.parallel(funcs, function(err, results) {
        if (err) {
          return cb(err, null);
        }
        // Flatten results and return
        var flat = [].concat.apply([], results);
        cb(null, flat);
      }
    );
  }

  Step(
    function() {
      // find top-level module dirs
      if (Array.isArray(dir)) {
        // dir is a list of paths
        readEntries(dir, this)
      } else {
        // dir is a single path value
        var self = this;
        fs.readdir(dir, function(err, entries) {
          if (err || !entries) {
            return self(err, entries);
          }
          var l = [];
          entries.forEach(function(entry) {
            l.push(path.join(dir, entry))
          });
          self(err, l);
        });
      }
    },
    function(err, entries) {
      if (err) {
        throw err;
      }
      // Stat extension files in parallel
      var group = this.group();
      entries.forEach(function(module) {
        var p = path.join(module, filename);
        var cb = group();
        fs.stat(p, function(err, stat) {
          cb(err,
            {stat:stat, path:module});
        });
      });
    },
    function(err, results) {
      if (!results)
        results = [];

      results.forEach(function(r) {
        if (!r.stat) {
          return;
        }
        // Ensure they are of type file not something else
        if (r.stat.isFile()) {
          extensions.push(r.path);
        }
      });
      cb(null, extensions);
    }
  );
}

var parseStriderData = function(json, typ,  ext){
  ext.id = ext.id || ((typ == "package") ? json.name : json.id)

  ext[typ] = json;

  for (var i in json){
    ext[i] = json[i];
  }
}

//
//### Load a Strider extension
//
// **moduleDir* is a directory containing a strider.json file and a package.json file.
//
// **cb** is a function of signature function(err, extension) where extension
// is an extension object on success and err is an error on failure.
//
// Note that this function does not initialize the extension.
//
function loadExtension(moduleDir, cb) {
  Step(
    function() {
      var striderFile = path.join(moduleDir, "strider.json");
      var packageFile = path.join(moduleDir, "package.json");
      fs.readFile(striderFile, this.parallel());
      fs.readFile(packageFile, this.parallel());
    },
    function(err, striderData, packageData) {
      if (err) return cb(err, null);

      // Parse extension JSON
      try {
        var extensionConfig = JSON.parse(striderData);
        var packageConfig = JSON.parse(packageData);
      } catch(e) {
        return cb(e, null);
      }

      var extension = {};

      parseStriderData(packageConfig, "package", extension);
      parseStriderData(extensionConfig, "strider", extension);

      if (!extension.id){
        console.error("\n\nExtension loaded that has no id. Extensions now require ID's",
          "- check if you're running an out of date plugin or contact the plugin author")
        return cb("No ID in " + moduleDir)
      }

      // load workers, webapps

      extensionConfig = extension.strider || {}
      if (extensionConfig.webapp) {
        var webapp = extensionConfig.webapp;
        extension.webapp = require(path.resolve(path.join(moduleDir, webapp)));
      }
      if (extensionConfig.worker) {
        var worker = extensionConfig.worker;
        extension.worker = require(path.resolve(path.join(moduleDir, worker)));
      }
      if (extensionConfig.templates){
        extension.templates = extensionConfig.templates;
      }
      cb(null, extension);
    }
  );
}

//
// ### Initialize Strider Extensions
//
// Find, load and initialize extenions of type ***type*** under extension
// directory ***extdir*** ***type*** may be one of "webapp" or "worker".
//
// Context should be a Strider context object with keys:
//  - config (strider config object)
//  - emitter (global eventemitter)
//  - extensionRoutes (list of webapp routes)
//  - registerTransportMiddleware (function)
//
// ***appInstance*** should be an ExpressJS app instance, and is only needed
// for webapp extensions. Can be left null/undefined for worker extensions.
//
// ***cb*** is a callback to be executed when all modules are initialized.
//
function initExtensions(extdir, type, context, appInstance, cb) {
  var  templates = {}

  Step(
    function() {
      console.log("Looking for %s-type extensions under %s", type, extdir);
      findExtensions(extdir, this);
    },
    function(err, extensions) {
      var group = this.group();
      extensions.forEach(function(ext) {
        var cb = group();
        loadExtension(ext, function(err, res) {
          cb(err, {ext:res, dir:ext});
        });
      });
    },
    function(err, loaded) {
      if (err) {
        console.error("Error loading extension: %s", err);
        process.exit(1);
      }
      var initCount = 0

      // now to initialize
      var self = this
      // Sort by weight
      loaded = loaded.sort(function (a, b) { return a.ext.weight - b.ext.weight; });

      for (var i=0; i < loaded.length; i++) {
        var l = loaded[i];
        if (l.ext === null) {
          continue;
        }
        // Keep track of which extensions are using which routes.
        // Put this here to allow use of a closure over path and extension.
        if (type === 'webapp') {
          // Extensions should use context.route.<method>() to add routes
          context.route = {
            get:function(p, f) {
              context.extensionRoutes.push(
                {method:"get", path:p, extension:l.dir});
              appInstance.get.apply(appInstance, arguments);
            },
            post:function(p, f) {
              context.extensionRoutes.push(
                {method:"post", path:p, extension:l.dir});
              appInstance.post.apply(appInstance, arguments);
            },
            delete:function(p, f) {
              context.extensionRoutes.push(
                {method:"delete", path:p, extension:l.dir});
              appInstance.delete.apply(appInstance, arguments);
            },
            put:function(p, f) {
              context.extensionRoutes.push(
                {method:"put", path:p, extension:l.dir});
              appInstance.put.apply(appInstance, arguments);
            }
          };
          // Add a static fileserver mounted at /ext/$module/ which maps to
          // moduledir/static
          appInstance.use('/ext/' + path.basename(l.dir),
              connect.static(path.join(l.dir, "static")));
        }
        if (type === 'worker' && typeof(l.ext.worker) === 'function') {
          try {
            l.ext.worker(context, self.parallel());
          } catch (e) {
            console.log("Error loading extension: %s in directory: %s", e, l.dir)
            process.exit(1)

          }
          initCount++;
        }
        if (type === 'webapp' && typeof(l.ext.webapp) === 'function') {
          try {
            l.ext.webapp(context, self.parallel());
          } catch (e) {
            console.log("Error loading extension: %s in directory: %s", e, l.dir)
            process.exit(1)
          }
          initCount++;
        }
        if (l.ext.templates){
          for (var k in l.ext.templates){
            templates[k] = l.ext.templates[k]

            if (/\.html/.test(l.ext.templates[k])){
              templates[k] = l.dir + '/' + l.ext.templates[k];
            }
          }
        }
      }
      if (initCount === 0) {
        // Bit odd, but necessary.
        this(null, []);
      }
    },
    function(err, initialized) {
      if (err) {
        console.log("Error loading extensions: %s", err);
        process.exit(1);
      }
      cb(null, initialized, templates);
    }
  );
}

// Exported functions
module.exports = {
  findExtensions: findExtensions,
  initExtensions: initExtensions,
  loadExtension: loadExtension,
};
<|endoftext|>


<commit_before>var request = require('request'),
    cheerio = require('cheerio'),
    Q = require('q');

var url = 'http://bitcamp15.devpost.com/submissions';

var numPages = function (hackathon) {
    var deferred = Q.defer();

    var url = 'http://' + hackathon + '.devpost.com/submissions/search?page=1';
    request(url, function (error, response, html) {
        if (!error) {
            var $ = cheerio.load(html);
            var pages = $( $('.next.next_page').prev() ).text();
            var pagesInt = parseInt(pages);
            if (Number.isInteger(pagesInt)) {
                deferred.resolve(pagesInt);
            }
            else {
                deferred.reject("Error: Not a number");
            }
        }
        else {
            deferred.reject("Error: Not a valid hackathon");
        }
    });

    return deferred.promise;
};

var hackathonPage = function (hackathon, page, filters) {
    var deferred = Q.defer();

    var url = 'http://' + hackathon + '.devpost.com/submissions/search?';
    if (page != undefined) {
        url += "page=" + page;
    }

    request(url, function (error, response, html) {
        var data = [];
        if (!error) {
            var $ = cheerio.load(html);
            $('.gallery-item').each(function (index, element) {
                var link = $( $(element).find('.link-to-software') ).attr('href');
                var image = $( $(element).find('figure > img') ).attr('src');
                var title = $( $(element).find('figcaption > div > h5') ).text().trim();
                var desc = $( $(element).find('figcaption > div > p') ).text().trim();
                var teamSize = $(element).find('.user-profile-link').length;
                data.push({
                    'url': link,
                    'imageUrl': image,
                    'title': title,
                    'description': desc,
                    'teamSize': teamSize
                });
            });

            deferred.resolve(data);
        }
        else {
            deferred.reject(error);
        }
    });

    return deferred.promise;
};

var hackathonProjectsAll = function (hackathon) {
    var deferred = Q.defer();

    // var baseUrl = 'http://' + hackathon + '.devpost.com/submissions/search?page=';
    numPages(hackathon)
    .then(
        function successCallback(numPages) {
            var promises = [];
            for (var i = 1; i <= numPages; i++) {
                promises.push(hackathonPage(hackathon, i));
            }
            Q.all(promises)
            .then(
                function successCallback(data) {
                    var output = [];
                    data.forEach(function (projects) {
                        output = output.concat(projects);
                    });
                    deferred.resolve(output);
                },
                function errorCallback(error) {
                    deferred.reject("ERROR");
                });
        },
        function errorCallback(error) {
            deferred.reject(error);
        });

    return deferred.promise;
};

var projectFindBySlug = function (projectSlug) {
    var deferred = Q.defer();

    var url = 'http://devpost.com/software/' + projectSlug;
    request(url, function (error, response, html) {
        if (!error) {
            var $ = cheerio.load(html);

            var titleObj = $('#app-title');
            var descriptionObj = $('#software-header').find('p');
            var detailsObj = $('#app-details-left > div:nth-of-type(2)');
            var builtWithObj = $('.cp-tag');
            var slidesObj = $('.software_photo_image');
            var teamMembersObj = $('.software-team-member');
            var hackathonObj = $('.software-list-with-thumbnail');

            var projectTitle = $(titleObj).text();
            var projectDescription = $(descriptionObj).text().trim();

            var projectDetails = [];
            $(detailsObj).children().each(function (index, element) {
                if (index % 2 == 0) {
                    projectDetails.push({heading: $(element).text(), text: ''});
                }
                else {
                    projectDetails[projectDetails.length - 1].text = $(element).text();
                }
            });

            var projectTags = [];
            $(builtWithObj).each(function (index, element) {
                projectTags.push($(element).text());
            });

            var projectImages = [];
            $(slidesObj).each(function (index, element) {
                projectImages.push($(element).attr('src'));
            });

            var projectMembers = [];
            $(teamMembersObj).each(function (index, element) {
                projectMembers.push({
                    avatarUrl: $(element).find('.software-member-photo').attr('src'),
                    name: $(element).find('.user-profile-link').text()
                });
            });

            var projectEvent = {};
            projectEvent.imageUrl = $(hackathonObj).find('.software-list-thumbnail > a > img').attr('src');
            projectEvent.name = $(hackathonObj).find('.software-list-content > p > a').text();
            projectEvent.serviceId = $(hackathonObj).find('.software-list-content > p > a').attr('href');

            var re = /https{0,1}:\/\/(.*)\.devpost\.com\//;
            projectEvent.serviceId = projectEvent.serviceId.match(re)[1];

            deferred.resolve({
                title: projectTitle,
                description: projectDescription,
                details: projectDetails,
                tags: projectTags,
                imageUrls: projectImages,
                members: projectMembers,
                event: projectEvent
            });

        }
        else {
            deferred.reject(error);
        }
    });

    return deferred.promise;
};

module.exports = {
    hackathon: {
        projects: {
            all: hackathonProjectsAll
        }
    },
    project: {
        findBySlug: projectFindBySlug
    },
    submissions: function (hackathon, page, filters) {
        var deferred = Q.defer();

        var url = 'http://' + hackathon + '.devpost.com/submissions/search?';
        if (page != undefined) {
            url += "page=" + page;
        }

        request(url, function (error, response, html) {
            var data = [];
            if (!error) {
                var $ = cheerio.load(html);
                $('.gallery-item').each(function (index, element) {
                    var link = $( $(element).find('.link-to-software') ).attr('href');
                    var image = $( $(element).find('figure > img') ).attr('src');
                    var title = $( $(element).find('figcaption > div > h5') ).text().trim();
                    var desc = $( $(element).find('figcaption > div > p') ).text().trim();
                    var teamSize = $(element).find('.user-profile-link').length;
                    data.push({
                        'url': link,
                        'imageUrl': image,
                        'title': title,
                        'description': desc,
                        'teamSize': teamSize
                    });
                });

                deferred.resolve(data);
            }
            else {
                deferred.reject(error);
            }
        });

        return deferred.promise;
    }
}<commit_msg>Hackathons are hard<commit_after>var request = require('request'),
    cheerio = require('cheerio'),
    Q = require('q');

var url = 'http://bitcamp15.devpost.com/submissions';

var numPages = function (hackathon) {
    var deferred = Q.defer();

    var url = 'http://' + hackathon + '.devpost.com/submissions/search?page=1';
    request(url, function (error, response, html) {
        if (!error) {
            var $ = cheerio.load(html);
            var pages = $( $('.next.next_page').prev() ).text();
            var pagesInt = parseInt(pages);
            if (Number.isInteger(pagesInt)) {
                deferred.resolve(pagesInt);
            }
            else {
                deferred.reject("Error: Not a number");
            }
        }
        else {
            deferred.reject("Error: Not a valid hackathon");
        }
    });

    return deferred.promise;
};

var hackathonPage = function (hackathon, page, filters) {
    var deferred = Q.defer();

    var url = 'http://' + hackathon + '.devpost.com/submissions/search?';
    if (page != undefined) {
        url += "page=" + page;
    }

    request(url, function (error, response, html) {
        var data = [];
        if (!error) {
            var $ = cheerio.load(html);
            $('.gallery-item').each(function (index, element) {
                var link = $( $(element).find('.link-to-software') ).attr('href');
                var image = $( $(element).find('figure > img') ).attr('src');
                var title = $( $(element).find('figcaption > div > h5') ).text().trim();
                var desc = $( $(element).find('figcaption > div > p') ).text().trim();
                var teamSize = $(element).find('.user-profile-link').length;
                var slug = $('.link-to-software').attr('href');

                var re = /^.*software\/()\/{0,1}$/;
                slug = slug.match(re)[1];
                data.push({
                    'url': link,
                    'imageUrl': image,
                    'title': title,
                    'description': desc,
                    'teamSize': teamSize,
                    'slug': slug
                });
            });

            deferred.resolve(data);
        }
        else {
            deferred.reject(error);
        }
    });

    return deferred.promise;
};

var hackathonProjectsAll = function (hackathon) {
    var deferred = Q.defer();

    // var baseUrl = 'http://' + hackathon + '.devpost.com/submissions/search?page=';
    numPages(hackathon)
    .then(
        function successCallback(numPages) {
            var promises = [];
            for (var i = 1; i <= numPages; i++) {
                promises.push(hackathonPage(hackathon, i));
            }
            Q.all(promises)
            .then(
                function successCallback(data) {
                    var output = [];
                    data.forEach(function (projects) {
                        output = output.concat(projects);
                    });
                    deferred.resolve(output);
                },
                function errorCallback(error) {
                    deferred.reject("ERROR");
                });
        },
        function errorCallback(error) {
            deferred.reject(error);
        });

    return deferred.promise;
};

var projectFindBySlug = function (projectSlug) {
    var deferred = Q.defer();

    var url = 'http://devpost.com/software/' + projectSlug;
    request(url, function (error, response, html) {
        if (!error) {
            var $ = cheerio.load(html);

            var titleObj = $('#app-title');
            var descriptionObj = $('#software-header').find('p');
            var detailsObj = $('#app-details-left > div:nth-of-type(2)');
            var builtWithObj = $('.cp-tag');
            var slidesObj = $('.software_photo_image');
            var teamMembersObj = $('.software-team-member');
            var hackathonObj = $('.software-list-with-thumbnail');

            var projectTitle = $(titleObj).text();
            var projectDescription = $(descriptionObj).text().trim();

            var projectDetails = [];
            $(detailsObj).children().each(function (index, element) {
                if (index % 2 == 0) {
                    projectDetails.push({heading: $(element).text(), text: ''});
                }
                else {
                    projectDetails[projectDetails.length - 1].text = $(element).text();
                }
            });

            var projectTags = [];
            $(builtWithObj).each(function (index, element) {
                projectTags.push($(element).text());
            });

            var projectImages = [];
            $(slidesObj).each(function (index, element) {
                projectImages.push($(element).attr('src'));
            });

            var projectMembers = [];
            $(teamMembersObj).each(function (index, element) {
                projectMembers.push({
                    avatarUrl: $(element).find('.software-member-photo').attr('src'),
                    name: $(element).find('.user-profile-link').text()
                });
            });

            var projectEvent = {};
            projectEvent.imageUrl = $(hackathonObj).find('.software-list-thumbnail > a > img').attr('src');
            projectEvent.name = $(hackathonObj).find('.software-list-content > p > a').text();
            projectEvent.serviceId = $(hackathonObj).find('.software-list-content > p > a').attr('href');

            var re = /https{0,1}:\/\/(.*)\.devpost\.com\//;
            projectEvent.serviceId = projectEvent.serviceId.match(re)[1];

            deferred.resolve({
                title: projectTitle,
                description: projectDescription,
                details: projectDetails,
                tags: projectTags,
                imageUrls: projectImages,
                members: projectMembers,
                event: projectEvent
            });

        }
        else {
            deferred.reject(error);
        }
    });

    return deferred.promise;
};

module.exports = {
    hackathon: {
        projects: {
            all: hackathonProjectsAll
        }
    },
    project: {
        findBySlug: projectFindBySlug
    },
    submissions: function (hackathon, page, filters) {
        var deferred = Q.defer();

        var url = 'http://' + hackathon + '.devpost.com/submissions/search?';
        if (page != undefined) {
            url += "page=" + page;
        }

        request(url, function (error, response, html) {
            var data = [];
            if (!error) {
                var $ = cheerio.load(html);
                $('.gallery-item').each(function (index, element) {
                    var link = $( $(element).find('.link-to-software') ).attr('href');
                    var image = $( $(element).find('figure > img') ).attr('src');
                    var title = $( $(element).find('figcaption > div > h5') ).text().trim();
                    var desc = $( $(element).find('figcaption > div > p') ).text().trim();
                    var teamSize = $(element).find('.user-profile-link').length;
                    data.push({
                        'url': link,
                        'imageUrl': image,
                        'title': title,
                        'description': desc,
                        'teamSize': teamSize
                    });
                });

                deferred.resolve(data);
            }
            else {
                deferred.reject(error);
            }
        });

        return deferred.promise;
    }
}<|endoftext|>


<commit_before>/**
 * Socioscapes is a javascript alternative to desktop geographic information systems and proprietary data visualization
 * platforms. The modular API fuses various free-to-use and open-source GIS libraries into an organized, modular, and
 * sandboxed environment.
 *
 *    Source code...................... http://github.com/moismailzai/socioscapes
 *    Reference implementation......... http://app.socioscapes.com
 *    License.......................... MIT license (free as in beer & speech)
 *    Copyright........................ Copies have no rights
 *
 * This software was written as partial fulfilment of the degree requirements for the Masters of Arts in Sociology at the
 * University of Toronto.
 */

var fetchGoogleAuth = require('./fetchers/fetchGoogleAuth.js'),
    fetchGoogleGeocode = require('./fetchers/fetchGoogleGeocode.js'),
    fetchGoogleBq = require('./fetchers/fetchGoogleBq.js'),
    fetchWfs = require('./fetchers/fetchWfs.js'),
    newLayer = require('./core/newLayer.js'),
    viewGmap = require('./views/viewGmap.js');

module.exports = function (pluginModule) {
    var s = {};

    Object.defineProperty(s, 'fetchGoogleAuth', {
        value: fetchGoogleAuth
    });
    Object.defineProperty(s, 'fetchGoogleGeocode', {
        value: fetchGoogleGeocode
    });
    Object.defineProperty(s, 'fetchGoogleBq', {
        value: fetchGoogleBq
    });
    Object.defineProperty(s, 'fetchWfs', {
        value: fetchWfs
    });
    Object.defineProperty(s, 'newLayer', {
        value: newLayer
    });
    Object.defineProperty(s, 'viewGmap', {
        value: viewGmap
    });
    if (pluginModule) {
        return pluginModule(s);
    }

    return s;
};<commit_msg>various jscode updates use strict mode<commit_after>'use strict';
/**
 * Socioscapes is a javascript alternative to desktop geographic information systems and proprietary data visualization
 * platforms. The modular API fuses various free-to-use and open-source GIS libraries into an organized, modular, and
 * extendable sandbox.
 *
 *    Source code...................... http://github.com/moismailzai/socioscapes
 *    Reference implementation......... http://app.socioscapes.com
 *    License.......................... MIT license (free as in beer & speech)
 *    Copyright........................
 *
 * This software was written as partial fulfilment of the degree requirements for the Masters of Arts in Sociology at the
 * University of Toronto.
 */
var fetchGoogleAuth = require('./fetchers/fetchGoogleAuth.js'),
    fetchGoogleGeocode = require('./fetchers/fetchGoogleGeocode.js'),
    fetchGoogleBq = require('./fetchers/fetchGoogleBq.js'),
    fetchWfs = require('./fetchers/fetchWfs.js'),
    newLayer = require('./core/newLayer.js'),
    viewGmap = require('./views/viewGmap.js');

/**
 * This is the root Socioscapes namespace and object.
 *
 * Requires the modules {@link module:fetchGoogleAuth}, {@link module:fetchGoogleGeocode},
 * {@link module:fetchGoogleBq}, {@link module:fetchWfs}, {@link module:newLayer}, and {@link module:viewGmap}.
 *
 * @namespace Socioscapes
 * @requires module:fetchGoogleAuth
 * @requires module:fetchGoogleGeocode
 * @requires module:fetchGoogleBq
 * @requires module:fetchWfs
 * @requires module:newLayer
 * @requires module:viewGmap
 */
module.exports = function () {
    Object.defineProperty(this, 'fetchGoogleAuth', {
        value: fetchGoogleAuth
    });
    Object.defineProperty(this, 'fetchGoogleGeocode', {
        value: fetchGoogleGeocode
    });
    Object.defineProperty(this, 'fetchGoogleBq', {
        value: fetchGoogleBq
    });
    Object.defineProperty(this, 'fetchWfs', {
        value: fetchWfs
    });
    Object.defineProperty(this, 'newLayer', {
        value: newLayer
    });
    Object.defineProperty(this, 'viewGmap', {
        value: viewGmap
    });
};<|endoftext|>


<commit_before>/*
 * 流域編號=1580(八掌溪流域)、1590(急水溪流域)、1600(將軍溪流域)、1630(曾文溪流域)、1650(鹽水溪流域)、1660(二仁溪流域)
 */
var map, info, bounds, points, markers = [], markersBase = [];
var rivers = ['1580', '1590', '1600', '1630', '1650', '1660'];
function initialize() {
    map = new google.maps.Map(document.getElementById('map-canvas'), {
        zoom: 12,
        center: {lat: 22.672925, lng: 120.309465}
    });
    info = new google.maps.InfoWindow();
    bounds = new google.maps.LatLngBounds();

    $.getJSON('points.json', {}, function (r) {
        points = r;
        for (k in rivers) {
            $.getJSON('http://i.tainan.gov.tw/TainanLocalWst.php?basin=' + rivers[k], {}, function (i) {
                for (g in i.local_wst_warn_info) {
                    var key = i.local_wst_warn_info[g].st_no;
                    if (!points[key]) {
                        console.log(key);
                        continue;
                    }
                    points[key].alert_level = i.local_wst_warn_info[g].alert_level;
                    points[key].change = i.local_wst_warn_info[g].change;
                    points[key].date = i.local_wst_warn_info[g].date;
                    points[key].info = i.local_wst_warn_info[g].info;
                    points[key].warn_info = i.local_wst_warn_info[g].warn_info;
                    var geoPoint = (new google.maps.LatLng(points[key].latitude, points[key].longitude));

                    if ('未達警戒' === points[key].alert_level) {
                        var marker = new google.maps.Marker({
                            position: geoPoint,
                            map: map,
                            icon: 'http://maps.google.com/mapfiles/ms/icons/green-dot.png',
                            title: points[key].name
                        });
                    } else {
                        var marker = new google.maps.Marker({
                            position: geoPoint,
                            map: map,
                            icon: 'http://maps.google.com/mapfiles/ms/icons/red-dot.png',
                            title: points[key].name
                        });
                    }

                    marker.data = points[key];
                    marker.addListener('click', function () {
                        console.log(this.data);
                        var infoText = '' + this.data.name + '';
                        infoText += '
站碼: ' + this.data.code;
                        infoText += '
河川分區: ' + this.data.type;
                        info.setContent(infoText);
                        info.open(map, this);

                        infoText += '
行政區: ' + this.data.area;
                        infoText += '
轄管單位: ' + this.data.admin;
                        infoText += '
河川排水: ' + this.data.river;
                        infoText += '
警戒狀態: ' + this.data.alert_level;
                        infoText += '
說明: ' + this.data.warn_info;
                        infoText += '
時間: ' + this.data.date;
                        if (this.data.image !== '') {
                            infoText += '
';
                        }

                        map.setZoom(15);
                        map.setCenter(this.getPosition());
                        $('#pointContent').html(infoText);
                    });
                    markers.push(marker);
                    markersBase.push(marker);
                    bounds.extend(geoPoint);
                }
            });
        }
        setTimeout(function () {
            map.fitBounds(bounds);
        }, 2000);
    });

    $('a.bounds-reset').click(function () {
        map.fitBounds(bounds);
        showPoints();
        return false;
    });

    $('a.bounds-image').click(function () {
        map.fitBounds(bounds);
        showImagePoints();
        return false;
    });

}

function showPoints() {
    for (k in markers) {
        markers[k].setMap(null);
    }
    markers = [];
    for (k in markersBase) {
        markersBase[k].setMap(map);
        markers.push(markersBase[k]);
    }
}

function showImagePoints() {
    for (k in markers) {
        markers[k].setMap(null);
    }
    markers = [];
    for (k in markersBase) {
        if (markersBase[k].data.image != '') {
            markersBase[k].setMap(map);
            markers.push(markersBase[k]);
        }
    }
}

google.maps.event.addDomListener(window, 'load', initialize);<commit_msg>remove testing log<commit_after>/*
 * 流域編號=1580(八掌溪流域)、1590(急水溪流域)、1600(將軍溪流域)、1630(曾文溪流域)、1650(鹽水溪流域)、1660(二仁溪流域)
 */
var map, info, bounds, points, markers = [], markersBase = [];
var rivers = ['1580', '1590', '1600', '1630', '1650', '1660'];
function initialize() {
    map = new google.maps.Map(document.getElementById('map-canvas'), {
        zoom: 12,
        center: {lat: 22.672925, lng: 120.309465}
    });
    info = new google.maps.InfoWindow();
    bounds = new google.maps.LatLngBounds();

    $.getJSON('points.json', {}, function (r) {
        points = r;
        for (k in rivers) {
            $.getJSON('http://i.tainan.gov.tw/TainanLocalWst.php?basin=' + rivers[k], {}, function (i) {
                for (g in i.local_wst_warn_info) {
                    var key = i.local_wst_warn_info[g].st_no;
                    if (!points[key]) {
                        console.log(key);
                        continue;
                    }
                    points[key].alert_level = i.local_wst_warn_info[g].alert_level;
                    points[key].change = i.local_wst_warn_info[g].change;
                    points[key].date = i.local_wst_warn_info[g].date;
                    points[key].info = i.local_wst_warn_info[g].info;
                    points[key].warn_info = i.local_wst_warn_info[g].warn_info;
                    var geoPoint = (new google.maps.LatLng(points[key].latitude, points[key].longitude));

                    if ('未達警戒' === points[key].alert_level) {
                        var marker = new google.maps.Marker({
                            position: geoPoint,
                            map: map,
                            icon: 'http://maps.google.com/mapfiles/ms/icons/green-dot.png',
                            title: points[key].name
                        });
                    } else {
                        var marker = new google.maps.Marker({
                            position: geoPoint,
                            map: map,
                            icon: 'http://maps.google.com/mapfiles/ms/icons/red-dot.png',
                            title: points[key].name
                        });
                    }

                    marker.data = points[key];
                    marker.addListener('click', function () {
                        var infoText = '' + this.data.name + '';
                        infoText += '
站碼: ' + this.data.code;
                        infoText += '
河川分區: ' + this.data.type;
                        info.setContent(infoText);
                        info.open(map, this);

                        infoText += '
行政區: ' + this.data.area;
                        infoText += '
轄管單位: ' + this.data.admin;
                        infoText += '
河川排水: ' + this.data.river;
                        infoText += '
警戒狀態: ' + this.data.alert_level;
                        infoText += '
說明: ' + this.data.warn_info;
                        infoText += '
時間: ' + this.data.date;
                        if (this.data.image !== '') {
                            infoText += '
';
                        }

                        map.setZoom(15);
                        map.setCenter(this.getPosition());
                        $('#pointContent').html(infoText);
                    });
                    markers.push(marker);
                    markersBase.push(marker);
                    bounds.extend(geoPoint);
                }
            });
        }
        setTimeout(function () {
            map.fitBounds(bounds);
        }, 2000);
    });

    $('a.bounds-reset').click(function () {
        map.fitBounds(bounds);
        showPoints();
        return false;
    });

    $('a.bounds-image').click(function () {
        map.fitBounds(bounds);
        showImagePoints();
        return false;
    });

}

function showPoints() {
    for (k in markers) {
        markers[k].setMap(null);
    }
    markers = [];
    for (k in markersBase) {
        markersBase[k].setMap(map);
        markers.push(markersBase[k]);
    }
}

function showImagePoints() {
    for (k in markers) {
        markers[k].setMap(null);
    }
    markers = [];
    for (k in markersBase) {
        if (markersBase[k].data.image != '') {
            markersBase[k].setMap(map);
            markers.push(markersBase[k]);
        }
    }
}

google.maps.event.addDomListener(window, 'load', initialize);<|endoftext|>


<commit_before>var DropDownMenu = React.createClass({
  getInitialState: function() {
    return {
      selectedEvents: {}
    };
  },

  _getRSVP: function(event) {
    event.preventDefault();
  },

  _handleChange: function(i) {
    var id = this.props.eventIds[i];
    var selected = this.state.selectedEvents;

    if (id in selected) {
      selected[id] = (selected[id]) ? false: true;
    } else {
      selected[id] = true;
    }

    this.setState({
      selectedEvents: selected
    });
  },
  render: function() {
    var itemNodes = this.props.eventTitles.map( (title, i) => {
      return (

        <input type="checkbox" key={i} onChange={this._handleChange.bind(this, i)} />
         { title }

      );
    });

    return(

Basic Example

              {itemNodes}

      <button onClick={this._getRSVP}>RSVP</button>

    )
  }
});

var AppHandler = React.createClass({
  getInitialState: function() {
    return {
      userId: '',
      eventTitles: [],
      eventIds: [],
      rawJson: []
    };
  },

  componentWillMount: function() {
    // $.getJSON('https://api.tnyu.org/v2/people/me')
    //   .done( function(user) {
    //     console.log(user.data);
    //   });

    $.getJSON('https://api.tnyu.org/v2/events/next-10-publicly')
    .done( (json) => {
      var eventIds = json.data.map(function(event) { return event.id; });
      var eventTitles = json.data.map(function(event) { return event.attributes.title; });
      this.setState({
        eventTitles: eventTitles,
        eventIds: eventIds,
        rawJson: json.data
      });
    });
  },

  render: function() {
    return (

      <DropDownMenu eventTitles={this.state.eventTitles} eventIds={this.state.eventIds} rawJson={this.state.rawJson}/>

    );
  }
});

React.render(<AppHandler />, document.getElementById('app'));
<commit_msg>add date and time on ui<commit_after>var DropDownMenu = React.createClass({
  getInitialState: function() {
    return {
      selectedEvents: {}
    };
  },

  _getRSVP: function(event) {
    event.preventDefault();
    this.props.eventIds.map(function(id, i) {
      $.ajax({
        type: "POST",
        url: "https://api.tnyu.org/v2/events/" + id + "/check-in",
        async: false,
        success: function(data) { console.log(data); },
        error: function(err) { console.log(err); }
      });

    });
  },

  _handleChange: function(i) {
    var id = this.props.eventIds[i];
    var selected = this.state.selectedEvents;

    if (id in selected) {
      // toggle checkbox
      selected[id] = (selected[id]) ? false: true;
    } else {
      selected[id] = true;
    }
    this.setState({
      selectedEvents: selected
    });
  },

  render: function() {
    var itemNodes = this.props.eventTitles.map( (title, i) => {
      var date = this.props.eventStartDates[i].substring(0, 10);
      var time = this.props.eventStartDates[i].substring(11, 16);
      var det = parseInt(time.substring(0, 2));
      var timeStr = (det < 12) ? "AM": "PM";

      return (

        <input className="col-md-1" type="checkbox" key={i} onChange={this._handleChange.bind(this, i)} />
             { title }
            { date }
            { time } { timeStr }

      );
    });

    return(

Tech@NYU: RSVP for Events

          {itemNodes}

      <button onClick={this._getRSVP}>RSVP</button>

    )
  }
});

var AppHandler = React.createClass({
  getInitialState: function() {
    return {
      userId: '',
      eventTitles: [],
      eventIds: [],
      eventStartDates: [],
      rawJson: []
    };
  },

  componentWillMount: function() {
    $.getJSON('https://api.tnyu.org/v2/people/me')
      .done( (user) => {
        this.setState({
          userId: user.data.id
        });

        $.getJSON('https://api.tnyu.org/v2/events/next-10-publicly')
        .done( (json) => {

          var eventIds = json.data.map(function(event) { return event.id; });
          var eventTitles = json.data.map(function(event) { return event.attributes.title; });
          var eventStartDates = json.data.map(function(event) { return event.attributes.startDateTime; });

          this.setState({
            eventTitles: eventTitles,
            eventIds: eventIds,
            eventStartDates: eventStartDates,
            rawJson: json.data
          });
        });
      })
      .fail((err) => {
        // redirect to login
        console.log(err);
      });

  },

  render: function() {
    return (

      <DropDownMenu eventTitles={this.state.eventTitles} eventIds={this.state.eventIds} eventStartDates={this.state.eventStartDates} rawJson={this.state.rawJson}/>

    );
  }
});

React.render(<AppHandler />, document.getElementById('app'));
<|endoftext|>


<commit_before>// Created by Corey Birnbaum (coreybirnbaum.com), released under MIT license.
// Credit for the hex stuff: https://gist.github.com/zackthehuman/1867663
// Credit for randomColor: https://github.com/davidmerfield/randomColor
;(function(root, factory) {
	// Support CommonJS
	if (typeof exports === 'object') {
	var randomAvatar = factory();

	// Support NodeJS & Component, which allow module.exports to be a function
	if (typeof module === 'object' && module && module.exports) {
		exports = module.exports = randomAvatar;
	}

	// Support CommonJS 1.1.1 spec
	exports.randomAvatar = randomAvatar;

	// Support AMD
	} else if (typeof define === 'function' && define.amd) {
	define([], factory);

	// Support vanilla script loading
	} else {
		root.randomAvatar = factory();
	}
}(this, function() {

	var canvas;
	var ctx;
	var bgColor;
	var fontSize;
	var opts;

	function randomAvatar(options) {
		if (!options) options = {}
		opts = {
			size: options.size || 128,
			style: options.style || 'random',
			text: options.text || randomText(),
			contrast: options.contrast || 25,
			luminosity: options.luminosity || 'bright'
		}

		if (!canvas) {
			canvas = document.createElement('canvas')
			canvas.width = opts.size
			canvas.height = opts.size
			ctx = canvas.getContext('2d')
		}

		fontSize = opts.size / 2;
		bgColor = randomColor({format: 'hslArray', luminosity: opts.luminosity})

		ctx.fillStyle = getHSLStyle(bgColor)
		ctx.fillRect(0, 0, opts.size, opts.size)
		ctx.font = fontSize+'px sans-serif'
		ctx.textAlign = 'center'

		var style;
		switch (opts.style) {
			case 'circle':
				style = 0
				break;
			case 'hex':
				style = 1
				break;
			case 'square':
				style = 2
				break;
			default:
				style = Math.floor(Math.random() * 3)
				break;
		}

		switch (style) {
			case 0:
				drawCircleBoard(4, 5, Math.floor(opts.size / 5))
				break;
			case 1:
				drawHexBoard(4, 5, Math.floor(opts.size / 5))
				break;
			case 2:
				drawSquareBoard(4, 5, Math.floor(opts.size / 5))
				break;
		}

		drawText(opts.text)

		var image = new Image();
		image.src = canvas.toDataURL('image/png');
		return image;
	}

	function drawCircleBoard(width, height, sideLength) {
		var i, j, x, y;
		var baseH = bgColor[0]
		var baseS = bgColor[1]
		var baseL = bgColor[2]
		var newHSL = [baseH, baseS, baseL]
		var pixelVariance = opts.size / 13
		// console.log(bgColor)

		var hexagonAngle = 0.523598776; // 30 degrees in radians
		var hexHeight = Math.sin(hexagonAngle) * sideLength;
		var hexRadius = Math.cos(hexagonAngle) * sideLength;
		var hexRectangleHeight = sideLength + 2 * hexHeight;
		var hexRectangleWidth = 2 * hexRadius;
		var offset = getRandomSizeVariance(sideLength * 1.3, 0)

		for (i = 0; i < width; ++i) {
			for (j = 0; j < height; ++j) {
				x = i * hexRectangleWidth + ((j % 2) * hexRadius) - offset
				y = j * (sideLength + hexHeight) - offset
				ctx.beginPath();
				ctx.arc(x + sideLength, y + sideLength, sideLength + getRandomSizeVariance(pixelVariance, 0.9), 0, Math.PI * 2);
				newHSL[0] = getRandomColorVariant(baseH, 360)
				newHSL[1] = getRandomColorVariant(baseS, 100)
				newHSL[2] = getRandomColorVariant(baseL, 100)
				ctx.fillStyle = getHSLStyle(newHSL)
				ctx.fill();
			}
		}
	}

	function drawHexBoard(width, height, sideLength) {
		var i, j, x, y;
		var baseH = bgColor[0]
		var baseS = bgColor[1]
		var baseL = bgColor[2]
		var newHSL = [baseH, baseS, baseL]
		var pixelVariance = opts.size / 13
		// console.log(bgColor)

		var hexagonAngle = 0.523598776; // 30 degrees in radians
		var offset = getRandomSizeVariance(sideLength * 1.3, 0)
		var hexHeight = Math.sin(hexagonAngle) * sideLength;
		var hexRadius = Math.cos(hexagonAngle) * sideLength;
		var hexRectangleHeight = sideLength + 2 * hexHeight;
		var hexRectangleWidth = 2 * hexRadius;

		for (i = 0; i < width; ++i) {
			for (j = 0; j < height; ++j) {
				x = i * hexRectangleWidth + ((j % 2) * hexRadius) - offset + getRandomSizeVariance(pixelVariance, 0.5)
				y = j * (sideLength + hexHeight) - offset + getRandomSizeVariance(pixelVariance, 0.5)
				ctx.beginPath()
				ctx.moveTo(x + hexRadius, y)
				ctx.lineTo(x + hexRectangleWidth, y + hexHeight)
				ctx.lineTo(x + hexRectangleWidth, y + hexHeight + sideLength)
				ctx.lineTo(x + hexRadius, y + hexRectangleHeight)
				ctx.lineTo(x, y + sideLength + hexHeight)
				ctx.lineTo(x, y + hexHeight)
				ctx.closePath()
				newHSL[0] = getRandomColorVariant(baseH, 360)
				newHSL[1] = getRandomColorVariant(baseS, 100)
				newHSL[2] = getRandomColorVariant(baseL, 100)
				ctx.fillStyle = getHSLStyle(newHSL)
				ctx.fill()
			}
		}
	}

	function drawSquareBoard(width, height, sideLength) {
		var i, j, x, y;
		var baseH = bgColor[0]
		var baseS = bgColor[1]
		var baseL = bgColor[2]
		var newHSL = [baseH, baseS, baseL]
		var pixelVariance = opts.size / 13
		// console.log(bgColor)

		sideLength *= 1.75
		// var shiftValue = sideLength * 0.25
		var offset = getRandomSizeVariance(sideLength * 1.3, 0)

		for (i = 0; i < width; ++i) {

			for (j = 0; j < height; ++j) {
				x = i * sideLength - offset// + shiftValue
				y = j * sideLength - offset
				// shiftValue *= -1
				newHSL[0] = getRandomColorVariant(baseH, 360)
				newHSL[1] = getRandomColorVariant(baseS, 100)
				newHSL[2] = getRandomColorVariant(baseL, 100)
				ctx.fillStyle = getHSLStyle(newHSL)
				ctx.fillRect(x, y, sideLength + getRandomSizeVariance(pixelVariance, 0.9), sideLength + getRandomSizeVariance(pixelVariance, 0.9))
			}
		}
	}

	function drawText(txt) {
		ctx.fillStyle = getContractColor(bgColor)
		ctx.fillText(txt, opts.size/2, (opts.size/2) + (fontSize/3))
	}

	// CREDIT: https://24ways.org/2010/calculating-color-contrast/
	function getContractColor(hsl) {
		var h = hsl[0] / 360 // has to be normalized for hslToRgb()
		var s = hsl[1] / 100
		var l = hsl[2] / 100
		var rgb = hslToRgb(h, s, l)
		var yiq = ((rgb[0]*299) + (rgb[1]*587) + (rgb[2]*114)) / 1000
		return (yiq >= 128) ? '#222' : '#fff'
	}

	// CREDIT: https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
	function hslToRgb(h, s, l) {
		var r, g, b;
		if (s == 0) {
			r = g = b = l; // achromatic
		}
		else {
			function hue2rgb(p, q, t){
				if (t < 0) t += 1;
				if (t > 1) t -= 1;
				if (t < 1/6) return p + (q - p) * 6 * t;
				if (t < 1/2) return q;
				if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
				return p;
			}

			var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
			var p = 2 * l - q;
			r = hue2rgb(p, q, h + 0.33333333333);
			g = hue2rgb(p, q, h);
			b = hue2rgb(p, q, h - 0.33333333333);
		}

		return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
	}

	function getHSLStyle(hsl) {
		return 'hsl('+hsl[0]+', '+hsl[1]+'%, '+hsl[2]+'%)';
	}

	function getRandomColorVariant(v, m) {
		return clamp(v + getRandomSizeVariance(opts.contrast, 0.5), 0, m)
	}

	function getRandomSizeVariance(b, v) {
		return (Math.random() * b) - (b * v)
	}

	function randomText() {
		return 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.charAt(Math.floor(Math.random() * 26))
	}

	function clamp(v, min, max) {
		return Math.min(Math.max(v, min), max)
	}

	return randomAvatar;
}));
<commit_msg>allow empty text<commit_after>// Created by Corey Birnbaum (coreybirnbaum.com), released under MIT license.
// Credit for the hex stuff: https://gist.github.com/zackthehuman/1867663
// Credit for randomColor: https://github.com/davidmerfield/randomColor
;(function(root, factory) {
	// Support CommonJS
	if (typeof exports === 'object') {
	var randomAvatar = factory();

	// Support NodeJS & Component, which allow module.exports to be a function
	if (typeof module === 'object' && module && module.exports) {
		exports = module.exports = randomAvatar;
	}

	// Support CommonJS 1.1.1 spec
	exports.randomAvatar = randomAvatar;

	// Support AMD
	} else if (typeof define === 'function' && define.amd) {
	define([], factory);

	// Support vanilla script loading
	} else {
		root.randomAvatar = factory();
	}
}(this, function() {

	var canvas;
	var ctx;
	var bgColor;
	var fontSize;
	var opts;

	function randomAvatar(options) {
		if (!options) options = {}
		opts = {
			size: options.size || 128,
			style: options.style || 'random',
			text: typeof options.text === 'undefined' ? randomText() : options.text,
			contrast: options.contrast || 25,
			luminosity: options.luminosity || 'bright'
		}

		if (!canvas) {
			canvas = document.createElement('canvas')
			canvas.width = opts.size
			canvas.height = opts.size
			ctx = canvas.getContext('2d')
		}

		fontSize = opts.size / 2;
		bgColor = randomColor({format: 'hslArray', luminosity: opts.luminosity})

		ctx.fillStyle = getHSLStyle(bgColor)
		ctx.fillRect(0, 0, opts.size, opts.size)
		ctx.font = fontSize+'px sans-serif'
		ctx.textAlign = 'center'

		var style;
		switch (opts.style) {
			case 'circle':
				style = 0
				break;
			case 'hex':
				style = 1
				break;
			case 'square':
				style = 2
				break;
			default:
				style = Math.floor(Math.random() * 3)
				break;
		}

		switch (style) {
			case 0:
				drawCircleBoard(4, 5, Math.floor(opts.size / 5))
				break;
			case 1:
				drawHexBoard(4, 5, Math.floor(opts.size / 5))
				break;
			case 2:
				drawSquareBoard(4, 5, Math.floor(opts.size / 5))
				break;
		}

		drawText(opts.text)

		var image = new Image();
		image.src = canvas.toDataURL('image/png');
		return image;
	}

	function drawCircleBoard(width, height, sideLength) {
		var i, j, x, y;
		var baseH = bgColor[0]
		var baseS = bgColor[1]
		var baseL = bgColor[2]
		var newHSL = [baseH, baseS, baseL]
		var pixelVariance = opts.size / 13
		// console.log(bgColor)

		var hexagonAngle = 0.523598776; // 30 degrees in radians
		var hexHeight = Math.sin(hexagonAngle) * sideLength;
		var hexRadius = Math.cos(hexagonAngle) * sideLength;
		var hexRectangleHeight = sideLength + 2 * hexHeight;
		var hexRectangleWidth = 2 * hexRadius;
		var offset = getRandomSizeVariance(sideLength * 1.3, 0)

		for (i = 0; i < width; ++i) {
			for (j = 0; j < height; ++j) {
				x = i * hexRectangleWidth + ((j % 2) * hexRadius) - offset
				y = j * (sideLength + hexHeight) - offset
				ctx.beginPath();
				ctx.arc(x + sideLength, y + sideLength, sideLength + getRandomSizeVariance(pixelVariance, 0.9), 0, Math.PI * 2);
				newHSL[0] = getRandomColorVariant(baseH, 360)
				newHSL[1] = getRandomColorVariant(baseS, 100)
				newHSL[2] = getRandomColorVariant(baseL, 100)
				ctx.fillStyle = getHSLStyle(newHSL)
				ctx.fill();
			}
		}
	}

	function drawHexBoard(width, height, sideLength) {
		var i, j, x, y;
		var baseH = bgColor[0]
		var baseS = bgColor[1]
		var baseL = bgColor[2]
		var newHSL = [baseH, baseS, baseL]
		var pixelVariance = opts.size / 13
		// console.log(bgColor)

		var hexagonAngle = 0.523598776; // 30 degrees in radians
		var offset = getRandomSizeVariance(sideLength * 1.3, 0)
		var hexHeight = Math.sin(hexagonAngle) * sideLength;
		var hexRadius = Math.cos(hexagonAngle) * sideLength;
		var hexRectangleHeight = sideLength + 2 * hexHeight;
		var hexRectangleWidth = 2 * hexRadius;

		for (i = 0; i < width; ++i) {
			for (j = 0; j < height; ++j) {
				x = i * hexRectangleWidth + ((j % 2) * hexRadius) - offset + getRandomSizeVariance(pixelVariance, 0.5)
				y = j * (sideLength + hexHeight) - offset + getRandomSizeVariance(pixelVariance, 0.5)
				ctx.beginPath()
				ctx.moveTo(x + hexRadius, y)
				ctx.lineTo(x + hexRectangleWidth, y + hexHeight)
				ctx.lineTo(x + hexRectangleWidth, y + hexHeight + sideLength)
				ctx.lineTo(x + hexRadius, y + hexRectangleHeight)
				ctx.lineTo(x, y + sideLength + hexHeight)
				ctx.lineTo(x, y + hexHeight)
				ctx.closePath()
				newHSL[0] = getRandomColorVariant(baseH, 360)
				newHSL[1] = getRandomColorVariant(baseS, 100)
				newHSL[2] = getRandomColorVariant(baseL, 100)
				ctx.fillStyle = getHSLStyle(newHSL)
				ctx.fill()
			}
		}
	}

	function drawSquareBoard(width, height, sideLength) {
		var i, j, x, y;
		var baseH = bgColor[0]
		var baseS = bgColor[1]
		var baseL = bgColor[2]
		var newHSL = [baseH, baseS, baseL]
		var pixelVariance = opts.size / 13
		// console.log(bgColor)

		sideLength *= 1.75
		// var shiftValue = sideLength * 0.25
		var offset = getRandomSizeVariance(sideLength * 1.3, 0)

		for (i = 0; i < width; ++i) {

			for (j = 0; j < height; ++j) {
				x = i * sideLength - offset// + shiftValue
				y = j * sideLength - offset
				// shiftValue *= -1
				newHSL[0] = getRandomColorVariant(baseH, 360)
				newHSL[1] = getRandomColorVariant(baseS, 100)
				newHSL[2] = getRandomColorVariant(baseL, 100)
				ctx.fillStyle = getHSLStyle(newHSL)
				ctx.fillRect(x, y, sideLength + getRandomSizeVariance(pixelVariance, 0.9), sideLength + getRandomSizeVariance(pixelVariance, 0.9))
			}
		}
	}

	function drawText(txt) {
		ctx.fillStyle = getContractColor(bgColor)
		ctx.fillText(txt, opts.size/2, (opts.size/2) + (fontSize/3))
	}

	// CREDIT: https://24ways.org/2010/calculating-color-contrast/
	function getContractColor(hsl) {
		var h = hsl[0] / 360 // has to be normalized for hslToRgb()
		var s = hsl[1] / 100
		var l = hsl[2] / 100
		var rgb = hslToRgb(h, s, l)
		var yiq = ((rgb[0]*299) + (rgb[1]*587) + (rgb[2]*114)) / 1000
		return (yiq >= 128) ? '#222' : '#fff'
	}

	// CREDIT: https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
	function hslToRgb(h, s, l) {
		var r, g, b;
		if (s == 0) {
			r = g = b = l; // achromatic
		}
		else {
			function hue2rgb(p, q, t){
				if (t < 0) t += 1;
				if (t > 1) t -= 1;
				if (t < 1/6) return p + (q - p) * 6 * t;
				if (t < 1/2) return q;
				if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
				return p;
			}

			var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
			var p = 2 * l - q;
			r = hue2rgb(p, q, h + 0.33333333333);
			g = hue2rgb(p, q, h);
			b = hue2rgb(p, q, h - 0.33333333333);
		}

		return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
	}

	function getHSLStyle(hsl) {
		return 'hsl('+hsl[0]+', '+hsl[1]+'%, '+hsl[2]+'%)';
	}

	function getRandomColorVariant(v, m) {
		return clamp(v + getRandomSizeVariance(opts.contrast, 0.5), 0, m)
	}

	function getRandomSizeVariance(b, v) {
		return (Math.random() * b) - (b * v)
	}

	function randomText() {
		return 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.charAt(Math.floor(Math.random() * 26))
	}

	function clamp(v, min, max) {
		return Math.min(Math.max(v, min), max)
	}

	return randomAvatar;
}));
<|endoftext|>


<commit_before>var width = 500;
var height = 500;
var canvas = document.getElementById('asteroids');
canvas.width = width;
canvas.height = height;
var context = canvas.getContext('2d');

var rectWidth = width/5;
var rectHeight = height/5;

var x = 0;
var y = 0;
var rotationDegrees = 0;

var movementRate = 0.1;
var rotationRate = 0.1;

function draw(){
	// call clearRect with the entire size of the canvas to clear the whole thing

	// Fill the whole canvas with a black rectangle
	context.fillStyle = "rgb(0, 0, 0)";
	context.fillRect(0, 0, width, height);

	drawTriangle(context, x, y, rectWidth, rectHeight, rotationDegrees);

	// Update x and y for the next draw operation
	y = y + movementRate;
	// x = x + movementRate;
	rotationDegrees = rotationDegrees + rotationRate;

	if (rotationDegrees > 360){
		rotationDegrees = 0;
	}

	window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);

function drawTriangle(context, x, y, rectWidth, rectHeight, rotationDegrees){
	context.save();

	var centerX = x + rectWidth/2;
	var centerY = y + rectHeight/2;

	context.translate(centerX, centerY); // Translate to center of rectangle
	console.log('context.translate(centerX, centerY)', centerX, centerY);

	context.strokeStyle = 'white';
	context.strokeRect(0, 0, width, height);

	// Convert degrees to radians, because context.rotate needs radians
	var radians = rotationDegrees * (Math.PI/180);
	context.rotate(radians);
	console.log('rotationDegrees', rotationDegrees);
	console.log('context.rotate(radians)', radians);

	context.strokeStyle = 'yellow';
	context.strokeRect(0, 0, width, height);

	// Draw a triangle with paths
	context.strokeStyle = 'red';
	// Start a new path
	context.beginPath();

	// Now define the path with .moveTo() and .lineTo() methods
	var triangleOriginX = -rectWidth/2;
	var triangleOriginY = -rectHeight/2;

	context.moveTo(triangleOriginX, triangleOriginY);
	context.lineTo(triangleOriginX + rectWidth, triangleOriginY);
	context.lineTo(triangleOriginX + rectWidth/2, triangleOriginY + rectHeight);

	context.closePath();

	// The path is only made visible when we call .stroke()
	context.stroke();

	context.restore();
}<commit_msg>listening for up/down/left/right keys<commit_after>var width = 500;
var height = 500;
var canvas = document.getElementById('asteroids');
canvas.width = width;
canvas.height = height;
var context = canvas.getContext('2d');

var rectWidth = width/5;
var rectHeight = height/5;

var x = 0;
var y = 0;
var rotationDegrees = 0;

var movementRate = .5;
var rotationRate = .5;

function draw(){
	// call clearRect with the entire size of the canvas to clear the whole thing

	// Fill the whole canvas with a black rectangle
	context.fillStyle = "rgb(0, 0, 0)";
	context.fillRect(0, 0, width, height);

	drawTriangle(context, x, y, rectWidth, rectHeight, rotationDegrees);

	// Update x and y for the next draw operation
	y = y + movementRate;
	// x = x + movementRate;
	rotationDegrees = rotationDegrees + rotationRate;

	if (rotationDegrees > 360){
		rotationDegrees = 0;
	}

	window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);

window.addEventListener('keydown', function(event) {
	console.log('keydown event.which', event.which);

	switch(event.which){
		case 37:
		console.log('left');
		break;
		case 38:
		console.log('up');
		break;
		case 39:
		console.log('right');
		break;
		case 40:
		console.log('down');
		break;
		default:
	}
});

function drawTriangle(context, x, y, rectWidth, rectHeight, rotationDegrees){
	context.save();

	var centerX = x + rectWidth/2;
	var centerY = y + rectHeight/2;

	context.translate(centerX, centerY); // Translate to center of rectangle
	// console.log('context.translate(centerX, centerY)', centerX, centerY);

	// context.strokeStyle = 'white';
	// context.strokeRect(0, 0, width, height);

	// Convert degrees to radians, because context.rotate needs radians
	var radians = rotationDegrees * (Math.PI/180);
	context.rotate(radians);
	// console.log('rotationDegrees', rotationDegrees);
	// console.log('context.rotate(radians)', radians);

	// context.strokeStyle = 'yellow';
	// context.strokeRect(0, 0, width, height);

	// Draw a triangle with paths
	context.strokeStyle = 'red';
	// Start a new path
	context.beginPath();

	// Now define the path with .moveTo() and .lineTo() methods
	var triangleOriginX = -rectWidth/2;
	var triangleOriginY = -rectHeight/2;

	context.moveTo(triangleOriginX, triangleOriginY);
	context.lineTo(triangleOriginX + rectWidth, triangleOriginY);
	context.lineTo(triangleOriginX + rectWidth/2, triangleOriginY + rectHeight);

	context.closePath();

	// The path is only made visible when we call .stroke()
	context.stroke();

	context.restore();
}<|endoftext|>


<commit_before>var app = require('app')
var BrowserWindow = require('browser-window')
var crashReporter = require('crash-reporter')
var Menu = require('menu')
var ipc = require('ipc')
var dialog = require('dialog')
var fs = require('fs')
var path = require('path')

var darwinTemplate = require('./menus/darwin-menu.js')
var otherTemplate = require('./menus/other-menu.js')

var emptyData = require('./empty-data.json')

var mainWindow = null
var menu = null

var iconPath = path.join(__dirname, '/assets/git-it.png')

crashReporter.start()

app.on('window-all-closed', function appQuit () {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('ready', function appReady () {
  mainWindow = new BrowserWindow({"min-width": 800, "min-height": 600, width: 900, height: 600, title: 'Git-it', icon: iconPath })
  mainWindow.loadUrl('file://' + __dirname + '/index.html')

  var userDataPath = path.join(app.getPath('userData'), 'user-data.json')

  fs.exists(userDataPath, function (exists) {
    if (!exists) {
      fs.writeFile(userDataPath, JSON.stringify(emptyData, null, ' '), function (err) {
        if (err) return console.log(err)
      })
    }
  })

  ipc.on('getUserDataPath', function (event) {
    event.returnValue = userDataPath
  })

  ipc.on('open-file-dialog', function (event) {
    var files = dialog.showOpenDialog(mainWindow, { properties: [ 'openFile', 'openDirectory' ]})
    if (files) {
      event.sender.send('selected-directory', files)
    }
  })

  ipc.on('confirm-clear', function (event) {
    var options = {
      type: 'info',
      buttons: ['Yes', 'No'],
      title: 'Confirm Clearing Statuses',
      message: 'Are you sure you want to clear the status for every challenge?'
    }
    dialog.showMessageBox(options, function cb (response) {
      event.sender.send('confirm-clear-response', response)
    })
  })

  if (process.platform === 'darwin') {
    menu = Menu.buildFromTemplate(darwinTemplate(app, mainWindow))
    Menu.setApplicationMenu(menu)
  } else {
    menu = Menu.buildFromTemplate(otherTemplate(mainWindow))
    mainWindow.setMenu(menu)
  }

  mainWindow.on('closed', function winClosed () {
    mainWindow = null
  })
})
<commit_msg>Remove crashReporter<commit_after>var app = require('app')
var BrowserWindow = require('browser-window')
var Menu = require('menu')
var ipc = require('ipc')
var dialog = require('dialog')
var fs = require('fs')
var path = require('path')

var darwinTemplate = require('./menus/darwin-menu.js')
var otherTemplate = require('./menus/other-menu.js')

var emptyData = require('./empty-data.json')

var mainWindow = null
var menu = null

var iconPath = path.join(__dirname, '/assets/git-it.png')

app.on('window-all-closed', function appQuit () {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('ready', function appReady () {
  mainWindow = new BrowserWindow({"min-width": 800, "min-height": 600, width: 900, height: 600, title: 'Git-it', icon: iconPath })
  mainWindow.loadUrl('file://' + __dirname + '/index.html')

  var userDataPath = path.join(app.getPath('userData'), 'user-data.json')

  fs.exists(userDataPath, function (exists) {
    if (!exists) {
      fs.writeFile(userDataPath, JSON.stringify(emptyData, null, ' '), function (err) {
        if (err) return console.log(err)
      })
    }
  })

  ipc.on('getUserDataPath', function (event) {
    event.returnValue = userDataPath
  })

  ipc.on('open-file-dialog', function (event) {
    var files = dialog.showOpenDialog(mainWindow, { properties: [ 'openFile', 'openDirectory' ]})
    if (files) {
      event.sender.send('selected-directory', files)
    }
  })

  ipc.on('confirm-clear', function (event) {
    var options = {
      type: 'info',
      buttons: ['Yes', 'No'],
      title: 'Confirm Clearing Statuses',
      message: 'Are you sure you want to clear the status for every challenge?'
    }
    dialog.showMessageBox(options, function cb (response) {
      event.sender.send('confirm-clear-response', response)
    })
  })

  if (process.platform === 'darwin') {
    menu = Menu.buildFromTemplate(darwinTemplate(app, mainWindow))
    Menu.setApplicationMenu(menu)
  } else {
    menu = Menu.buildFromTemplate(otherTemplate(mainWindow))
    mainWindow.setMenu(menu)
  }

  mainWindow.on('closed', function winClosed () {
    mainWindow = null
  })
})
<|endoftext|>