<commit_before>

// Save Button in Modal
var saveButton = document.getElementById("myOfficialStateSaver");

// location of SVG map
const svgamericamap = document.getElementById("SVGAMERICA");

// State name text node
var stateNameHeader = document.getElementById("stateNameh2");

// Image + text where per-state-gif lands
var stateGifHolder = document.getElementById("stateGifHolder");
var stateTitleforModal = document.getElementById("stateTitleforModal");

// Loading GIF for modal
const loadingGif = "loading-america.gif";

// Default fills color of SVG Map
const mapColor = "#fff";
const mapColorHover = "#ff0000"
const mapColorFavorite = "url(#favoriteStateBackgroundImage";

// End user's Favorite State
// localStorage sets this if the user set one in the last session
var myFavoriteState = localStorage.favoriteState;
var myFavoriteStateID = localStorage.favoriteStateID
//console.log("global variable set: " + myFavoriteState + myFavoriteStateID);

// Helper function, checks to see if LocalStorage is?
function storageAvailable(type) {
	try {
		var storage = window[type],
			x = '__storage_test__';
		storage.setItem(x, x);
		storage.removeItem(x);
		return true;
	}
	catch(e) {
		return false;
	}
};

// If it's not available,
if (!storageAvailable('localStorage')) {
   console.log("no local storage");
}

// Checks to see if there is anything in localStorage, and acts on it
function onLoadState(){
  var onLoadFavoriteStateNode = document.getElementById(myFavoriteStateID);
  onLoadFavoriteStateNode.setAttribute("favorite", "true");
  onLoadFavoriteStateNode.setAttribute("fill", mapColorFavorite);
};

// Remove any previously selected favorite state.
function makeStateUnfavorite(){
  var oldFavoriteStateID = localStorage.getItem('favoriteStateID');
  var oldFavoriteStateNode = document.getElementById(oldFavoriteStateID);

  // Remove favorite attribute
  oldFavoriteStateNode.removeAttribute("favorite");

  // Returns color to normal
  oldFavoriteStateNode.setAttribute("fill", mapColor);
};

// function to save selected state to myState variable, and to local storage
function savemyState(passedStateName, passedStateID){

    // Adds event listener for clicking save
    saveButton.addEventListener("click", function handler(){

      // removes any existing favorite
      makeStateUnfavorite();

      // If we leave this line in, we can only use the button once?
      this.removeEventListener('click', handler);

      // Put our passed value into local storage!
      localStorage.setItem('favoriteState', passedStateName);
      localStorage.setItem('favoriteStateID', passedStateID);

      // The state which we just selected to be favorite, color it in!
      var mySelectedStateID = document.getElementById(passedStateID);
      mySelectedStateID.setAttribute("fill", mapColorFavorite);

      // This state we just selected to be favorite, add an attribute mark it so
      mySelectedStateID.setAttribute("favorite", "true");

    });

};

  // Waits for all content to be loaded
  document.addEventListener('DOMContentLoaded', function() {

    // Local Storage Getterer
    onLoadState();

    // Selects all the child nodes of SVGMAP
    var mapchild = svgamericamap.children;

    // Loop through the states
    for(var i = 0; i < mapchild.length; i++){

    // Mouseover event handler
      mapchild[i].addEventListener("mouseover", function(){

          // Sets background color of state
          // if it's not our favorite
          if(!this.hasAttribute("favorite")){
            this.setAttribute("fill",mapColorHover);
          };

          var stateFullName = this.getAttribute("data-name");

          // sets text header to state name
          stateNameHeader.textContent = stateFullName;

          // Clears already loaded GIF if there is one
          // So it doesn't show up accidentally for fast-clickers
          stateGifHolder.setAttribute("src", loadingGif);

      }); // End mouseover function

    // Mouseout event handler
      mapchild[i].addEventListener("mouseout", function(){
        if(!this.hasAttribute("favorite")){
          this.setAttribute("fill",mapColor);
        };

         var stateFullName = this.getAttribute("data-name");

        // removes state name from h2
        stateNameHeader.textContent = "";
      }); // End mosueout function

      // Event listener for click
       mapchild[i].addEventListener("click", function(){

        // Clears already loaded GIF if there is one
        // So it doesn't show up accidentally for fast-clickers
        stateGifHolder.setAttribute("src", loadingGif);

        // What the state and ID are here:
        var stateFullName = this.getAttribute("data-name");
        var stateID = this.getAttribute("data-id");

        this.setAttribute("fill",mapColorHover);

          stateNameHeader.textContent = stateFullName;

          // Adds event listener for the state
          savemyState(stateFullName,stateID);

          // pass name to getGif function
         return getGif(stateFullName);

       });

    }; // for loop per dom element in map

    // Service that loads from Giffy.  Expects name of state as paramter
    // Also handles modal

    var getGif = function(stateFullName){

      const apiKey = "dc6zaTOxFJmzC";
      var stateFullName = stateFullName;
      const loadGifs = new XMLHttpRequest();

      loadGifs.onreadystatechange = function() {

        if (this.readyState == 4 && this.status == 200) {

          var returnedGifs = JSON.parse(this.responseText);

          // Thumbnail
          var smallGif = returnedGifs.data[0].images.downsized.url;

          // Actual GIF
          var mainGif = returnedGifs.data[0].images.original.url;

          // Title in modal:
          stateTitleforModal.innerHTML=stateFullName;

          // Sets SRC of image in Modal to value from GIFFY feed
          stateGifHolder.setAttribute("src",mainGif);

          // Fires modal dialog box
          $('#stateModal').modal('show')

          } // if

          else{
            // Error handling
            console.log("Waiting");
          }
        };

        loadGifs.open("GET", "http://api.giphy.com/v1/gifs/search?q=" + stateFullName + "&api_key="+ apiKey +"&limit=1");
        loadGifs.send();
     }; // getgif

  }); // DOM loaded<commit_msg>starting geolocation<commit_after>

// Save Button in Modal
var saveButton = document.getElementById("myOfficialStateSaver");

// location of SVG map
const svgamericamap = document.getElementById("SVGAMERICA");

// State name text node
var stateNameHeader = document.getElementById("stateNameh2");

// Image + text where per-state-gif lands
var stateGifHolder = document.getElementById("stateGifHolder");
var stateTitleforModal = document.getElementById("stateTitleforModal");

// Loading GIF for modal
const loadingGif = "loading-america.gif";

// Default fills color of SVG Map
const mapColor = "#fff";
const mapColorHover = "#ff0000"
const mapColorFavorite = "url(#favoriteStateBackgroundImage";

// End user's Favorite State
// localStorage sets this if the user set one in the last session
var myFavoriteState = localStorage.favoriteState;
var myFavoriteStateID = localStorage.favoriteStateID
//console.log("global variable set: " + myFavoriteState + myFavoriteStateID);

// Helper function, checks to see if LocalStorage is?
function storageAvailable(type) {
	try {
		var storage = window[type],
			x = '__storage_test__';
		storage.setItem(x, x);
		storage.removeItem(x);
		return true;
	}
	catch(e) {
		return false;
	}
};

// If it's not available,
if (!storageAvailable('localStorage')) {
   console.log("no local storage");
}

// Checks to see if there is anything in localStorage, and acts on it
function onLoadState(){
  var onLoadFavoriteStateNode = document.getElementById(myFavoriteStateID);
  onLoadFavoriteStateNode.setAttribute("favorite", "true");
  onLoadFavoriteStateNode.setAttribute("fill", mapColorFavorite);
};

// Remove any previously selected favorite state.
function makeStateUnfavorite(){
  var oldFavoriteStateID = localStorage.getItem('favoriteStateID');
  var oldFavoriteStateNode = document.getElementById(oldFavoriteStateID);

  // Remove favorite attribute
  oldFavoriteStateNode.removeAttribute("favorite");

  // Returns color to normal
  oldFavoriteStateNode.setAttribute("fill", mapColor);
};

// function to save selected state to myState variable, and to local storage
function savemyState(passedStateName, passedStateID){

    // Adds event listener for clicking save
    saveButton.addEventListener("click", function handler(){

      // removes any existing favorite
      makeStateUnfavorite();

      // If we leave this line in, we can only use the button once?
      this.removeEventListener('click', handler);

      // Put our passed value into local storage!
      localStorage.setItem('favoriteState', passedStateName);
      localStorage.setItem('favoriteStateID', passedStateID);

      // The state which we just selected to be favorite, color it in!
      var mySelectedStateID = document.getElementById(passedStateID);
      mySelectedStateID.setAttribute("fill", mapColorFavorite);

      // This state we just selected to be favorite, add an attribute mark it so
      mySelectedStateID.setAttribute("favorite", "true");

    });

};

// URL for finding state
// http://nominatim.openstreetmap.org/reverse?format=xml&lat=35.7787429714954&lon=-78.6602098644987&pdoran@gmail.com&zoom=8&format=json&json_callback=myGeoState

var myLat;
var myLong;
var stateLookupService = "http://nominatim.openstreetmap.org/reverse?pdoran@gmail.com&zoom=8&format=json&json_callback=myGeoState&lat=" + myLat + "&lon=" + myLong;

console.log(stateLookupService)

// Check if we're on mobile

// Get state by geolocation, or allow user to find it w/a link

var options = {
  enableHighAccuracy: false,
  timeout: 5000,
  maximumAge: 0
};

function geosuccess(pos) {
  var crd = pos.coords;

  console.log('Your current position is:');
  console.log(`Latitude : ${crd.latitude}`);
  console.log(`Longitude: ${crd.longitude}`);
  console.log(`More or less ${crd.accuracy} meters.`);
};

function error(err) {
  console.warn(`ERROR(${err.code}): ${err.message}`);
};

navigator.geolocation.getCurrentPosition(geosuccess, error, options);

// pass lat  long to service

// Make the click function

  // Waits for all content to be loaded
  document.addEventListener('DOMContentLoaded', function() {

    // Local Storage Getterer
    onLoadState();

    // Selects all the child nodes of SVGMAP
    var mapchild = svgamericamap.children;

    // Loop through the states
    for(var i = 0; i < mapchild.length; i++){

    // Mouseover event handler
      mapchild[i].addEventListener("mouseover", function(){

          // Sets background color of state
          // if it's not our favorite
          if(!this.hasAttribute("favorite")){
            this.setAttribute("fill",mapColorHover);
          };

          var stateFullName = this.getAttribute("data-name");

          // sets text header to state name
          stateNameHeader.textContent = stateFullName;

          // Clears already loaded GIF if there is one
          // So it doesn't show up accidentally for fast-clickers
          stateGifHolder.setAttribute("src", loadingGif);

      }); // End mouseover function

    // Mouseout event handler
      mapchild[i].addEventListener("mouseout", function(){
        if(!this.hasAttribute("favorite")){
          this.setAttribute("fill",mapColor);
        };

         var stateFullName = this.getAttribute("data-name");

        // removes state name from h2
        stateNameHeader.textContent = "";
      }); // End mosueout function

      // Event listener for click
       mapchild[i].addEventListener("click", function(){

        // Clears already loaded GIF if there is one
        // So it doesn't show up accidentally for fast-clickers
        stateGifHolder.setAttribute("src", loadingGif);

        // What the state and ID are here:
        var stateFullName = this.getAttribute("data-name");
        var stateID = this.getAttribute("data-id");

        this.setAttribute("fill",mapColorHover);

          stateNameHeader.textContent = stateFullName;

          // Adds event listener for the state
          savemyState(stateFullName,stateID);

          // pass name to getGif function
         return getGif(stateFullName);

       });

    }; // for loop per dom element in map

    // Service that loads from Giffy.  Expects name of state as paramter
    // Also handles modal

    var getGif = function(stateFullName){

      const apiKey = "dc6zaTOxFJmzC";
      var stateFullName = stateFullName;
      const loadGifs = new XMLHttpRequest();

      loadGifs.onreadystatechange = function() {

        if (this.readyState == 4 && this.status == 200) {

          var returnedGifs = JSON.parse(this.responseText);

          // Thumbnail
          var smallGif = returnedGifs.data[0].images.downsized.url;

          // Actual GIF
          var mainGif = returnedGifs.data[0].images.original.url;

          // Title in modal:
          stateTitleforModal.innerHTML=stateFullName;

          // Sets SRC of image in Modal to value from GIFFY feed
          stateGifHolder.setAttribute("src",mainGif);

          // Fires modal dialog box
          $('#stateModal').modal('show')

          } // if

          else{
            // Error handling
            console.log("Waiting");
          }
        };

        loadGifs.open("GET", "http://api.giphy.com/v1/gifs/search?q=" + stateFullName + "&api_key="+ apiKey +"&limit=1");
        loadGifs.send();
     }; // getgif

  }); // DOM loaded<|endoftext|>


<commit_before>'use strict';

// Dependencies
var express = require('express');
var fs = require('fs');
var glob = require('glob');
var path = require('path');
var Mocha = require('mocha');
var Runner = Mocha.Runner;
var _ = require('underscore');

// Create an application
exports.create = function (opts) {
    var app = express();
    bindRoutes(app, opts);
    return app;
};

exports.bindIos = function (app, opts) {
    var suite_clone;
    app.io.sockets.on('connection', function (socket) {

        var mocha = new Mocha({ timeout: 15000});
        mocha.reporter('spec').ui('bdd');

        // socket.on('list', function (data) {

        //     glob(path.resolve(opts.path, '**/*.js'), function (err, files) {
        //         if (err) { throw err; }
        //         files.forEach(function (file) {
        //             mocha.addFile(file);
        //         });

        //         var runner = mocha.run(function(data){
        //           socket.emit('list', data.toString());
        //         });

        //         runner.on('pass', function(test){
        //           socket.emit('list', test.title);
        //         });

        //         runner.on('fail', function(test){
        //           socket.emit('list', test.title);
        //         });

        //     });
        // });

        socket.on('source', function (data) {

            var fs = require('fs');
            fs.readFile(data, function (err, data) {
              if (err) {
                throw err;
              }
              socket.emit('source', data.toString());
            });

        });

        socket.on('getfiles', function (data) {

            mocha.suite.on('require', function(source, file, m) {

                if (!Object.keys(source).length) {
                    socket.emit('getfiles', file, opts.path);

                    mocha.suite.suites[mocha.suite.suites.length -1].eachTest(function (test) {
                        socket.emit('test', test.title);
                    })
                }
            });

            glob(path.resolve(opts.path, '**/*.js'), function (err, files) {
                if (err) { throw err; }
                files.forEach(function (file) {
                    mocha.addFile(file);
                });

                mocha.loadFiles(function() {
                });
            });

        });

        socket.on('run', function (data) {

            var runner = new Runner(mocha.suite);
            runner.grep(new RegExp(data,'ig'));

            runner.on('pass', function(test, info){
               socket.emit('spec', test.title, info, 'success');

            });

            runner.on('fail', function(test, err){
               socket.emit('spec', test.title, require('util').inspect(err), 'danger');
            });

            runner.on('error', function(err){
                socket.emit('spec', 'err:'+err);
            });

            runner.run(function(err){
//                socket.emit('spec', data, 'err:'+err);
            });

        });

    });

    return app;
};

// Bind application routes
function bindRoutes (app, opts) {

    // Main test page
    app.get('/', function (req, res) {
        renderTmpl(__dirname + '/../view/index.html', opts, function (err, content) {
            res.send(content);
        });
    });

}

// Poor-man's mustache
function renderTmpl (path, vars, callback) {
    fs.readFile(path, 'utf8', function (err, file) {
        if (err) {
            return callback(err);
        }
        var out = file.replace(/\{\{([a-z]+)\}\}/ig, function (all, name) {
            return vars[name];
        });
        callback(null, out);
    });
}<commit_msg>ignoreLeaks<commit_after>'use strict';

// Dependencies
var express = require('express');
var fs = require('fs');
var glob = require('glob');
var path = require('path');
var Mocha = require('mocha');
var Runner = Mocha.Runner;
var _ = require('underscore');

// Create an application
exports.create = function (opts) {
    var app = express();
    bindRoutes(app, opts);
    return app;
};

exports.bindIos = function (app, opts) {
    var suite_clone;
    app.io.sockets.on('connection', function (socket) {

        var mocha = new Mocha({ timeout: 15000 });
        mocha.reporter('spec').ui('bdd');

        // socket.on('list', function (data) {

        //     glob(path.resolve(opts.path, '**/*.js'), function (err, files) {
        //         if (err) { throw err; }
        //         files.forEach(function (file) {
        //             mocha.addFile(file);
        //         });

        //         var runner = mocha.run(function(data){
        //           socket.emit('list', data.toString());
        //         });

        //         runner.on('pass', function(test){
        //           socket.emit('list', test.title);
        //         });

        //         runner.on('fail', function(test){
        //           socket.emit('list', test.title);
        //         });

        //     });
        // });

        socket.on('source', function (data) {

            var fs = require('fs');
            fs.readFile(data, function (err, data) {
              if (err) {
                throw err;
              }
              socket.emit('source', data.toString());
            });

        });

        socket.on('getfiles', function (data) {

            mocha.suite.on('require', function(source, file, m) {

                if (!Object.keys(source).length) {
                    socket.emit('getfiles', file, opts.path);

                    mocha.suite.suites[mocha.suite.suites.length -1].eachTest(function (test) {
                        socket.emit('test', test.title);
                    })
                }
            });

            glob(path.resolve(opts.path, '**/*.js'), function (err, files) {
                if (err) { throw err; }
                files.forEach(function (file) {
                    mocha.addFile(file);
                });

                mocha.loadFiles(function() {
                });
            });

        });

        socket.on('run', function (data) {

            var runner = new Runner(mocha.suite);
            runner.ignoreLeaks = true;
            runner.grep(new RegExp(data,'ig'));

            runner.on('pass', function(test, info){
               socket.emit('spec', test.title, info, 'success');

            });

            runner.on('fail', function(test, err){
               socket.emit('spec', test.title, require('util').inspect(err), 'danger');
            });

            runner.on('error', function(err){
                socket.emit('spec', 'err:'+err);
            });

            runner.run(function(err){
//                socket.emit('spec', data, 'err:'+err);
            });

        });

    });

    return app;
};

// Bind application routes
function bindRoutes (app, opts) {

    // Main test page
    app.get('/', function (req, res) {
        renderTmpl(__dirname + '/../view/index.html', opts, function (err, content) {
            res.send(content);
        });
    });

}

// Poor-man's mustache
function renderTmpl (path, vars, callback) {
    fs.readFile(path, 'utf8', function (err, file) {
        if (err) {
            return callback(err);
        }
        var out = file.replace(/\{\{([a-z]+)\}\}/ig, function (all, name) {
            return vars[name];
        });
        callback(null, out);
    });
}
<|endoftext|>


<commit_before>'use strict';
var nodemailer  = require('nodemailer'),
    express     = require('express'),
    flatten     = require('flatten.js').flatten,
    path        = require('path'),
    app         = express(),
    hbs         = require('./hbs'),
    options     = require('./config'),
    store       = require('./store')(options.store),
    undefsafe   = require('undefsafe'),
    models      = require('./models').createModels(store),
    routes      = require('./routes'),
    handlers    = require('./handlers'),
    middleware  = require('./middleware'),
    helpers     = require('./helpers'),
    metrics     = require('./metrics'),
    github      = require('./github')(options), // if used, contains github.id
    dropbox     = require('./dropbox')(options),
    _           = require('underscore'),
    crypto      = require('crypto'),
    filteredCookieSession = require('express-cookie-blacklist'),
    sessionVersion = require('./session-version'),
    stripeRoutes  = require('./stripe')(options),
    flattened;

function generateSessionSecret() {
  console.log('Warning: Generating a session key - please see http://jsbin.com/help/session-secret');
  return crypto.createHash('md5').update(Math.random() + '').digest('hex');
}

/**
 * JS Bin configuration
 */

app.store  = store;
app.sessionVersion = sessionVersion;
// Create model singletons
// models.createModels(store);

app.mailer = (function (mail) {
  var mailTransport = null,
      method   = mail && mail.adapter,
      settings = mail && mail[method];

  if (method && options) {
    mailTransport = nodemailer.createTransport(method, settings);
  }

  return new handlers.MailHandler(mailTransport, app.render.bind(app));
})(options.mail);

app.PRODUCTION  = 'production';
app.DEVELOPMENT = 'development';

// Set the NODE_ENV variable as this is used by Express, we want the
// environment to take precedence but allow it to be set using the config file
// too.
if (process.env.NODE_ENV) {
  options.env = process.env.NODE_ENV;
}
process.env.NODE_ENV = options.env;

// Need to set the node environment to run in the same timezone as the database
// This will ideally be UTC in both cases but if not this can be set either
// using the TZ environment variable or the "timezone" option.
// This is because the mysql library coerces MySQL dates (without timezones)
// into JavaScript date objects.
if (!process.env.TZ && options.timezone) {
  process.env.TZ = options.timezone;
}

// Sort out the port.
(function () {
  var port = process.env.PORT;

  // if we're running from the bin/jsbin file, then we modify
  // both the listen port AND the options.url
  if (process.env.JSBIN_PORT) {
    if (options.url.host.indexOf(':') === -1) {
      // URL 不添加端口号
      // options.url.host += ':' + process.env.JSBIN_PORT;
    } else {
      options.url.host = options.url.host.replace(/\:\d+$/, function () {
        return ':' + process.env.JSBIN_PORT;
      });
    }
  }

  if (!port) {
    options.url.host.replace(/\:(\d+)$/, function (m, p) {
      if (p.length) {
        port = p;
      }
    });
  }

  if (!port) {
    port = 80;
  }

  // NOTE: this is *only* used for running the server.listen()
  // it's not used in the urls to access assets, etc.
  options.port = port;
})();

// Strip trailing slash from the prefix
options.url.prefix = options.url.prefix.replace(/\/$/, '');

// Apply the keys from the config file. All nested properties are
// space delimited to match the express style.
//
// For example, app.set('url prefix'); //=> '/'
flattened = flatten(options, ' ');

Object.getOwnPropertyNames(flattened).forEach(function (key) {
  app.set(key, flattened[key]);
});

// in live, we run behind a proxy - so this will give us our IPs again:
// http://expressjs.com/guide.html#proxies
if (process.env.NODE_ENV === app.PRODUCTION || process.env.JSBIN_PROXY) {
  app.enable('trust proxy');
}

app.set('root', path.resolve(path.join(__dirname, '..')));

// ensure jsbin is running from the expected root
process.chdir(app.get('root'));

app.set('version', require('../package').version);

app.set('url prefix', options.url.prefix);
app.set('url ssl', options.url.ssl);
app.set('url full', 'http://' + app.get('url host') + app.get('url prefix'));
app.set('basepath', app.get('url prefix'));
app.set('is_production', app.get('env') === app.PRODUCTION);

if (options.url.static) {
  app.set('static url', 'http://' + app.get('url static'));
} else {
  app.set('static url', app.get('url full'));
}

if (options.url.runner) {
  // strip trailing slash, just in case
  options.url.runner = options.url.runner.replace(/\/$/, '');
  app.set('url runner', options.url.runner);
} else {
  app.set('url runner', app.get('url full'));
}

app.set('views', 'views');
app.set('view engine', 'html');
app.engine('html', hbs.__express);
app.engine('txt', hbs.__express); // used in email

// Define some global template variables.
var helpers = helpers.createHelpers(app);
app.locals.version = app.get('version');
app.locals.client = app.get('client');
Object.keys(helpers).forEach(function (key) {
  app.locals[key] = helpers[key];
});

// set these as global template variables since they keep getting missed
app.locals.is_production = app.get('is_production');
app.locals.cachebust = app.locals.cacheBust = app.get('is_production') ? '?' + app.get('version') : '';

app.connect = function (callback) {
  app.emit('before:connect', app);

  // Register all the middleware.
  app.configure(function () {
    var mount = app.set('url prefix') || '/',
        logger;

    logger = process.env.JSBIN_LOGGER || app.get('server logger') || 'tiny';

    if (logger !== 'none') {
      app.use(express.logger(logger));
    }

    // favicon
    app.use(express.favicon(path.join(__dirname, '../', 'public','images','favicon.png')));

    app.use(function (req, res, next) {
      // used for timings
      req.start = Date.now();
      next();
    });
    app.emit('before:middleware');

    app.use(middleware.flash());

    // this middleware says:
    // a) if we have a static url in our config, i.e. static.jsbin.com
    // b) only serve static assets IF AND ONLY IF, the full url is requested,
    //    i.e. static.jsbin.com/css/style.css
    // c) otherwise, skip the static handler, and go straight to routes.js
    //
    // If the request hits routes.js and doesn't match a defined route (or doesn't
    // look like a bin url) then it gets 404'd - i.e. you can't request /css/style.css
    // because it'll return a 404.
    app.use(mount, (function () {
      var staticRouter = express.static(path.join(app.get('root'), 'public'));

      return function (req, res, next) {
        // construct the full request url
        var url = req.protocol + '://' + req.get('host') + req.url;

        // *if* the config has a static url path (i.e. different from jsbin.com),
        // i.e. static.jsbin.com
        if (options.url.static) {
          // and the url requested is NOT static, then continue with node
          if (url.indexOf(options.url.static) === -1) {
            return next();
          }
        }
        // otherwise serve it as a static asset...
        return staticRouter(req, res, next);
      };
    })());

    app.use(middleware.limitContentLength({limit: app.get('max-request-size')}));

    app.emit('before:cookies', { app: app });

    app.use(express.cookieParser(app.get('session secret') || generateSessionSecret()));
    app.use(filteredCookieSession(['user.settings', 'passport', 'user.email', 'user.github_id', 'user.github_token', 'user.dropbox_token', 'user.dropbox_id', 'user.flagged', 'user.bincount', 'user.api_key', 'user.key', 'user.id']));
    app.use(express.cookieSession({
      key: 'jsbin',
      cookie: {
        maxAge: 365 * 24 * 60 * 60 * 1000,
        // the domain must contain a dot and should not have a port
        domain: app.get('url host').indexOf('.') === -1 ? undefined : '.' + app.get('url host').replace(/:\d+$/, '')
      }
    }));

    app.emit('before:session', {app: app});

    // memcached sessions
    if (options.session.memcached && options.session.memcached.connection) {
      require('./addons/memcached')(app, options.session.memcached.connection);
    }

    app.emit('after:session', {app: app});

    app.use(function (req, res, next) {
      // Deletes cookies using the old domain (without the leading '.')
      // and we know this because they don't have a version in their cookie.
      if (undefsafe(req, 'session.version') === undefined) {
        var oldSess = _.extend({ version: app.get('version') }, req.session);
        res.clearCookie('jsbin');
        req.session = oldSess;
      }

      next();
    });

    // Passport
    if (options.github && options.github.id) {
      github.initialize(app);
    }
    if (options.dropbox && options.dropbox.id) {
      dropbox.initialize();
    }
    app.use(express.urlencoded());
    app.use(express.json());
    app.use(middleware.csrf({ ignore: ['/', /^\/api\//, /^\/hooks\//, /^\/subscribe\//] }));
    app.use(middleware.api({ app: app }));
    app.use(middleware.subdomain(app));
    app.use(middleware.noslashes());
    app.use(middleware.protectServiceWorker());
    app.use(middleware.ajax());
    // app.use(middleware.cors());
    app.use(middleware.jsonp());
    app.use(middleware.protocolCheck);
    app.use(middleware.decompressBody);
    app.use(middleware.notices());
    app.use(middleware.nofollow({
      allowed: ['/']
    }));

    app.emit('before:router', app);
    app.use(mount, app.router);

    // All routes must be registered after middleware
    // Register stripe webhooks
    if (options.payment && options.payment.stripe && options.store.adapter === 'mysql') {
      stripeRoutes(app);
    }
    // Register all routes
    routes(app);

  });

  app.emit('after', app);

  store.connect(function (err) {
    if (err) {
      metrics.increment('error.store.connect');
      throw err;
    }

    var port = app.set('port');
    app.listen(port);

    if (typeof callback === 'function') {
      callback();
    }
    app.emit('connected');

    process.stdout.write('JS Bin v' + app.get('version') + ' is up and running on port ' + app.get('port') + '. Now point your browser at ' + app.get('url full') + '\n');
  });
};

// Export the application to allow it to be included.
module.exports = { app: app };

// Run a local development server if this file is called directly.
if (require.main === module) {
  app.connect();
}
<commit_msg>update PORT setting<commit_after>'use strict';
var nodemailer  = require('nodemailer'),
    express     = require('express'),
    flatten     = require('flatten.js').flatten,
    path        = require('path'),
    app         = express(),
    hbs         = require('./hbs'),
    options     = require('./config'),
    store       = require('./store')(options.store),
    undefsafe   = require('undefsafe'),
    models      = require('./models').createModels(store),
    routes      = require('./routes'),
    handlers    = require('./handlers'),
    middleware  = require('./middleware'),
    helpers     = require('./helpers'),
    metrics     = require('./metrics'),
    github      = require('./github')(options), // if used, contains github.id
    dropbox     = require('./dropbox')(options),
    _           = require('underscore'),
    crypto      = require('crypto'),
    filteredCookieSession = require('express-cookie-blacklist'),
    sessionVersion = require('./session-version'),
    stripeRoutes  = require('./stripe')(options),
    flattened;

function generateSessionSecret() {
  console.log('Warning: Generating a session key - please see http://jsbin.com/help/session-secret');
  return crypto.createHash('md5').update(Math.random() + '').digest('hex');
}

/**
 * JS Bin configuration
 */

app.store  = store;
app.sessionVersion = sessionVersion;
// Create model singletons
// models.createModels(store);

app.mailer = (function (mail) {
  var mailTransport = null,
      method   = mail && mail.adapter,
      settings = mail && mail[method];

  if (method && options) {
    mailTransport = nodemailer.createTransport(method, settings);
  }

  return new handlers.MailHandler(mailTransport, app.render.bind(app));
})(options.mail);

app.PRODUCTION  = 'production';
app.DEVELOPMENT = 'development';

// Set the NODE_ENV variable as this is used by Express, we want the
// environment to take precedence but allow it to be set using the config file
// too.
if (process.env.NODE_ENV) {
  options.env = process.env.NODE_ENV;
}
process.env.NODE_ENV = options.env;

// Need to set the node environment to run in the same timezone as the database
// This will ideally be UTC in both cases but if not this can be set either
// using the TZ environment variable or the "timezone" option.
// This is because the mysql library coerces MySQL dates (without timezones)
// into JavaScript date objects.
if (!process.env.TZ && options.timezone) {
  process.env.TZ = options.timezone;
}

// Sort out the port.
(function () {
  var port = process.env.PORT;

  // if we're running from the bin/jsbin file, then we modify
  // both the listen port AND the options.url
  if (process.env.JSBIN_PORT) {
    if (options.url.host.indexOf(':') === -1) {
      // URL 不添加端口号
      // options.url.host += ':' + process.env.JSBIN_PORT;
    } else {
      options.url.host = options.url.host.replace(/\:\d+$/, function () {
        return ':' + process.env.JSBIN_PORT;
      });
    }
  }

  if (!port) {
    options.url.host.replace(/\:(\d+)$/, function (m, p) {
      if (p.length) {
        port = p;
      }
    });
  }

  if (!port) {
    port = 3000;
  }

  // NOTE: this is *only* used for running the server.listen()
  // it's not used in the urls to access assets, etc.
  options.port = port;
})();

// Strip trailing slash from the prefix
options.url.prefix = options.url.prefix.replace(/\/$/, '');

// Apply the keys from the config file. All nested properties are
// space delimited to match the express style.
//
// For example, app.set('url prefix'); //=> '/'
flattened = flatten(options, ' ');

Object.getOwnPropertyNames(flattened).forEach(function (key) {
  app.set(key, flattened[key]);
});

// in live, we run behind a proxy - so this will give us our IPs again:
// http://expressjs.com/guide.html#proxies
if (process.env.NODE_ENV === app.PRODUCTION || process.env.JSBIN_PROXY) {
  app.enable('trust proxy');
}

app.set('root', path.resolve(path.join(__dirname, '..')));

// ensure jsbin is running from the expected root
process.chdir(app.get('root'));

app.set('version', require('../package').version);

app.set('url prefix', options.url.prefix);
app.set('url ssl', options.url.ssl);
app.set('url full', 'http://' + app.get('url host') + app.get('url prefix'));
app.set('basepath', app.get('url prefix'));
app.set('is_production', app.get('env') === app.PRODUCTION);

if (options.url.static) {
  app.set('static url', 'http://' + app.get('url static'));
} else {
  app.set('static url', app.get('url full'));
}

if (options.url.runner) {
  // strip trailing slash, just in case
  options.url.runner = options.url.runner.replace(/\/$/, '');
  app.set('url runner', options.url.runner);
} else {
  app.set('url runner', app.get('url full'));
}

app.set('views', 'views');
app.set('view engine', 'html');
app.engine('html', hbs.__express);
app.engine('txt', hbs.__express); // used in email

// Define some global template variables.
var helpers = helpers.createHelpers(app);
app.locals.version = app.get('version');
app.locals.client = app.get('client');
Object.keys(helpers).forEach(function (key) {
  app.locals[key] = helpers[key];
});

// set these as global template variables since they keep getting missed
app.locals.is_production = app.get('is_production');
app.locals.cachebust = app.locals.cacheBust = app.get('is_production') ? '?' + app.get('version') : '';

app.connect = function (callback) {
  app.emit('before:connect', app);

  // Register all the middleware.
  app.configure(function () {
    var mount = app.set('url prefix') || '/',
        logger;

    logger = process.env.JSBIN_LOGGER || app.get('server logger') || 'tiny';

    if (logger !== 'none') {
      app.use(express.logger(logger));
    }

    // favicon
    app.use(express.favicon(path.join(__dirname, '../', 'public','images','favicon.png')));

    app.use(function (req, res, next) {
      // used for timings
      req.start = Date.now();
      next();
    });
    app.emit('before:middleware');

    app.use(middleware.flash());

    // this middleware says:
    // a) if we have a static url in our config, i.e. static.jsbin.com
    // b) only serve static assets IF AND ONLY IF, the full url is requested,
    //    i.e. static.jsbin.com/css/style.css
    // c) otherwise, skip the static handler, and go straight to routes.js
    //
    // If the request hits routes.js and doesn't match a defined route (or doesn't
    // look like a bin url) then it gets 404'd - i.e. you can't request /css/style.css
    // because it'll return a 404.
    app.use(mount, (function () {
      var staticRouter = express.static(path.join(app.get('root'), 'public'));

      return function (req, res, next) {
        // construct the full request url
        var url = req.protocol + '://' + req.get('host') + req.url;

        // *if* the config has a static url path (i.e. different from jsbin.com),
        // i.e. static.jsbin.com
        if (options.url.static) {
          // and the url requested is NOT static, then continue with node
          if (url.indexOf(options.url.static) === -1) {
            return next();
          }
        }
        // otherwise serve it as a static asset...
        return staticRouter(req, res, next);
      };
    })());

    app.use(middleware.limitContentLength({limit: app.get('max-request-size')}));

    app.emit('before:cookies', { app: app });

    app.use(express.cookieParser(app.get('session secret') || generateSessionSecret()));
    app.use(filteredCookieSession(['user.settings', 'passport', 'user.email', 'user.github_id', 'user.github_token', 'user.dropbox_token', 'user.dropbox_id', 'user.flagged', 'user.bincount', 'user.api_key', 'user.key', 'user.id']));
    app.use(express.cookieSession({
      key: 'jsbin',
      cookie: {
        maxAge: 365 * 24 * 60 * 60 * 1000,
        // the domain must contain a dot and should not have a port
        domain: app.get('url host').indexOf('.') === -1 ? undefined : '.' + app.get('url host').replace(/:\d+$/, '')
      }
    }));

    app.emit('before:session', {app: app});

    // memcached sessions
    if (options.session.memcached && options.session.memcached.connection) {
      require('./addons/memcached')(app, options.session.memcached.connection);
    }

    app.emit('after:session', {app: app});

    app.use(function (req, res, next) {
      // Deletes cookies using the old domain (without the leading '.')
      // and we know this because they don't have a version in their cookie.
      if (undefsafe(req, 'session.version') === undefined) {
        var oldSess = _.extend({ version: app.get('version') }, req.session);
        res.clearCookie('jsbin');
        req.session = oldSess;
      }

      next();
    });

    // Passport
    if (options.github && options.github.id) {
      github.initialize(app);
    }
    if (options.dropbox && options.dropbox.id) {
      dropbox.initialize();
    }
    app.use(express.urlencoded());
    app.use(express.json());
    app.use(middleware.csrf({ ignore: ['/', /^\/api\//, /^\/hooks\//, /^\/subscribe\//] }));
    app.use(middleware.api({ app: app }));
    app.use(middleware.subdomain(app));
    app.use(middleware.noslashes());
    app.use(middleware.protectServiceWorker());
    app.use(middleware.ajax());
    // app.use(middleware.cors());
    app.use(middleware.jsonp());
    app.use(middleware.protocolCheck);
    app.use(middleware.decompressBody);
    app.use(middleware.notices());
    app.use(middleware.nofollow({
      allowed: ['/']
    }));

    app.emit('before:router', app);
    app.use(mount, app.router);

    // All routes must be registered after middleware
    // Register stripe webhooks
    if (options.payment && options.payment.stripe && options.store.adapter === 'mysql') {
      stripeRoutes(app);
    }
    // Register all routes
    routes(app);

  });

  app.emit('after', app);

  store.connect(function (err) {
    if (err) {
      metrics.increment('error.store.connect');
      throw err;
    }

    var port = app.set('port');
    app.listen(port);

    if (typeof callback === 'function') {
      callback();
    }
    app.emit('connected');

    process.stdout.write('JS Bin v' + app.get('version') + ' is up and running on port ' + app.get('port') + '. Now point your browser at ' + app.get('url full') + '\n');
  });
};

// Export the application to allow it to be included.
module.exports = { app: app };

// Run a local development server if this file is called directly.
if (require.main === module) {
  app.connect();
}
<|endoftext|>


<commit_before>"use strict";

var path = require("path"),
    util = require("util");

var express = require("express"),
    mercator = new (require("sphericalmercator"))();

module.exports = function(tilelive, uri) {
  var app = express();

  // warm the cache
  tilelive.load(uri);

  var getInfo = function(source, callback) {
    return source.getInfo(function(err, _info) {
      if (err) {
        return callback(err);
      }

      var info = {};

      Object.keys(_info).forEach(function(key) {
        info[key] = _info[key];
      });

      if (info.vector_layers) {
        info.format = "pbf";
      }

      info.bounds = info.bounds || [-180, -85.0511, 180, 85.0511];
      info.format = info.format || (info.vector_layers ? "pbf" : null);
      info.minzoom = Math.max(0, info.minzoom | 0);
      info.maxzoom = info.maxzoom || Infinity;

      return callback(null, info);
    });
  };

  // TODO a more complete implementation of this exists...somewhere
  var getExtension = function(format) {
    // trim PNG variant info
    switch ((format || "").replace(/^(png).*/, "$1")) {
    case "png":
      return "png";

    case "pbf":
      return "vector.pbf";

    default:
      throw new Error("Unrecognized format: " + format);
    }
  };

  // TODO grids
  // TODO use TileJSON endpoint to initialize boilerplate viewer

  app.get("/:z(\\d+)/:x(\\d+)/:y(\\d+).:format([\\w\\.]+)", function(req, res, next) {
    var z = req.params.z | 0,
        x = req.params.x | 0,
        y = req.params.y | 0;

    // yeah, this is unnecessary now (since uri doesn't change), but if this is
    // used to render multiple layers it becomes necessary
    return tilelive.load(uri, function(err, source) {
      if (err) {
        return next(err);
      }

      return getInfo(source, function(err, info) {
        if (err) {
          return next(err);
        }

        // validate format / extension
        if (getExtension(info.format) !== req.params.format) {
          console.warn("Invalid format", req.params.format);
          return res.send(404);
        }

        // validate zoom
        if (z < info.minzoom || z > info.maxzoom) {
          console.warn("Invalid zoom:", z);
          return res.send(404);
        }

        // validate coords against bounds
        var xyz = mercator.xyz(info.bounds, z);

        if (x < xyz.minX ||
            x > xyz.maxX ||
            y < xyz.minY ||
            y > xyz.maxY) {
          console.warn("Invalid coordinates: %d,%d", x, y);
          return res.send(404);
        }

        return source.getTile(z, x, y, function(err, data, headers) {
          if (err) {
            return next(err);
          }

          res.set(headers);
          return res.send(data);
        });
      });
    });
  });

  app.get("/index.json", function(req, res, next) {
    return tilelive.load(uri, function(err, source) {
      if (err) {
        return next(err);
      }

      return getInfo(source, function(err, info) {
        if (err) {
          return next(err);
        }

        var uri = util.format("http://%s%s{z}/{x}/{y}.%s",
                               req.headers.host,
                               path.normalize(path.dirname(req.originalUrl) + "/"),
                               getExtension(info.format));

        info.tiles = [uri];
        info.tilejson = "2.0.0";

        return res.send(info);
      });
    });
  });

  return app;
};
<commit_msg>404 on getTile errors<commit_after>"use strict";

var path = require("path"),
    util = require("util");

var express = require("express"),
    mercator = new (require("sphericalmercator"))();

module.exports = function(tilelive, uri) {
  var app = express();

  // warm the cache
  tilelive.load(uri);

  var getInfo = function(source, callback) {
    return source.getInfo(function(err, _info) {
      if (err) {
        return callback(err);
      }

      var info = {};

      Object.keys(_info).forEach(function(key) {
        info[key] = _info[key];
      });

      if (info.vector_layers) {
        info.format = "pbf";
      }

      info.bounds = info.bounds || [-180, -85.0511, 180, 85.0511];
      info.format = info.format || (info.vector_layers ? "pbf" : null);
      info.minzoom = Math.max(0, info.minzoom | 0);
      info.maxzoom = info.maxzoom || Infinity;

      return callback(null, info);
    });
  };

  // TODO a more complete implementation of this exists...somewhere
  var getExtension = function(format) {
    // trim PNG variant info
    switch ((format || "").replace(/^(png).*/, "$1")) {
    case "png":
      return "png";

    case "pbf":
      return "vector.pbf";

    default:
      throw new Error("Unrecognized format: " + format);
    }
  };

  // TODO grids
  // TODO use TileJSON endpoint to initialize boilerplate viewer

  app.get("/:z(\\d+)/:x(\\d+)/:y(\\d+).:format([\\w\\.]+)", function(req, res, next) {
    var z = req.params.z | 0,
        x = req.params.x | 0,
        y = req.params.y | 0;

    // yeah, this is unnecessary now (since uri doesn't change), but if this is
    // used to render multiple layers it becomes necessary
    return tilelive.load(uri, function(err, source) {
      if (err) {
        return next(err);
      }

      return getInfo(source, function(err, info) {
        if (err) {
          return next(err);
        }

        // validate format / extension
        if (getExtension(info.format) !== req.params.format) {
          console.warn("Invalid format", req.params.format);
          return res.send(404);
        }

        // validate zoom
        if (z < info.minzoom || z > info.maxzoom) {
          console.warn("Invalid zoom:", z);
          return res.send(404);
        }

        // validate coords against bounds
        var xyz = mercator.xyz(info.bounds, z);

        if (x < xyz.minX ||
            x > xyz.maxX ||
            y < xyz.minY ||
            y > xyz.maxY) {
          console.warn("Invalid coordinates: %d,%d", x, y);
          return res.send(404);
        }

        return source.getTile(z, x, y, function(err, data, headers) {
          if (err) {
            console.warn(err.stack);
            return res.send(404);
            // return next(err);
          }

          res.set(headers);
          return res.send(data);
        });
      });
    });
  });

  app.get("/index.json", function(req, res, next) {
    return tilelive.load(uri, function(err, source) {
      if (err) {
        return next(err);
      }

      return getInfo(source, function(err, info) {
        if (err) {
          return next(err);
        }

        var uri = util.format("http://%s%s{z}/{x}/{y}.%s",
                               req.headers.host,
                               path.normalize(path.dirname(req.originalUrl) + "/"),
                               getExtension(info.format));

        info.tiles = [uri];
        info.tilejson = "2.0.0";

        return res.send(info);
      });
    });
  });

  return app;
};
<|endoftext|>


<commit_before>CardshifterApp.controller("DeckbuilderController", function($scope) {
    var DECK_STORAGE = "CARDSHIFTER_DECK_STORAGE";

    $scope.cards = [];
    $scope.maxCards = 0;
    $scope.minCards = 0;
    $scope.currentDeck = {};
    $scope.cardInfo = {};
    $scope.currentDeckName = "untitled";
    $scope.savedDecks = [];

    if(!localStorage.getItem(DECK_STORAGE)) {
        localStorage.setItem(DECK_STORAGE, "{\"decks\": []}");
    }

    CardshifterServerAPI.setMessageListener(function(cardInformation) {
        var deck = cardInformation.configs.Deck;
        console.log(deck);

        window.SIRPYTHONTESTINGINCORPORATED = cardInformation;

        for(var card in deck.cardData) {
            deck.cardData[card].max = deck.max[card] || deck.maxPerCard;
            $scope.currentDeck[deck.cardData[card].id] = 0;
        }

        $scope.cards = deck.cardData;
        $scope.maxCards = deck.maxSize;
        $scope.minCards = deck.minSize;

        $scope.$apply();
    }, ["playerconfig"]);

    $scope.decrement = function(card) {
        if($scope.currentDeck[card.id] !== 0) {
            $scope.currentDeck[card.id]--;
        }
    }
    $scope.increment = function(card) {
        if($scope.getTotalSelected() !== $scope.maxCards &&
           $scope.currentDeck[card.id] !== card.max) {
            $scope.currentDeck[card.id]++;
        }
    }

    $scope.getTotalSelected = function() {
        var total = 0
        for(var card in $scope.currentDeck) {
            total += $scope.currentDeck[card];
        }
        return total;
    }

    $scope.showDetails = function(card) {
        var props = card.properties;
        $scope.cardInfo = {
            name: props.name,
            flavor: props.flavor,
            type: props.creatureType,
            health: props.HEALTH,
            attack: props.ATTACK,
            sickness: props.SICKNESS
        };
    }

    $scope.saveDeck = function() {
        if($scope.getTotalSelected() === $scope.minCards) {
            if($scope.deckName) {
                if(!deckExists($scope.deckName)) {
                    var savedDecks = JSON.parse(localStorage.getItem(DECK_STORAGE));

                    var newDeck = {
                        name: $scope.deckName,
                        cards: $scope.currentDeck
                    };

                    savedDecks.decks.push(newDeck);
                    localStorage.setItem(DECK_STORAGE, JSON.stringify(savedDecks));
                    updateSavedDecks();

                    $scope.switchDeck(newDeck);
                } else {
                    console.log("deck already exists");     // bad looking nesting
                }
            } else {
                console.log("please enter name");
            }
        } else {
            console.log("not enough cards");
        }
    }
    $scope.switchDeck = function(deck) {
        $scope.currentDeckName = deck.name;
        $scope.currentDeck = deck.cards;
    }

    function updateSavedDecks() {
        $scope.savedDecks = JSON.parse(localStorage.getItem(DECK_STORAGE)).decks;
    }
    function deckExists(name) {
        for(var i = 0, length = $scope.savedDecks.length; i < length; i++) {
            if($scope.savedDecks[i].name === name) {
                return true;
            }
        }
        return false;
    }
});<commit_msg>added deck deletion, repurposed deckExists, change storing method<commit_after>CardshifterApp.controller("DeckbuilderController", function($scope) {
    var DECK_STORAGE = "CARDSHIFTER_DECK_STORAGE";

    $scope.cards = [];
    $scope.maxCards = 0;
    $scope.minCards = 0;
    $scope.currentDeck = {};
    $scope.cardInfo = {};
    $scope.currentDeckName = "untitled";
    $scope.savedDecks = [];
    $scope.doneLoading = false;

    if(!localStorage.getItem(DECK_STORAGE)) {
        var json = "{\"decks\": {";
        for(var i = 0, length = availableGameMods.length; i < length; i++) {
            json += "\"" + availableGameMods[i] + "\":[],";
        }
        json = json.slice(0, -1); // remove last comma
        json += "}}";
        localStorage.setItem(DECK_STORAGE, json);
    }

    CardshifterServerAPI.setMessageListener(function(cardInformation) {
        var deck = cardInformation.configs.Deck;

        for(var card in deck.cardData) {
            if(deck.cardData.hasOwnProperty(card)) {
                deck.cardData[card].max = deck.max[card] || deck.maxPerCard;
                $scope.currentDeck[deck.cardData[card].id] = 0;
            }
        }

        $scope.cards = deck.cardData;
        $scope.maxCards = deck.maxSize;
        $scope.minCards = deck.minSize;
        updateSavedDecks();
        $scope.doneLoading = true;

        $scope.$apply();
    }, ["playerconfig"]);

    $scope.decrement = function(card) {
        if($scope.currentDeck[card.id] !== 0) {
            $scope.currentDeck[card.id]--;
        }
    };
    $scope.increment = function(card) {
        if($scope.getTotalSelected() !== $scope.maxCards &&
           $scope.currentDeck[card.id] !== card.max) {
            $scope.currentDeck[card.id]++;
        }
    };

    $scope.getTotalSelected = function() {
        var total = 0;
        for(var card in $scope.currentDeck) {
            if($scope.currentDeck.hasOwnProperty(card)) {
                total += $scope.currentDeck[card];
            }

        }
        return total;
    };

    $scope.showDetails = function(card) {
        var props = card.properties;
        $scope.cardInfo = {
            name: props.name,
            flavor: props.flavor,
            type: props.creatureType,
            health: props.HEALTH,
            attack: props.ATTACK,
            sickness: props.SICKNESS
        };
    };

    $scope.saveDeck = function() {
        if($scope.getTotalSelected() === $scope.minCards) {
            if($scope.deckName) {
                if(!getDeckIndex($scope.deckName)) { // if deck exists
                    var savedDecks = JSON.parse(localStorage.getItem(DECK_STORAGE));

                    var newDeck = {
                        name: $scope.deckName,
                        cards: $scope.currentDeck
                    };

                    savedDecks.decks[currentUser.game.mod].push(newDeck);
                    localStorage.setItem(DECK_STORAGE, JSON.stringify(savedDecks));
                    updateSavedDecks();

                    $scope.switchDeck(newDeck);
                } else {
                    console.log("deck already exists");     // bad looking nesting
                }
            } else {
                console.log("please enter name");
            }
        } else {
            console.log("not enough cards");
        }
    };
    $scope.switchDeck = function(deck) {
        $scope.currentDeckName = deck.name;
        $scope.currentDeck = deck.cards;
    };
    $scope.deleteDeck = function(deckName) {
        var savedDecks = JSON.parse(localStorage.getItem(DECK_STORAGE));
        savedDecks.decks[currentUser.game.mod].splice(getDeckIndex(deckName), 1);
        localStorage.setItem(DECK_STORAGE, JSON.stringify(savedDecks));

        updateSavedDecks();
    };

    function updateSavedDecks() {
        $scope.savedDecks = JSON.parse(localStorage.getItem(DECK_STORAGE)).decks[currentUser.game.mod];
    }
    function getDeckIndex(deckName) {
        for(var i = 0, length = $scope.savedDecks.length; i < length; i++) {
            if($scope.savedDecks[i].name === deckName) {
                return i;
            }
        }
        return false;
    }
});<|endoftext|>


<commit_before>/*jshint laxcomma:true */

/**
 * The Strider (web) app.
 */

var auth = require('./auth')
    , apres = require('apres')
    , backchannel = require('./backchannel')
    , common = require('./common')
    , express = require('express')
    , EventEmitter = require('events').EventEmitter
    , everypaas = require('everypaas')
    , logging = require('./logging')
    , middleware = require('./middleware')
    , mongoose = require('mongoose')
    , mongoose_auth = require('mongoose-auth')
    , mongoStore = require('connect-mongo')(express)
    , routes = require('../routes')
    , websockets = require('./websockets')

    , routes_admin = require('../routes/admin/index.js')
    , routes_jobs = require('../routes/jobs/index.js')
    , api = require('../routes/api')
    , api_account = require('../routes/api/account.js')
    , api_admin = require('../routes/api/admin/index.js')
    , api_collaborators = require('../routes/api/collaborators')
    , api_github = require('../routes/api/github.js')
    , api_heroku = require('../routes/api/heroku.js')
    , api_jobs = require('../routes/api/jobs.js')
    , api_repo = require('../routes/api/repo.js')
    , api_webhooks = require('../routes/api/webhooks')
    ;

var MONTH_IN_MILLISECONDS = 2629743000;
var session_store;

var init = exports.init = function (config) {

  var mongodbUrl = everypaas.getMongodbUrl() || config.db_uri;
  console.log("Using MongoDB URL: %s", mongodbUrl);
  mongoose.connect(mongodbUrl);
  session_store = new mongoStore({url: mongodbUrl});

  var app = express.createServer();

  app.configure(function(){
    app.set('views', __dirname + '/../views');
    app.set('view engine', 'jade');
    app.set('view options', { pretty: true });
    app.use(middleware.bodySetter);
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.methodOverride());
    app.use(require('stylus').middleware({ src: __dirname + '/../public' }));
    app.use(express.session({secret: config.session_secret, store: session_store,
      cookie: {maxAge: MONTH_IN_MILLISECONDS}}));
    app.use(mongoose_auth.middleware());
    app.use(express.static(__dirname + '/../public', {maxAge: MONTH_IN_MILLISECONDS}));
    apres.helpExpress(app);
    app.use(app.router);
  });

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

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

  // Routes

  app.get('/', routes.index);
  app.get('/about',function(req, res) {
     res.render('about');
   });

  // Docs page (single page for moment)
  app.get('/docs', function(req, res) {res.render('docs');});
  app.get('/docs/getting_started', function(req, res) {res.render('docs/GettingStarted');});
  app.get('/docs/why_heroku_api_key', function(req, res) {res.render('docs/whyHerokuAPIKey');});

  app.get('/admin/projects', middleware.require_admin, routes_admin.projects);
  app.get('/admin/users', middleware.require_admin, routes_admin.users);
  app.get('/admin/jobs', middleware.require_admin, function(req, res) {
    res.render('admin/jobs')});
  app.get('/admin/make_admin', middleware.require_admin, routes_admin.make_admin);
  app.get('/admin/invites', middleware.require_admin, routes_admin.invites);
  app.get('/admin/:org/:repo/job/:job_id', middleware.require_admin, routes_admin.job);

  app.get('/account', middleware.require_auth_browser, routes.account);
  app.get('/add_repo', middleware.require_auth_browser, function(req, res) { res.render('add_repo'); });

  /* Requires at least read-only access to the repository in the path */
  app.get('/:org/:repo/latest_build', middleware.require_auth_browser, middleware.require_resource_read,
    routes_jobs.latest_build);
  app.get('/:org/:repo/', middleware.require_auth_browser, middleware.require_resource_read,
    routes_jobs.latest_build);
  app.get('/:org/:repo/job/:job_id', middleware.require_auth_browser, middleware.require_resource_read,
    routes_jobs.job);

  /* Requires admin access to the repository in the path */
  app.get('/:org/:repo/config',middleware.require_auth_browser, middleware.require_resource_admin,
    routes.config);

  app.post('/webhook', routes.webhook_signature);
  app.post('/webhook/:secret',routes.webhook_secret);

  app.get('/kickoff/:githubId', middleware.require_auth, routes.kickoff);
  app.get('/manual_setup', middleware.require_auth, function(req,res) {res.render('manual_setup');});

  app.post('/api/github/manual_setup',
    middleware.require_auth,
    middleware.require_params(["github_url"]),
    api_github.post_manual_setup);
  app.get('/api/github/metadata', middleware.require_auth, api_github.github_metadata);
  app.post('/api/github/webhooks/unset', middleware.require_auth, api_github.github_webhooks_unset);

  app.get('/api/admin/jobs', middleware.require_admin, api_admin.admin_jobs_status);
  app.get('/api/admin/users', middleware.require_admin, api_admin.get_user_list);
  app.post('/api/admin/invite/new', middleware.require_admin, api.invite_new);

  // this should be app.del and delete should be removed from the end
  // that requires javascript on client side
  app.get('/:org/:repo/delete', middleware.require_resource_admin, routes.delete_project);

  app.get('/api/jobs', middleware.require_auth, api_jobs.jobs);
  app.post('/api/jobs/start', middleware.require_auth, api_jobs.jobs_start);
  app.post('/api/heroku/account_integration', middleware.require_auth, api_heroku.heroku_account_integration);
  app.post('/api/heroku/delivery_integration', middleware.require_auth, api_heroku.heroku_delivery_integration);
  app.post('/api/heroku/config', middleware.require_auth, middleware.require_params(["url"]), api_heroku.heroku_config);

  app.post('/api/account/password', middleware.require_auth, api_account.account_password);
  app.post('/api/account/email', middleware.require_auth, api_account.account_email);

  // collaborators
  app.get('/api/collaborators',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_collaborators.get_index);
  app.post('/api/collaborators',
    middleware.require_auth,
    middleware.require_params(["url", "email"]),
    api_collaborators.post_index);
  app.delete('/api/collaborators',
    middleware.require_auth,
    middleware.require_params(["url", "email"]),
    api_collaborators.delete_index);

  // webhooks
  app.get('/api/webhooks',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_webhooks.get_index);
  app.post('/api/webhooks',
    middleware.require_auth,
    middleware.require_params(["url", "target_url", "secret"]),
    api_webhooks.post_index);
  app.delete('/api/webhooks',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_webhooks.delete_index);

  // repo config
  app.get('/api/repo',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_repo.get_index);
  app.post('/api/repo',
    middleware.require_auth,
    middleware.require_params(["url", "active"]),
    api_repo.post_index);
  app.delete('/api/repo',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_repo.delete_index);

  mongoose_auth.helpExpress(app);

  app.dynamicHelpers({
    user_created_timestamp: function(req, res){
      var user_created_timestamp=0;
      if (req.user !== undefined)
      {
        user_created_timestamp = parseInt(req.user.id.substr(0,8),16);
      }
      return user_created_timestamp;
    },
  });

  common.app = app;
  common.session_store = session_store;
  //
  // ### Strider Webapp Event Emitter
  //
  // Strider has a Node.Js Event Emitter which emits many events.  This can be
  // used by extensions to add extremely flexible custom handling for just about
  // anything.
  //
  common.emitter = new EventEmitter();

  return app;
};

// Don't run if require()'d
if (!module.parent) {
  var config = require('./config');
  var app = init(config);
  // Custom 404 handler.
  // Run after extensions, which might load static middlewares.
  app.use(middleware.custom404);
  app.listen(8080);
  // Initialize socket.io
  websockets.init(app, session_store);
  backchannel.init();
  console.info("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
}

<commit_msg>read db_uri directly from config - that is where all the everypaas etc stuff happens.<commit_after>/*jshint laxcomma:true */

/**
 * The Strider (web) app.
 */

var auth = require('./auth')
    , apres = require('apres')
    , backchannel = require('./backchannel')
    , common = require('./common')
    , express = require('express')
    , EventEmitter = require('events').EventEmitter
    , everypaas = require('everypaas')
    , logging = require('./logging')
    , middleware = require('./middleware')
    , mongoose = require('mongoose')
    , mongoose_auth = require('mongoose-auth')
    , mongoStore = require('connect-mongo')(express)
    , routes = require('../routes')
    , websockets = require('./websockets')

    , routes_admin = require('../routes/admin/index.js')
    , routes_jobs = require('../routes/jobs/index.js')
    , api = require('../routes/api')
    , api_account = require('../routes/api/account.js')
    , api_admin = require('../routes/api/admin/index.js')
    , api_collaborators = require('../routes/api/collaborators')
    , api_github = require('../routes/api/github.js')
    , api_heroku = require('../routes/api/heroku.js')
    , api_jobs = require('../routes/api/jobs.js')
    , api_repo = require('../routes/api/repo.js')
    , api_webhooks = require('../routes/api/webhooks')
    ;

var MONTH_IN_MILLISECONDS = 2629743000;
var session_store;

var init = exports.init = function (config) {

  var mongodbUrl = config.db_uri;
  console.log("Using MongoDB URL: %s", mongodbUrl);
  mongoose.connect(mongodbUrl);
  session_store = new mongoStore({url: mongodbUrl});

  var app = express.createServer();

  app.configure(function(){
    app.set('views', __dirname + '/../views');
    app.set('view engine', 'jade');
    app.set('view options', { pretty: true });
    app.use(middleware.bodySetter);
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.methodOverride());
    app.use(require('stylus').middleware({ src: __dirname + '/../public' }));
    app.use(express.session({secret: config.session_secret, store: session_store,
      cookie: {maxAge: MONTH_IN_MILLISECONDS}}));
    app.use(mongoose_auth.middleware());
    app.use(express.static(__dirname + '/../public', {maxAge: MONTH_IN_MILLISECONDS}));
    apres.helpExpress(app);
    app.use(app.router);
  });

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

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

  // Routes

  app.get('/', routes.index);
  app.get('/about',function(req, res) {
     res.render('about');
   });

  // Docs page (single page for moment)
  app.get('/docs', function(req, res) {res.render('docs');});
  app.get('/docs/getting_started', function(req, res) {res.render('docs/GettingStarted');});
  app.get('/docs/why_heroku_api_key', function(req, res) {res.render('docs/whyHerokuAPIKey');});

  app.get('/admin/projects', middleware.require_admin, routes_admin.projects);
  app.get('/admin/users', middleware.require_admin, routes_admin.users);
  app.get('/admin/jobs', middleware.require_admin, function(req, res) {
    res.render('admin/jobs')});
  app.get('/admin/make_admin', middleware.require_admin, routes_admin.make_admin);
  app.get('/admin/invites', middleware.require_admin, routes_admin.invites);
  app.get('/admin/:org/:repo/job/:job_id', middleware.require_admin, routes_admin.job);

  app.get('/account', middleware.require_auth_browser, routes.account);
  app.get('/add_repo', middleware.require_auth_browser, function(req, res) { res.render('add_repo'); });

  /* Requires at least read-only access to the repository in the path */
  app.get('/:org/:repo/latest_build', middleware.require_auth_browser, middleware.require_resource_read,
    routes_jobs.latest_build);
  app.get('/:org/:repo/', middleware.require_auth_browser, middleware.require_resource_read,
    routes_jobs.latest_build);
  app.get('/:org/:repo/job/:job_id', middleware.require_auth_browser, middleware.require_resource_read,
    routes_jobs.job);

  /* Requires admin access to the repository in the path */
  app.get('/:org/:repo/config',middleware.require_auth_browser, middleware.require_resource_admin,
    routes.config);

  app.post('/webhook', routes.webhook_signature);
  app.post('/webhook/:secret',routes.webhook_secret);

  app.get('/kickoff/:githubId', middleware.require_auth, routes.kickoff);
  app.get('/manual_setup', middleware.require_auth, function(req,res) {res.render('manual_setup');});

  app.post('/api/github/manual_setup',
    middleware.require_auth,
    middleware.require_params(["github_url"]),
    api_github.post_manual_setup);
  app.get('/api/github/metadata', middleware.require_auth, api_github.github_metadata);
  app.post('/api/github/webhooks/unset', middleware.require_auth, api_github.github_webhooks_unset);

  app.get('/api/admin/jobs', middleware.require_admin, api_admin.admin_jobs_status);
  app.get('/api/admin/users', middleware.require_admin, api_admin.get_user_list);
  app.post('/api/admin/invite/new', middleware.require_admin, api.invite_new);

  // this should be app.del and delete should be removed from the end
  // that requires javascript on client side
  app.get('/:org/:repo/delete', middleware.require_resource_admin, routes.delete_project);

  app.get('/api/jobs', middleware.require_auth, api_jobs.jobs);
  app.post('/api/jobs/start', middleware.require_auth, api_jobs.jobs_start);
  app.post('/api/heroku/account_integration', middleware.require_auth, api_heroku.heroku_account_integration);
  app.post('/api/heroku/delivery_integration', middleware.require_auth, api_heroku.heroku_delivery_integration);
  app.post('/api/heroku/config', middleware.require_auth, middleware.require_params(["url"]), api_heroku.heroku_config);

  app.post('/api/account/password', middleware.require_auth, api_account.account_password);
  app.post('/api/account/email', middleware.require_auth, api_account.account_email);

  // collaborators
  app.get('/api/collaborators',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_collaborators.get_index);
  app.post('/api/collaborators',
    middleware.require_auth,
    middleware.require_params(["url", "email"]),
    api_collaborators.post_index);
  app.delete('/api/collaborators',
    middleware.require_auth,
    middleware.require_params(["url", "email"]),
    api_collaborators.delete_index);

  // webhooks
  app.get('/api/webhooks',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_webhooks.get_index);
  app.post('/api/webhooks',
    middleware.require_auth,
    middleware.require_params(["url", "target_url", "secret"]),
    api_webhooks.post_index);
  app.delete('/api/webhooks',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_webhooks.delete_index);

  // repo config
  app.get('/api/repo',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_repo.get_index);
  app.post('/api/repo',
    middleware.require_auth,
    middleware.require_params(["url", "active"]),
    api_repo.post_index);
  app.delete('/api/repo',
    middleware.require_auth,
    middleware.require_params(["url"]),
    api_repo.delete_index);

  mongoose_auth.helpExpress(app);

  app.dynamicHelpers({
    user_created_timestamp: function(req, res){
      var user_created_timestamp=0;
      if (req.user !== undefined)
      {
        user_created_timestamp = parseInt(req.user.id.substr(0,8),16);
      }
      return user_created_timestamp;
    },
  });

  common.app = app;
  common.session_store = session_store;
  //
  // ### Strider Webapp Event Emitter
  //
  // Strider has a Node.Js Event Emitter which emits many events.  This can be
  // used by extensions to add extremely flexible custom handling for just about
  // anything.
  //
  common.emitter = new EventEmitter();

  return app;
};

// Don't run if require()'d
if (!module.parent) {
  var config = require('./config');
  var app = init(config);
  // Custom 404 handler.
  // Run after extensions, which might load static middlewares.
  app.use(middleware.custom404);
  app.listen(8080);
  // Initialize socket.io
  websockets.init(app, session_store);
  backchannel.init();
  console.info("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
}

<|endoftext|>


<commit_before>var Promise = require('bluebird');
var request = require('request-promise');
var cheerio = require('cheerio');
var playStoreUrl = 'https://play.google.com/store/apps/details';
var queryString = require('querystring');
var url = require('url');

var h = require('./helpers');

function app(id, lang) {
    lang = lang || 'en';

    return new Promise(function (resolve, reject) {
        var reqUrl = url.parse(playStoreUrl + '?' + queryString.stringify({id: id, hl: lang}));
        request(reqUrl.href)
            .then(cheerio.load, h.requestError)
            .then(parseFields)
            .then(function (app) {
                app.url = url;
                app.appId = id;
                resolve(app);
            })
            .catch(reject);
    });
}

function parseFields($) {
    var detailsInfo = $('.details-info');
    var title = detailsInfo.find('div.document-title').text().trim();
    var developer = detailsInfo.find('span[itemprop="name"]').text();
    var genre = detailsInfo.find('span[itemprop="genre"]').text();
    var price = detailsInfo.find('meta[itemprop=price]').attr('content');
    var icon = detailsInfo.find('img.cover-image').attr('src');

    var additionalInfo = $('.details-section-contents');
    var version = additionalInfo.find('div.content[itemprop="softwareVersion"]').text().trim();
    var updated = additionalInfo.find('div.content[itemprop="datePublished"]').text().trim();
    var requiredAndroidVersion = additionalInfo.find('div.content[itemprop="operatingSystems"]').text().trim();
    var contentRating = additionalInfo.find('div.content[itemprop="contentRating"]').text().trim();
    var size = additionalInfo.find('div.content[itemprop="fileSize"]').text().trim();
    var installs = additionalInfo.find('div.content[itemprop="numDownloads"]').text().trim();
    var minInstalls = cleanInt(installs.split(' - ')[0]);
    var maxInstalls = cleanInt(installs.split(' - ')[1]) || undefined;

    var ratingBox = $('.rating-box');
    var reviews = cleanInt(ratingBox.find('span.reviews-num').text());

    var ratingHistogram = $('.rating-histogram');
    var histogram = {
        5: Number(ratingHistogram.find('.five .bar-number').text()),
        4: Number(ratingHistogram.find('.four .bar-number').text()),
        3: Number(ratingHistogram.find('.three .bar-number').text()),
        2: Number(ratingHistogram.find('.two .bar-number').text()),
        1: Number(ratingHistogram.find('.one .bar-number').text())
    };
    //for other languages
    var score = parseFloat(ratingBox.find('div.score').text().replace(',', '.')) || 0;

    var video = $('.screenshots span.preview-overlay-container[data-video-url]').attr('data-video-url');
    if (video) {
        video = video.split('?')[0];
    }

    var description = $('.description div.id-app-orig-desc');

    return {
        title: title,
        icon: icon,
        minInstalls: minInstalls,
        maxInstalls: maxInstalls,
        score: score,
        reviews: reviews,
        histogram: histogram,
        description: description.text(),
        descriptionHTML: description.html(),
        developer: developer,
        updated: updated,
        version: version,
        size: size,
        requiredAndroidVersion: requiredAndroidVersion,
        contentRating: contentRating,
        genre: genre,
        price: price,
        free: price === '0',
        video: video
    };
}

function cleanInt(number) {
    number = number || '0';
    //removes thousands separator
    number = number.replace(/\D/g, '');
    return parseInt(number);
}

module.exports = app;
<commit_msg>Fix app.url set incorrectly<commit_after>var Promise = require('bluebird');
var request = require('request-promise');
var cheerio = require('cheerio');
var playStoreUrl = 'https://play.google.com/store/apps/details';
var queryString = require('querystring');
var url = require('url');

var h = require('./helpers');

function app(id, lang) {
    lang = lang || 'en';

    return new Promise(function (resolve, reject) {
        var reqUrl = url.parse(playStoreUrl + '?' + queryString.stringify({id: id, hl: lang}));
        request(reqUrl.href)
            .then(cheerio.load, h.requestError)
            .then(parseFields)
            .then(function (app) {
                app.url = reqUrl.href;
                app.appId = id;
                resolve(app);
            })
            .catch(reject);
    });
}

function parseFields($) {
    var detailsInfo = $('.details-info');
    var title = detailsInfo.find('div.document-title').text().trim();
    var developer = detailsInfo.find('span[itemprop="name"]').text();
    var genre = detailsInfo.find('span[itemprop="genre"]').text();
    var price = detailsInfo.find('meta[itemprop=price]').attr('content');
    var icon = detailsInfo.find('img.cover-image').attr('src');

    var additionalInfo = $('.details-section-contents');
    var version = additionalInfo.find('div.content[itemprop="softwareVersion"]').text().trim();
    var updated = additionalInfo.find('div.content[itemprop="datePublished"]').text().trim();
    var requiredAndroidVersion = additionalInfo.find('div.content[itemprop="operatingSystems"]').text().trim();
    var contentRating = additionalInfo.find('div.content[itemprop="contentRating"]').text().trim();
    var size = additionalInfo.find('div.content[itemprop="fileSize"]').text().trim();
    var installs = additionalInfo.find('div.content[itemprop="numDownloads"]').text().trim();
    var minInstalls = cleanInt(installs.split(' - ')[0]);
    var maxInstalls = cleanInt(installs.split(' - ')[1]) || undefined;

    var ratingBox = $('.rating-box');
    var reviews = cleanInt(ratingBox.find('span.reviews-num').text());

    var ratingHistogram = $('.rating-histogram');
    var histogram = {
        5: Number(ratingHistogram.find('.five .bar-number').text()),
        4: Number(ratingHistogram.find('.four .bar-number').text()),
        3: Number(ratingHistogram.find('.three .bar-number').text()),
        2: Number(ratingHistogram.find('.two .bar-number').text()),
        1: Number(ratingHistogram.find('.one .bar-number').text())
    };
    //for other languages
    var score = parseFloat(ratingBox.find('div.score').text().replace(',', '.')) || 0;

    var video = $('.screenshots span.preview-overlay-container[data-video-url]').attr('data-video-url');
    if (video) {
        video = video.split('?')[0];
    }

    var description = $('.description div.id-app-orig-desc');

    return {
        title: title,
        icon: icon,
        minInstalls: minInstalls,
        maxInstalls: maxInstalls,
        score: score,
        reviews: reviews,
        histogram: histogram,
        description: description.text(),
        descriptionHTML: description.html(),
        developer: developer,
        updated: updated,
        version: version,
        size: size,
        requiredAndroidVersion: requiredAndroidVersion,
        contentRating: contentRating,
        genre: genre,
        price: price,
        free: price === '0',
        video: video
    };
}

function cleanInt(number) {
    number = number || '0';
    //removes thousands separator
    number = number.replace(/\D/g, '');
    return parseInt(number);
}

module.exports = app;
<|endoftext|>


<commit_before>var SerialPort = require("serialport").SerialPort

/**
 * Create the connection to the TV
 *
 * @param   object  options
 */
function tv(options) {
  this.options = options;

  if (typeof options.port === "undefined") {
    throw "Please define a port such as /dev/ttyS0";
  }

  this.session = new SerialPort(options.port, {
    baudrate: 9600
  });
}

module.exports = tv;

/**
 * Power toggle the TV
 */
tv.prototype.powerToggle = function() {

};

/**
 * Power the TV on/off
 *
 * @param   bool    state
 */
tv.prototype.power = function(state) {

}

tv.prototype.volumeUp = function() {

}

tv.prototype.volumeDown = function() {

}

tv.prototype.volume = function(value) {

}

tv.prototype.volumeMute = function() {

}

tv.prototype.getSession = function() {

}

/**
 * Close the serial session
 */
tv.prototype.close = function() {
  this.session.close();
}<commit_msg>Defining all methods and start of doc blocks<commit_after>var SerialPort = require("serialport").SerialPort

/**
 * Create the connection to the TV
 *
 * @param   object  options
 */
function tv(options) {
  this.options = options;

  if (typeof options.port === "undefined") {
    throw "Please define a port such as /dev/ttyS0";
  }

  this.session = new SerialPort(options.port, {
    baudrate: 9600
  });
}

module.exports = tv;

/**
 * Power toggle the TV
 */
tv.prototype.powerToggle = function() {

};

/**
 * Power the TV on/off
 *
 * @param   bool      state
 * @param   function  callback
 */
tv.prototype.power = function(state, callback) {

}

/**
 * Increase volume up by 1
 *
 * @param   function  callback
 */
tv.prototype.volumeUp = function(callback) {

}

/**
 * Decrease volume up by 1
 *
 * @param   function  callback
 */
tv.prototype.volumeDown = function(callback) {

}

/**
 * Set the volume to a specific level
 *
 * @param   int       value       (0-100)
 * @param   function  callback
 */
tv.prototype.volume = function(value, callback) {

}

/**
 * Toggle volume mute
 *
 * @param   function  callback
 */
tv.prototype.volumeMute = function(callback) {

}

/**
 * Go to the next channel in the list
 *
 * @param   function  callback
 */
tv.prototype.channelUp = function(callback) {

}

/**
 * Go to the previous channel in the list
 *
 * @param   function  callback
 */
tv.prototype.channelDown = function(callback) {

}

/**
 * Go to the previous channel
 *
 * @param   function  callback
 */
tv.prototype.channelPrevious = function(callback) {

}

/**
 * Go to a specific channel number
 *
 * @param   function  callback
 */
tv.prototype.channel = function(value, callback) {

}

/**
 * Set the source to the TV
 *
 * @param   function  callback
 */
tv.prototype.sourceTv = function(callback) {

}

/**
 * Set the source to the AV input (1-3)
 *
 * @param   int       value
 * @param   function  callback
 */
tv.prototype.sourceAv = function(value, callback) {

}

/**
 * Set the source to the component input (1-3)
 *
 * @param   int       value
 * @param   function  callback
 */
tv.prototype.sourceComponent = function(value, callback) {

}

/**
 * Set the source to the PC input
 *
 * @param   function  callback
 */
tv.prototype.sourcePc = function(callback) {

}

/**
 * Set the source to the HDMI input (1-4)
 *
 * @param   int       value
 * @param   function  callback
 */
tv.prototype.sourceHdmi = function(value, callback) {

}

/**
 * Set the source to the Samsung Smart Hub
 *
 * @param   function  callback
 */
tv.prototype.sourceSmartHub = function(callback) {

}

tv.prototype.pictureMode = function(mode, callback) {

}

tv.prototype.setBacklight = function(value, callback) {

}

tv.prototype.setContrast = function(value, callback) {

}

tv.prototype.setBrightness = function(value, callback) {

}

tv.prototype.setSharpness = function(value, callback) {

}

tv.prototype.setColour = function(value, callback) {

}

tv.prototype.setTint = function(value, callback) {

}

tv.prototype.pictureBlackTone = function(mode, callback) {

}

tv.prototype.pictureDynamicContrast = function(mode, callback) {

}

tv.prototype.pictureShadowDetail = function(value, callback) {

}

tv.prototype.picutreGamma = function(value, callback) {

}

tv.prototype.pictureSize = function(size, callback) {

}

tv.prototype.set3DMode = function(mode, callback) {

}

tv.prototype.setSoundMode = function(mode, callback) {

}

tv.prototype.sendKeyDigit = function(value, callback) {

}

tv.prototype.sendKeyOk = function(callback) {

}

tv.prototype.sendKeyExit = function(callback) {

}

tv.prototype.sendKeyReturn = function(callback) {

}

tv.prototype.sendKeyMore = function(callback) {

}

tv.prototype.sendKeyTools = function(callback) {

}

tv.prototype.sendKeyInfo = function(callback) {

}

tv.prototype.sendKeyGuide = function(callback) {

}

tv.prototype.sendKeyMenu = function(callback) {

}

tv.prototype.sendKeyUp = function(callback) {

}

tv.prototype.sendKeyDown = function(callback) {

}

tv.prototype.sendKeyLeft = function(callback) {

}

tv.prototype.sendKeyRight = function(callback) {

}

tv.prototype.sleepMode = function(callback) {

}

tv.prototype.sendKeyRed = function(callback) {

}

tv.prototype.sendKeyGreen = function(callback) {

}

tv.prototype.sendKeyYellow = function(callback) {

}

tv.prototype.sendKeyBlue = function(callback) {

}

tv.prototype.channelList = function(callback) {

}

tv.prototype.getSession = function() {

}

/**
 * Close the serial session
 */
tv.prototype.close = function() {
  this.session.close();
}<|endoftext|>