<commit_before>'use strict';

module.exports = triangulateMountain;

var DoublyLinkedList = require('./dlinkedlist'),
    util = require('./util');

// triangulates a monotone mountain based on `edge`, adding resulting triangles to the `triangles` array

function triangulateMountain(edge, triangles) {

    var list = new DoublyLinkedList(),
        a = edge.p,
        b = edge.q,
        points = edge.mpoints;

    points.sort(compareX);

    list.add(a);
    for (var i = 0; i < points.length; i++) {
        if (util.neq(points[i], list.tail)) list.add(points[i]);
    }
    if (util.neq(b, list.tail)) list.add(b);

    var p = list.head.next;

    if (list.length < 3) return;
    else if (list.length === 3) { triangles.push([a, p, b]); return; }

    // triangles.push(monoPoly(list)); return;

    var convexPoints = [],
        positive = util.cross(p, b, a) > 0;

    while (p !== list.tail) {
        addEar(convexPoints, p, list, positive);
        p = p.next;
    }

    while (convexPoints.length) {
        var ear = convexPoints.shift(),
            prev = ear.prev,
            next = ear.next;

        triangles.push([prev, ear, next]);

        list.remove(ear);

        addEar(convexPoints, prev, list, positive);
        addEar(convexPoints, next, list, positive);
    }
}

function compareX(a, b) {
    return a.x - b.x;
}

function addEar(points, p, list, positive) {
    if (!p.ear && p !== list.head && p !== list.tail && isConvex(p, positive)) {
        p.ear = true;
        points.push(p);
    }
}

function isConvex(p, positive) {
    return positive === (util.cross(p.next, p.prev, p) > 0);
}

// function monoPoly(list) {
//     var poly = [];
//     var p = list.head;
//     while (p) {
//         poly.push(p);
//         p = p.next;
//     }
//     return poly;
// }
<commit_msg>add some simple heuristic optimizations<commit_after>'use strict';

module.exports = triangulateMountain;

var DoublyLinkedList = require('./dlinkedlist'),
    util = require('./util');

// triangulates a monotone mountain based on `edge`, adding resulting triangles to the `triangles` array

function triangulateMountain(edge, triangles) {

    var a = edge.p,
        b = edge.q,
        points = edge.mpoints,
        p = points[0],
        len = points.length;

    if (len === 1 && util.neq(p, a) && util.neq(p, b)) { triangles.push([a, p, b]); return; }

    // silly heuristic optimizations (remove some duplicates before sorting)
    if (len >= 3 && !util.neq(points[len - 1], points[len - 3])) { points.pop(); len--; }
    if (len >= 3 && !util.neq(p, points[2])) points.shift();

    points.sort(compareX);

    var list = new DoublyLinkedList();

    list.add(a);
    for (var i = 0; i < points.length; i++) {
        if (util.neq(points[i], list.tail)) list.add(points[i]);
    }
    if (util.neq(b, list.tail)) list.add(b);

    p = list.head.next;

    if (list.length < 3) return;
    else if (list.length === 3) { triangles.push([a, p, b]); return; }

    // triangles.push(monoPoly(list)); return;

    var convexPoints = [],
        positive = util.cross(p, b, a) > 0;

    while (p !== list.tail) {
        addEar(convexPoints, p, list, positive);
        p = p.next;
    }

    while (convexPoints.length) {
        var ear = convexPoints.shift(),
            prev = ear.prev,
            next = ear.next;

        triangles.push([prev, ear, next]);

        list.remove(ear);

        addEar(convexPoints, prev, list, positive);
        addEar(convexPoints, next, list, positive);
    }
}

function compareX(a, b) {
    return a.x - b.x;
}

function addEar(points, p, list, positive) {
    if (!p.ear && p !== list.head && p !== list.tail && isConvex(p, positive)) {
        p.ear = true;
        points.push(p);
    }
}

function isConvex(p, positive) {
    return positive === (util.cross(p.next, p.prev, p) > 0);
}

// function monoPoly(list) {
//     var poly = [];
//     var p = list.head;
//     while (p) {
//         poly.push(p);
//         p = p.next;
//     }
//     return poly;
// }
<|endoftext|>


<commit_before>// Requiring Librairies
var apiRouter = require('express').Router();
var bodyParser = require('body-parser');
var url = require('url');
var mime = require('mime');
var path = require('path');
var mw = require('dat-middleware');
var flow = require('middleware-flow');
var morgan = require('morgan');
var error = require('debug')('rest-fs:fileserver');
var txtorbin = require('istextorbinary')
var multer = require('multer');
var rimraf = require('rimraf')
var fs = require ("fs")
var slash = require('slash');
var jwt = require('jsonwebtoken');
var cookieParser = require('cookie-parser')
var mkdirp = require("mkdirp")
var exec = require('child_process').exec;

// basics middleware

// CORS
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, token');

    // intercept OPTIONS method
    if ('OPTIONS' == req.method) {
      res.send(200);
    }
    else {
      next();
    }
}

// global conf variables
var conf
var basePath

// Main function
var fileserver = function(app, confArg) {

  // Ensure function arguments
  if (!app || !confArg) {
    throw new Error('express app AND conf object required');
  }

  // populate global var
  conf = confArg
  basePath = path.join(confArg.basePath, confArg.subPath)

  // Multer custom storage place
  var storage = multer.diskStorage({
      destination: function (req, file, cb) {
          var reqPath = decodeURI(url.parse(req.url).pathname)
          var completePath = slash(path.join(basePath,reqPath))

          var newDestination = completePath;
          var stat = null;
          try {
              stat = fs.statSync(newDestination);
          } catch (err) {
              fs.mkdirSync(newDestination);
          }
          if (stat && !stat.isDirectory()) {
              throw new Error('Directory cannot be created because an inode of a different type exists at "' + dest + '"');
          }
          cb(null, newDestination);
      }
  });

  // upload middleware

  var upload = multer(
      {
          dest: '/',
          storage: storage
      }
  );

  // Prepare request
  app.use(allowCrossDomain);
  app.use(cookieParser())
  app.use(bodyParser.json());

  // health
  apiRouter.get('/health-check', healthCheck)

  // Logs
  apiRouter.use(morgan('tiny'));

  // Login
  apiRouter.post('/login', login)

  // Protect following routes
  apiRouter.use(filter)
  apiRouter.use(checkAuth)

  apiRouter.post('/exec', execute)

  // Routes
  apiRouter.get('/*', getFileOrFolder)
  apiRouter.post("/*", upload.single("file"), postFileOrDir)
  apiRouter.put("/*", putFileOrDir)
  apiRouter.delete('/*', delFileOrFolder)

  // Link api endpoint and return router
  app.use("/api", apiRouter)
  return app;
};

// controller routes

// Health Check
function healthCheck (req, res, next) {
  return res.json({success : true, message:"Api is online"})
}

// Auth
function checkAuth (req, res, next) {
  if(!conf.users) return next()
  token = req.headers.token || req.cookies.token
  if (!token) return res.status(401).json({error : true, message : "token not present or invalid"})
    // invalid token
  jwt.verify(token, conf.jwtSecret, function(err, decoded) {
  if (err) return res.status(401).json({error : true, message : "token invalid"})
    return next()
  });
}

// Login
function login (req, res, next){
  var creds = req.body
  var users = conf.users

  if(!users) res.status(200).json({success: true})

  var id = users.findIndex(user => user.username == creds.username && user.password == creds.password)
  if(id == -1) return res.status(401).json({error : true, message : "wrong credentials"})
  else {
    jwt.sign({username : users[id].username}, conf.jwtSecret, { algorithm: 'HS256' }, (err, token) => {
      if(err) return res.json(err)
      return res.json({success : true, token : token})
    })
  }

}

// Filter file
function filter(req,res,next){
  var reqPath = decodeURI(url.parse(req.url).pathname)
  var name = req.body.name || ""
  var completePath = slash(path.join(basePath,reqPath, name))

  if(filterFile(completePath)) return next()
  else return res.status(403).json({error : true, message : "Type disabled"})

}

// Get
var getFileOrFolder = function (req, res, next) {

  var reqPath = decodeURI(url.parse(req.url).pathname)
  var topPath = path.dirname(reqPath)
  var name = path.basename(reqPath)
  var completePath = slash(path.join(basePath,reqPath))
  var mimeType

  var content
  var fileList = []

  try{
    type = fs.lstatSync(completePath).isDirectory()?"directory":"file"
    if(type == "file"){
      mimeType = mime.lookup(completePath);
      if(txtorbin.isTextSync(completePath)){
        content=fs.readFileSync(completePath, "utf8")
      }
    }else{
      files = fs.readdirSync(completePath)
      for (let file of files){
        let name = file
        let topPath = reqPath
        let mimeType
        let type = fs.lstatSync( path.join(basePath,topPath,name) ).isDirectory()?"directory":"file"
        if(type == "file") mimeType = mime.lookup( path.join(basePath,topPath,name) );
        if(filterFile(path.join(basePath,topPath,name))) fileList.push({name , topPath, type, mimeType })
      }
    }
    // Option to download or get the raw file
    if(type == "file" && req.query.option == "download") return res.download(completePath)
    if(type == "file" && req.query.option == "raw") return res.sendFile(path.join(completePath))
    // Return JSON of file object
    return res.json({ topPath, name, type, fileList, content, mimeType})
  }catch(err){
    return res.status(400).json({err})
  }

}

// Post
var postFileOrDir = function (req, res, next) {

  var reqPath = decodeURI(url.parse(req.url).pathname)
  var topPath = path.dirname(reqPath)
  var name = req.body.name || ""
  var isDir = name && name.substr(-1) === '/' || false;
  var completePath = slash(path.join(basePath,reqPath, name))
  var mimeType

  mkdirp.sync(path.dirname(completePath))

  if(req.file){
    var file = req.file
    fs.renameSync(path.join(file.destination,file.filename), path.join(file.destination, file.originalname))
    return res.json({name : file.originalname, mimeType : mime.lookup(file.originalname), type:"file" })
  }

  if (isDir) {
    name = name.slice(0,-1)
    try {
      fs.mkdirSync(completePath);
    } catch(e) {
      if ( e.code != 'EEXIST' ) console.log("allready exists")
    }
  }
  else {
    try {
      fs.writeFileSync(completePath, req.body.content || "");
    } catch(e) {
      if ( e.code != 'EEXIST' ) console.log("allready exists")
    }
  }

  res.status(201).json({name, mimeType : isDir ? undefined : mime.lookup(name), type : isDir?"directory":"file", topPath})
};

// Put
var putFileOrDir = function (req, res, next) {
  var reqPath = decodeURI(url.parse(req.url).pathname)
  var topPath = path.dirname(reqPath)
  var name = path.basename(reqPath)
  var completePath = slash(path.join(basePath,reqPath))

  var body = req.body

  try{
    type = fs.lstatSync(completePath).isDirectory()?"directory":"file"
    if(type == "file" && body.content){
      fs.writeFileSync(completePath, body.content, "utf8")
    }
    if(body.name){
      fs.rename(completePath, path.join(basePath, topPath, body.name))
    }
    return res.json({ success : true})
  }catch(err){
    return res.status(400).json({err})
  }
};

// Delete
var delFileOrFolder = function (req, res, next) {
  var reqPath = decodeURI(url.parse(req.url).pathname)
  var topPath = path.dirname(reqPath)
  var name = path.basename(reqPath)
  var completePath = slash(path.join(basePath,reqPath))

  var body = req.body

  try{
    rimraf(completePath, ()=>{
      return res.json({ success : true})
    })
  }catch(err){
    return res.status(400).json({err})
  }
};

// Exec
var execute = function (req, res, next) {
  if(!req.body.command) {
    console.log("No command to execute")
    return res.json({success : false})
  } else {
    console.log("Executed command", req.body.command)
    exec(`cd ${path.join(basePath, req.body.path||"")} && `+req.body.command, (er, so, se)=>{
      console.log(er || so || se)
      if(er || se) return res.json({success : false})
      else return res.json({success : true})
    });
  }
};

module.exports = fileserver;

function filterFile(path){
  path = slash(path)
  if(!conf.exclusions || !conf.exclusions.length) return true
  for (let exp of conf.exclusions){
    let reg = new RegExp(exp)
    if(reg.test(path)) return false
  }
  return true
}
<commit_msg>toml mime added<commit_after>// Requiring Librairies
var apiRouter = require('express').Router();
var bodyParser = require('body-parser');
var url = require('url');
var mime = require('mime');
var path = require('path');
var mw = require('dat-middleware');
var flow = require('middleware-flow');
var morgan = require('morgan');
var error = require('debug')('rest-fs:fileserver');
var txtorbin = require('istextorbinary')
var multer = require('multer');
var rimraf = require('rimraf')
var fs = require ("fs")
var slash = require('slash');
var jwt = require('jsonwebtoken');
var cookieParser = require('cookie-parser')
var mkdirp = require("mkdirp")
var exec = require('child_process').exec;

mime.define({
    'text/x-toml': ['toml']
});

// basics middleware

// CORS
var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, token');

    // intercept OPTIONS method
    if ('OPTIONS' == req.method) {
      res.send(200);
    }
    else {
      next();
    }
}

// global conf variables
var conf
var basePath

// Main function
var fileserver = function(app, confArg) {

  // Ensure function arguments
  if (!app || !confArg) {
    throw new Error('express app AND conf object required');
  }

  // populate global var
  conf = confArg
  basePath = path.join(confArg.basePath, confArg.subPath)

  // Multer custom storage place
  var storage = multer.diskStorage({
      destination: function (req, file, cb) {
          var reqPath = decodeURI(url.parse(req.url).pathname)
          var completePath = slash(path.join(basePath,reqPath))

          var newDestination = completePath;
          var stat = null;
          try {
              stat = fs.statSync(newDestination);
          } catch (err) {
              fs.mkdirSync(newDestination);
          }
          if (stat && !stat.isDirectory()) {
              throw new Error('Directory cannot be created because an inode of a different type exists at "' + dest + '"');
          }
          cb(null, newDestination);
      }
  });

  // upload middleware

  var upload = multer(
      {
          dest: '/',
          storage: storage
      }
  );

  // Prepare request
  app.use(allowCrossDomain);
  app.use(cookieParser())
  app.use(bodyParser.json());

  // health
  apiRouter.get('/health-check', healthCheck)

  // Logs
  apiRouter.use(morgan('tiny'));

  // Login
  apiRouter.post('/login', login)

  // Protect following routes
  apiRouter.use(filter)
  apiRouter.use(checkAuth)

  apiRouter.post('/exec', execute)

  // Routes
  apiRouter.get('/*', getFileOrFolder)
  apiRouter.post("/*", upload.single("file"), postFileOrDir)
  apiRouter.put("/*", putFileOrDir)
  apiRouter.delete('/*', delFileOrFolder)

  // Link api endpoint and return router
  app.use("/api", apiRouter)
  return app;
};

// controller routes

// Health Check
function healthCheck (req, res, next) {
  return res.json({success : true, message:"Api is online"})
}

// Auth
function checkAuth (req, res, next) {
  if(!conf.users) return next()
  token = req.headers.token || req.cookies.token
  if (!token) return res.status(401).json({error : true, message : "token not present or invalid"})
    // invalid token
  jwt.verify(token, conf.jwtSecret, function(err, decoded) {
  if (err) return res.status(401).json({error : true, message : "token invalid"})
    return next()
  });
}

// Login
function login (req, res, next){
  var creds = req.body
  var users = conf.users

  if(!users) res.status(200).json({success: true})

  var id = users.findIndex(user => user.username == creds.username && user.password == creds.password)
  if(id == -1) return res.status(401).json({error : true, message : "wrong credentials"})
  else {
    jwt.sign({username : users[id].username}, conf.jwtSecret, { algorithm: 'HS256' }, (err, token) => {
      if(err) return res.json(err)
      return res.json({success : true, token : token})
    })
  }

}

// Filter file
function filter(req,res,next){
  var reqPath = decodeURI(url.parse(req.url).pathname)
  var name = req.body.name || ""
  var completePath = slash(path.join(basePath,reqPath, name))

  if(filterFile(completePath)) return next()
  else return res.status(403).json({error : true, message : "Type disabled"})

}

// Get
var getFileOrFolder = function (req, res, next) {

  var reqPath = decodeURI(url.parse(req.url).pathname)
  var topPath = path.dirname(reqPath)
  var name = path.basename(reqPath)
  var completePath = slash(path.join(basePath,reqPath))
  var mimeType

  var content
  var fileList = []

  try{
    type = fs.lstatSync(completePath).isDirectory()?"directory":"file"
    if(type == "file"){
      mimeType = mime.lookup(completePath);
      if(txtorbin.isTextSync(completePath)){
        content=fs.readFileSync(completePath, "utf8")
      }
    }else{
      files = fs.readdirSync(completePath)
      for (let file of files){
        let name = file
        let topPath = reqPath
        let mimeType
        let type = fs.lstatSync( path.join(basePath,topPath,name) ).isDirectory()?"directory":"file"
        if(type == "file") mimeType = mime.lookup( path.join(basePath,topPath,name) );
        if(filterFile(path.join(basePath,topPath,name))) fileList.push({name , topPath, type, mimeType })
      }
    }
    // Option to download or get the raw file
    if(type == "file" && req.query.option == "download") return res.download(completePath)
    if(type == "file" && req.query.option == "raw") return res.sendFile(path.join(completePath))
    // Return JSON of file object
    return res.json({ topPath, name, type, fileList, content, mimeType})
  }catch(err){
    return res.status(400).json({err})
  }

}

// Post
var postFileOrDir = function (req, res, next) {

  var reqPath = decodeURI(url.parse(req.url).pathname)
  var topPath = path.dirname(reqPath)
  var name = req.body.name || ""
  var isDir = name && name.substr(-1) === '/' || false;
  var completePath = slash(path.join(basePath,reqPath, name))
  var mimeType

  mkdirp.sync(path.dirname(completePath))

  if(req.file){
    var file = req.file
    fs.renameSync(path.join(file.destination,file.filename), path.join(file.destination, file.originalname))
    return res.json({name : file.originalname, mimeType : mime.lookup(file.originalname), type:"file" })
  }

  if (isDir) {
    name = name.slice(0,-1)
    try {
      fs.mkdirSync(completePath);
    } catch(e) {
      if ( e.code != 'EEXIST' ) console.log("allready exists")
    }
  }
  else {
    try {
      fs.writeFileSync(completePath, req.body.content || "");
    } catch(e) {
      if ( e.code != 'EEXIST' ) console.log("allready exists")
    }
  }

  res.status(201).json({name, mimeType : isDir ? undefined : mime.lookup(name), type : isDir?"directory":"file", topPath})
};

// Put
var putFileOrDir = function (req, res, next) {
  var reqPath = decodeURI(url.parse(req.url).pathname)
  var topPath = path.dirname(reqPath)
  var name = path.basename(reqPath)
  var completePath = slash(path.join(basePath,reqPath))

  var body = req.body

  try{
    type = fs.lstatSync(completePath).isDirectory()?"directory":"file"
    if(type == "file" && body.content){
      fs.writeFileSync(completePath, body.content, "utf8")
    }
    if(body.name){
      fs.rename(completePath, path.join(basePath, topPath, body.name))
    }
    return res.json({ success : true})
  }catch(err){
    return res.status(400).json({err})
  }
};

// Delete
var delFileOrFolder = function (req, res, next) {
  var reqPath = decodeURI(url.parse(req.url).pathname)
  var topPath = path.dirname(reqPath)
  var name = path.basename(reqPath)
  var completePath = slash(path.join(basePath,reqPath))

  var body = req.body

  try{
    rimraf(completePath, ()=>{
      return res.json({ success : true})
    })
  }catch(err){
    return res.status(400).json({err})
  }
};

// Exec
var execute = function (req, res, next) {
  if(!req.body.command) {
    console.log("No command to execute")
    return res.json({success : false})
  } else {
    console.log("Executed command", req.body.command)
    exec(`cd ${path.join(basePath, req.body.path||"")} && `+req.body.command, (er, so, se)=>{
      console.log(er || so || se)
      if(er || se) return res.json({success : false})
      else return res.json({success : true})
    });
  }
};

module.exports = fileserver;

function filterFile(path){
  path = slash(path)
  if(!conf.exclusions || !conf.exclusions.length) return true
  for (let exp of conf.exclusions){
    let reg = new RegExp(exp)
    if(reg.test(path)) return false
  }
  return true
}
<|endoftext|>


<commit_before>Google = {};

// https://developers.google.com/accounts/docs/OAuth2Login#userinfocall
Google.whitelistedFields = ['id', 'email', 'verified_email', 'name', 'given_name',
                   'family_name', 'picture', 'locale', 'timezone', 'gender'];

OAuth.registerService('google', 2, null, function(query) {

  var response = getTokens(query);
  var accessToken = response.accessToken;
  var idToken = response.idToken;
  var identity = getIdentity(accessToken);

  var serviceData = {
    accessToken: accessToken,
    idToken: idToken,
    expiresAt: (+new Date) + (1000 * response.expiresIn)
  };

  var fields = _.pick(identity, Google.whitelistedFields);
  _.extend(serviceData, fields);

  // only set the token in serviceData if it's there. this ensures
  // that we don't lose old ones (since we only get this on the first
  // log in attempt)
  if (response.refreshToken)
    serviceData.refreshToken = response.refreshToken;

  return {
    serviceData: serviceData,
    options: {profile: {name: identity.name}}
  };
});

// returns an object containing:
// - accessToken
// - expiresIn: lifetime of token in seconds
// - refreshToken, if this is the first authorization request
var getTokens = function (query) {
  var config = ServiceConfiguration.configurations.findOne({service: 'google'});
  if (!config)
    throw new ServiceConfiguration.ConfigError();

  var response;
  try {
    response = HTTP.post(
      "https://accounts.google.com/o/oauth2/token", {params: {
        code: query.code,
        client_id: config.clientId,
        client_secret: OAuth.openSecret(config.secret),
        redirect_uri: OAuth._redirectUri('google', config),
        grant_type: 'authorization_code'
      }});
  } catch (err) {
    throw _.extend(new Error("Failed to complete OAuth handshake with Google. " + err.message),
                   {response: err.response});
  }

  if (response.data.error) { // if the http response was a json object with an error attribute
    throw new Error("Failed to complete OAuth handshake with Google. " + response.data.error);
  } else {
    return {
      accessToken: response.data.access_token,
      refreshToken: response.data.refresh_token,
      expiresIn: response.data.expires_in,
      idToken: response.data.id_token
    };
  }
};

var getIdentity = function (accessToken) {
  try {
    return HTTP.get(
      "https://www.googleapis.com/oauth2/v1/userinfo",
      {params: {access_token: accessToken}}).data;
  } catch (err) {
    throw _.extend(new Error("Failed to fetch identity from Google. " + err.message),
                   {response: err.response});
  }
};

Google.retrieveCredential = function(credentialToken, credentialSecret) {
  return OAuth.retrieveCredential(credentialToken, credentialSecret);
};
<commit_msg>support google oauth from installed clients (different google client id from server)<commit_after>Google = {};

// https://developers.google.com/accounts/docs/OAuth2Login#userinfocall
Google.whitelistedFields = ['id', 'email', 'verified_email', 'name', 'given_name',
                   'family_name', 'picture', 'locale', 'timezone', 'gender'];

OAuth.registerService('google', 2, null, function(query) {

  var response = getTokens(query);
  var accessToken = response.accessToken;
  var idToken = response.idToken;
  var identity = getIdentity(accessToken);

  var serviceData = {
    accessToken: accessToken,
    idToken: idToken,
    expiresAt: (+new Date) + (1000 * response.expiresIn)
  };

  var fields = _.pick(identity, Google.whitelistedFields);
  _.extend(serviceData, fields);

  // only set the token in serviceData if it's there. this ensures
  // that we don't lose old ones (since we only get this on the first
  // log in attempt)
  if (response.refreshToken)
    serviceData.refreshToken = response.refreshToken;

  return {
    serviceData: serviceData,
    options: {profile: {name: identity.name}}
  };
});

// returns an object containing:
// - accessToken
// - expiresIn: lifetime of token in seconds
// - refreshToken, if this is the first authorization request
var getTokens = function (query) {
  var config = ServiceConfiguration.configurations.findOne({service: 'google'});
  if (!config)
    throw new ServiceConfiguration.ConfigError();

  var response;
  try {
    response = HTTP.post(
      "https://accounts.google.com/o/oauth2/token", {params: {
        code: query.code,
        client_id: config.clientId,
        client_secret: OAuth.openSecret(config.secret),
        redirect_uri: query.installedClient ? '' : OAuth._redirectUri('google', config),
        grant_type: 'authorization_code'
      }});
  } catch (err) {
    throw _.extend(new Error("Failed to complete OAuth handshake with Google. " + err.message),
                   {response: err.response});
  }

  if (response.data.error) { // if the http response was a json object with an error attribute
    throw new Error("Failed to complete OAuth handshake with Google. " + response.data.error);
  } else {
    return {
      accessToken: response.data.access_token,
      refreshToken: response.data.refresh_token,
      expiresIn: response.data.expires_in,
      idToken: response.data.id_token
    };
  }
};

var getIdentity = function (accessToken) {
  try {
    return HTTP.get(
      "https://www.googleapis.com/oauth2/v1/userinfo",
      {params: {access_token: accessToken}}).data;
  } catch (err) {
    throw _.extend(new Error("Failed to fetch identity from Google. " + err.message),
                   {response: err.response});
  }
};

Google.retrieveCredential = function(credentialToken, credentialSecret) {
  return OAuth.retrieveCredential(credentialToken, credentialSecret);
};
<|endoftext|>


<commit_before>import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Header from './../app/header';
import {
  getFeedContent,
  getMoreFeedContent,
  getUserFeedContent,
  getMoreUserFeedContent,
} from './../feed/feedActions';

@connect(
  state => ({
    feed: state.feed,
    posts: state.posts,
  }),
  dispatch => bindActionCreators({
    getFeedContent,
    getMoreFeedContent,
  }, dispatch)
)
export default class UserProfile extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const { auth, feed, posts } = this.props;
    const account = auth.user && auth.user.name;

    return (

        { auth.isFetching ?

Logging in...

          :

            { React.cloneElement(
              this.props.children,
              {
                feed,
                posts,
                getFeedContent,
                getMoreFeedContent,
              }
            ) }

        }

    );
  }
}
<commit_msg>get actions from props<commit_after>import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Header from './../app/header';
import {
  getFeedContent,
  getMoreFeedContent,
  getUserFeedContent,
  getMoreUserFeedContent,
} from './../feed/feedActions';

@connect(
  state => ({
    feed: state.feed,
    posts: state.posts,
  }),
  dispatch => bindActionCreators({
    getFeedContent,
    getMoreFeedContent,
  }, dispatch)
)
export default class UserProfile extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const { auth, feed, posts, getFeedContent, getMoreFeedContent } = this.props;
    const account = auth.user && auth.user.name;

    return (

        { auth.isFetching ?

Logging in...

          :

            { React.cloneElement(
              this.props.children,
              {
                feed,
                posts,
                getFeedContent,
                getMoreFeedContent,
                limit: 10
              }
            ) }

        }

    );
  }
}
<|endoftext|>


<commit_before>// ==========================================
// Begin Kitten Scientist's Automation Engine
// ==========================================

var version = 'Kitten Scientists version 1.1.5';
var game = gamePage;

var options = {
    interval: 3000,
    color: '#aa50fe', // dark purple
    amount: {
        consume: 0.5
    },
    auto: {
        build: [
            {name: 'field', require: 'catnip'},
            {name: 'pasture', require: 'catnip'},
            {name: 'mine', require: 'wood'},
            {name: 'library', require: 'wood'},
            {name: 'academy', require: 'wood'},
            {name: 'barn', require: 'wood'},
            {name: 'workshop', require: 'minerals'},
            {name: 'lumberMill', require: 'minerals'},
            {name: 'aqueduct', require: 'minerals'},
            {name: 'unicornPasture', require: false},
            {name: 'tradepost', require: 'gold'}
        ],
        craft: [
            {name: 'wood', require: 'catnip'},
            {name: 'beam', require: 'wood'},
            {name: 'slab', require: 'minerals'},
            {name: 'steel', require: 'coal'},
            {name: 'plate', require: 'iron'}
        ],
        house: [
            {name: 'hut', require: 'wood'},
            {name: 'logHouse', require: 'minerals'},
            {name: 'mansion', require: 'titanium'}
        ],
        luxury: [
            {name: 'manuscript', require: 'culture'},
            {name: 'compendium', require: 'science'}
        ]
    },
    limit: {
        build: 0.75,
        craft: 0.95,
        house: 0.85,
        hunt: 0.95,
        luxury: 0.99,
        faith: 0.99
    },
    stock: {
        compendium: 500,
        manuscript: 500,
        parchment: 500
    },
    toggle: {
        building: true,
        crafting: true,
        housing: true,
        hunting: true,
        luxury: true,
        praising: true
    }
};

// GameLog Modification
// ====================

var gameLog = com.nuclearunicorn.game.log.Console().static;

var message = function () {
    var args = Array.prototype.slice.call(arguments);
    args[1] = args[1] || 'ks-default';

    // update the color of the message immediately after adding
    gameLog.msg.apply(gameLog, args);
    $('.type_' + args[1]).css('color', options.color);
};

// Core Engine for Kitten Scientists
// =================================

var Engine = function () {
    this.buildManager = new BuildManager();
    this.craftManager = new CraftManager();
};

Engine.prototype = {
    buildManager: undefined,
    craftManager: undefined,
    loop: undefined,
    start: function () {
        if (this.loop) return;

        this.loop = setInterval(this.iterate.bind(this), options.interval);
        message('Starting the kitten scientists!');
    },
    stop: function () {
        if (!this.loop) return;

        clearInterval(this.loop);
        this.loop = undefined;
        message('Freezing the kitten scientists!');
    },
    iterate: function () {
        this.observeGameLog();
        if (options.toggle.praising) this.praiseSun();
        if (options.toggle.hunting) this.sendHunters();
        if (options.toggle.crafting) this.startCrafts('craft', options.auto.craft);
        if (options.toggle.building) this.startBuilds('build', options.auto.build);
        if (options.toggle.housing) this.startBuilds('house', options.auto.house);
    },
    observeGameLog: function () {
        $('#gameLog').find('input').click();
    },
    praiseSun: function () {
        var currentTab = game.activeTabId;
        var faith = this.craftManager.getResource('faith');

        if (faith.value / faith.maxValue >= options.limit.faith) {
            game.activeTabId = 'Religion';
            game.render();

            message('The sun has been praised!');
            $(".nosel:contains('Praise the sun!')").click();

            game.activeTabId = currentTab;
            game.render();
        }
    },
    sendHunters: function () {
        var catpower = this.craftManager.getResource('manpower');
        var workshop = game.workshop;
        var parchment = workshop.getCraft('parchment');

        if (catpower.value / catpower.maxValue > options.limit.hunt) {
            if (parchment.unlocked) {
                game.craftAll(parchment.name);
                message('Auto Hunt: crafted all parchments');
            }

            if (options.toggle.luxury) this.startCrafts('luxury', options.auto.luxury);

            message('Kittens Hunt: Hunters deployed!');
            $("a:contains('Send hunters')").click();
        }
    },
    startBuilds: function (type, builds) {
        var buildManager = this.buildManager;
        var craftManager = this.craftManager;
        var limit = options.limit[type];

        for (i in builds) {
            var build = builds[i];
            var require = !build.require ? !build.require : craftManager.getResource(build.require);

            if (require === true || limit <= require.value / require.maxValue) {
                buildManager.build(build.name);
            }
        }
    },
    startCrafts: function (type, crafts) {
        var limit = options.limit[type];
        var manager = this.craftManager;

        for (i in crafts) {
            var craft = crafts[i];
            var require = manager.getResource(craft.require);

            if (limit <= require.value / require.maxValue) {
                manager.craft(craft.name, manager.getLowestCraftAmount(craft.name));
            }
        }
    }
};

// Building manager
// ================

var BuildManager = function () {
    this.craftManager = new CraftManager();
};

BuildManager.prototype = {
    craftManager: undefined,
    build: function (name) {
        if (!this.isBuildable(name)) return;

        var label = this.getBuild(name).label;
        var button = $(".nosel:not('.disabled'):contains('" + label + "')");

        if (button.length === 0) return;

        button.click();
        message('Kittens Build: +1 ' + label);
    },
    isBuildable: function (name) {
        var buildable = this.getBuild(name).unlocked;

        if (buildable) {
            var manager = this.craftManager;
            var prices = this.getPrices(name);

            for (i in prices) {
                var price = prices[i];

                if (manager.getValueAvailable(price.name) < price.val) {
                    buildable = false;
                }
            }
        }

        return buildable;
    },
    getBuild: function (name) {
        return game.bld.getBuilding(name);
    },
    getPrices: function (name) {
        return game.bld.getPrices(name);
    }
};

// Crafting Manager
// ================

var CraftManager = function () {};

CraftManager.prototype = {
    craft: function (name, amount) {
        amount = Math.floor(amount);

        if (undefined === name || 1 > amount) return;
        if (!this.canCraft(name, amount)) return;

        var craft = this.getCraft(name);
        var ratio = ('wood' === name) ? 'refineRatio' : 'craftRatio';

        game.craft(craft.name, amount);

        // determine actual amount after crafting upgrades
        amount = (amount * (game.bld.getEffect(ratio) + 1)).toFixed(2);

        message('Kittens Craft: +' + amount + ' ' + name);
    },
    canCraft: function (name, amount) {
        var craft = this.getCraft(name);
        var result = false;

        if (craft.unlocked) {
            result = true;

            for (i in craft.prices) {
                var price = craft.prices[i];
                var value = this.getValueAvailable(price.name);

                if (value < price.val * amount) {
                    result = false;
                }
            }
        }

        return result;
    },
    getCraft: function (name) {
        // adjust for spelling bug in core game logic
        if ('compendium' === name) name = 'compedium';

        return game.workshop.getCraft(name);
    },
    getLowestCraftAmount: function (name) {
        var amount = 0;
        var consume = options.amount.consume;
        var materials = this.getMaterials(name);

        for (i in materials) {
            var total = this.getValueAvailable(i) * consume / materials[i];

            amount = (0 === amount || total < amount) ? total : amount;
        }

        return amount;
    },
    getMaterials: function (name) {
        var materials = {};
        var prices = this.getCraft(name).prices;

        for (i in prices) {
            var price = prices[i];

            materials[price.name] = price.val;
        }

        return materials;
    },
    getResource: function (name) {
        // adjust for spelling bug in core game logic
        if ('compendium' === name) name = 'compedium';

        return game.resPool.get(name);
    },
    getValue: function (name) {
        return this.getResource(name).value;
    },
    getValueAvailable: function (name) {
        var value = this.getValue(name);
        var stock = options.stock[name] || 0;

        if ('catnip' === name) {
            var resPerTick = game.getResourcePerTick(name, false, {
                modifiers: {
                    'catnip': 0.10 - game.calendar.getWeatherMod()
                }});

            if (resPerTick < 0) stock -= resPerTick * 202 * 5;
        }

        return value - stock;
    }
};

// ==============================
// Configure overall page display
// ==============================

var container = $('#game');
var column = $('.column');

container.css({
    fontFamily: 'Courier New',
    fontSize: '12px',
    minWidth: '1300px',
    top: '32px'
});

column.css({
    minHeight: 'inherit',
    maxWidth: 'inherit',
    padding: '1%',
    margin: 0
});

var left = $('#leftColumn');
var middle = $('#midColumn');
var right = $('#rightColumn');

left.css({
    height: '92%',
    width: '26%'
});

middle.css({
    marginTop: '1%',
    height: '92%',
    width: '48%'
});

right.css({
    height: '92%',
    width: '19%'
});

// Reconfigure dynamic page display
// ================================

var addRule = function (rule) {
    var sheets = document.styleSheets;
    sheets[0].insertRule(rule, 1);
};

addRule('#gameLog .msg {'
+ 'display: block;'
+ '}');

addRule('#resContainer .maxRes {'
+ 'color: #676766;'
+ '}');

addRule('#game .btn {'
+ 'border-radius: 0px;'
+ 'font-family: "Courier New";'
+ 'font-size: "10px";'
+ 'margin: 0 0 7px 0;'
+ '}');

addRule('#ks-options ul {'
+ 'list-style: none;'
+ 'margin: 0 0 5px;'
+ 'padding: 0;'
+ '}');

addRule('#ks-options ul:after {'
+ 'clear: both;'
+ 'content: " ";'
+ 'display: block;'
+ 'height: 0;'
+ '}');

addRule('#ks-options ul li {'
+ 'display: block;'
+ 'float: left;'
+ 'width: 50%;'
+ '}');

// Add options element
// ===================

var getToggle = function (name, text) {
    var li = $('<li/>');

    var label = $('<label/>', {
        'for': 'toggle-' + name,
        text: text
    });

    var toggle = $('<input/>', {
        id: 'toggle-' + name,
        type: 'checkbox',
        checked: 'checked'
    });

    return li.append(toggle, label);
};

var optionsElement = $('<div/>', {id: 'ks-options', css: {marginBottom: '10px'}});
var optionsListElement = $('<ul/>');
var optionsTitleElement = $('<div/>', {
    css: { borderBottom: '1px solid gray', marginBottom: '5px' },
    text: version
});

optionsElement.append(optionsTitleElement);

optionsListElement.append(getToggle('engine', 'Engine').css('width', '100%'));
optionsListElement.append(getToggle('crafting', 'Crafting'));
optionsListElement.append(getToggle('housing', 'Housing'));
optionsListElement.append(getToggle('building', 'Building'));
optionsListElement.append(getToggle('praising', 'Faith'));
optionsListElement.append(getToggle('hunting', 'Hunting'));
optionsListElement.append(getToggle('luxury', 'Luxury'));

// add the options above the game log
right.prepend(optionsElement.append(optionsListElement));

// Initialize and set toggles for Engine
// =====================================

var engine = new Engine();
var toggleEngine = $('#toggle-engine');

toggleEngine.on('change', function () {
    if (toggleEngine.is(':checked')) {
        engine.start();
    } else {
        engine.stop();
    }
});

toggleEngine.trigger('change');

// Add toggles for options
// =======================

var autoOptions = ['building', 'crafting', 'housing', 'hunting', 'luxury', 'praising'];

var ucfirst = function (string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
};

$.each(autoOptions, function (event, option) {
    var toggle = $('#toggle-' + option);

    toggle.on('change', function () {
        if (toggle.is(':checked')) {
            options.toggle[option] = true;
            message('Enabled Auto ' + ucfirst(option));
        } else {
            options.toggle[option] = false;
            message('Disable Auto ' + ucfirst(option));
        }
    });
});
<commit_msg>general: Move 'Crafting' to after 'Building' and 'Housing'<commit_after>// ==========================================
// Begin Kitten Scientist's Automation Engine
// ==========================================

var version = 'Kitten Scientists version 1.1.5';
var game = gamePage;

var options = {
    interval: 3000,
    color: '#aa50fe', // dark purple
    amount: {
        consume: 0.5
    },
    auto: {
        build: [
            {name: 'field', require: 'catnip'},
            {name: 'pasture', require: 'catnip'},
            {name: 'mine', require: 'wood'},
            {name: 'library', require: 'wood'},
            {name: 'academy', require: 'wood'},
            {name: 'barn', require: 'wood'},
            {name: 'workshop', require: 'minerals'},
            {name: 'lumberMill', require: 'minerals'},
            {name: 'aqueduct', require: 'minerals'},
            {name: 'unicornPasture', require: false},
            {name: 'tradepost', require: 'gold'}
        ],
        craft: [
            {name: 'wood', require: 'catnip'},
            {name: 'beam', require: 'wood'},
            {name: 'slab', require: 'minerals'},
            {name: 'steel', require: 'coal'},
            {name: 'plate', require: 'iron'}
        ],
        house: [
            {name: 'hut', require: 'wood'},
            {name: 'logHouse', require: 'minerals'},
            {name: 'mansion', require: 'titanium'}
        ],
        luxury: [
            {name: 'manuscript', require: 'culture'},
            {name: 'compendium', require: 'science'}
        ]
    },
    limit: {
        build: 0.75,
        craft: 0.95,
        house: 0.85,
        hunt: 0.95,
        luxury: 0.99,
        faith: 0.99
    },
    stock: {
        compendium: 500,
        manuscript: 500,
        parchment: 500
    },
    toggle: {
        building: true,
        crafting: true,
        housing: true,
        hunting: true,
        luxury: true,
        praising: true
    }
};

// GameLog Modification
// ====================

var gameLog = com.nuclearunicorn.game.log.Console().static;

var message = function () {
    var args = Array.prototype.slice.call(arguments);
    args[1] = args[1] || 'ks-default';

    // update the color of the message immediately after adding
    gameLog.msg.apply(gameLog, args);
    $('.type_' + args[1]).css('color', options.color);
};

// Core Engine for Kitten Scientists
// =================================

var Engine = function () {
    this.buildManager = new BuildManager();
    this.craftManager = new CraftManager();
};

Engine.prototype = {
    buildManager: undefined,
    craftManager: undefined,
    loop: undefined,
    start: function () {
        if (this.loop) return;

        this.loop = setInterval(this.iterate.bind(this), options.interval);
        message('Starting the kitten scientists!');
    },
    stop: function () {
        if (!this.loop) return;

        clearInterval(this.loop);
        this.loop = undefined;
        message('Freezing the kitten scientists!');
    },
    iterate: function () {
        this.observeGameLog();
        if (options.toggle.praising) this.praiseSun();
        if (options.toggle.hunting) this.sendHunters();
        if (options.toggle.building) this.startBuilds('build', options.auto.build);
        if (options.toggle.housing) this.startBuilds('house', options.auto.house);
        if (options.toggle.crafting) this.startCrafts('craft', options.auto.craft);
    },
    observeGameLog: function () {
        $('#gameLog').find('input').click();
    },
    praiseSun: function () {
        var currentTab = game.activeTabId;
        var faith = this.craftManager.getResource('faith');

        if (faith.value / faith.maxValue >= options.limit.faith) {
            game.activeTabId = 'Religion';
            game.render();

            message('The sun has been praised!');
            $(".nosel:contains('Praise the sun!')").click();

            game.activeTabId = currentTab;
            game.render();
        }
    },
    sendHunters: function () {
        var catpower = this.craftManager.getResource('manpower');
        var workshop = game.workshop;
        var parchment = workshop.getCraft('parchment');

        if (catpower.value / catpower.maxValue > options.limit.hunt) {
            if (parchment.unlocked) {
                game.craftAll(parchment.name);
                message('Auto Hunt: crafted all parchments');
            }

            if (options.toggle.luxury) this.startCrafts('luxury', options.auto.luxury);

            message('Kittens Hunt: Hunters deployed!');
            $("a:contains('Send hunters')").click();
        }
    },
    startBuilds: function (type, builds) {
        var buildManager = this.buildManager;
        var craftManager = this.craftManager;
        var limit = options.limit[type];

        for (i in builds) {
            var build = builds[i];
            var require = !build.require ? !build.require : craftManager.getResource(build.require);

            if (require === true || limit <= require.value / require.maxValue) {
                buildManager.build(build.name);
            }
        }
    },
    startCrafts: function (type, crafts) {
        var limit = options.limit[type];
        var manager = this.craftManager;

        for (i in crafts) {
            var craft = crafts[i];
            var require = manager.getResource(craft.require);

            if (limit <= require.value / require.maxValue) {
                manager.craft(craft.name, manager.getLowestCraftAmount(craft.name));
            }
        }
    }
};

// Building manager
// ================

var BuildManager = function () {
    this.craftManager = new CraftManager();
};

BuildManager.prototype = {
    craftManager: undefined,
    build: function (name) {
        if (!this.isBuildable(name)) return;

        var label = this.getBuild(name).label;
        var button = $(".nosel:not('.disabled'):contains('" + label + "')");

        if (button.length === 0) return;

        button.click();
        message('Kittens Build: +1 ' + label);
    },
    isBuildable: function (name) {
        var buildable = this.getBuild(name).unlocked;

        if (buildable) {
            var manager = this.craftManager;
            var prices = this.getPrices(name);

            for (i in prices) {
                var price = prices[i];

                if (manager.getValueAvailable(price.name) < price.val) {
                    buildable = false;
                }
            }
        }

        return buildable;
    },
    getBuild: function (name) {
        return game.bld.getBuilding(name);
    },
    getPrices: function (name) {
        return game.bld.getPrices(name);
    }
};

// Crafting Manager
// ================

var CraftManager = function () {};

CraftManager.prototype = {
    craft: function (name, amount) {
        amount = Math.floor(amount);

        if (undefined === name || 1 > amount) return;
        if (!this.canCraft(name, amount)) return;

        var craft = this.getCraft(name);
        var ratio = ('wood' === name) ? 'refineRatio' : 'craftRatio';

        game.craft(craft.name, amount);

        // determine actual amount after crafting upgrades
        amount = (amount * (game.bld.getEffect(ratio) + 1)).toFixed(2);

        message('Kittens Craft: +' + amount + ' ' + name);
    },
    canCraft: function (name, amount) {
        var craft = this.getCraft(name);
        var result = false;

        if (craft.unlocked) {
            result = true;

            for (i in craft.prices) {
                var price = craft.prices[i];
                var value = this.getValueAvailable(price.name);

                if (value < price.val * amount) {
                    result = false;
                }
            }
        }

        return result;
    },
    getCraft: function (name) {
        // adjust for spelling bug in core game logic
        if ('compendium' === name) name = 'compedium';

        return game.workshop.getCraft(name);
    },
    getLowestCraftAmount: function (name) {
        var amount = 0;
        var consume = options.amount.consume;
        var materials = this.getMaterials(name);

        for (i in materials) {
            var total = this.getValueAvailable(i) * consume / materials[i];

            amount = (0 === amount || total < amount) ? total : amount;
        }

        return amount;
    },
    getMaterials: function (name) {
        var materials = {};
        var prices = this.getCraft(name).prices;

        for (i in prices) {
            var price = prices[i];

            materials[price.name] = price.val;
        }

        return materials;
    },
    getResource: function (name) {
        // adjust for spelling bug in core game logic
        if ('compendium' === name) name = 'compedium';

        return game.resPool.get(name);
    },
    getValue: function (name) {
        return this.getResource(name).value;
    },
    getValueAvailable: function (name) {
        var value = this.getValue(name);
        var stock = options.stock[name] || 0;

        if ('catnip' === name) {
            var resPerTick = game.getResourcePerTick(name, false, {
                modifiers: {
                    'catnip': 0.10 - game.calendar.getWeatherMod()
                }});

            if (resPerTick < 0) stock -= resPerTick * 202 * 5;
        }

        return value - stock;
    }
};

// ==============================
// Configure overall page display
// ==============================

var container = $('#game');
var column = $('.column');

container.css({
    fontFamily: 'Courier New',
    fontSize: '12px',
    minWidth: '1300px',
    top: '32px'
});

column.css({
    minHeight: 'inherit',
    maxWidth: 'inherit',
    padding: '1%',
    margin: 0
});

var left = $('#leftColumn');
var middle = $('#midColumn');
var right = $('#rightColumn');

left.css({
    height: '92%',
    width: '26%'
});

middle.css({
    marginTop: '1%',
    height: '92%',
    width: '48%'
});

right.css({
    height: '92%',
    width: '19%'
});

// Reconfigure dynamic page display
// ================================

var addRule = function (rule) {
    var sheets = document.styleSheets;
    sheets[0].insertRule(rule, 1);
};

addRule('#gameLog .msg {'
+ 'display: block;'
+ '}');

addRule('#resContainer .maxRes {'
+ 'color: #676766;'
+ '}');

addRule('#game .btn {'
+ 'border-radius: 0px;'
+ 'font-family: "Courier New";'
+ 'font-size: "10px";'
+ 'margin: 0 0 7px 0;'
+ '}');

addRule('#ks-options ul {'
+ 'list-style: none;'
+ 'margin: 0 0 5px;'
+ 'padding: 0;'
+ '}');

addRule('#ks-options ul:after {'
+ 'clear: both;'
+ 'content: " ";'
+ 'display: block;'
+ 'height: 0;'
+ '}');

addRule('#ks-options ul li {'
+ 'display: block;'
+ 'float: left;'
+ 'width: 50%;'
+ '}');

// Add options element
// ===================

var getToggle = function (name, text) {
    var li = $('<li/>');

    var label = $('<label/>', {
        'for': 'toggle-' + name,
        text: text
    });

    var toggle = $('<input/>', {
        id: 'toggle-' + name,
        type: 'checkbox',
        checked: 'checked'
    });

    return li.append(toggle, label);
};

var optionsElement = $('<div/>', {id: 'ks-options', css: {marginBottom: '10px'}});
var optionsListElement = $('<ul/>');
var optionsTitleElement = $('<div/>', {
    css: { borderBottom: '1px solid gray', marginBottom: '5px' },
    text: version
});

optionsElement.append(optionsTitleElement);

optionsListElement.append(getToggle('engine', 'Engine').css('width', '100%'));
optionsListElement.append(getToggle('crafting', 'Crafting'));
optionsListElement.append(getToggle('housing', 'Housing'));
optionsListElement.append(getToggle('building', 'Building'));
optionsListElement.append(getToggle('praising', 'Faith'));
optionsListElement.append(getToggle('hunting', 'Hunting'));
optionsListElement.append(getToggle('luxury', 'Luxury'));

// add the options above the game log
right.prepend(optionsElement.append(optionsListElement));

// Initialize and set toggles for Engine
// =====================================

var engine = new Engine();
var toggleEngine = $('#toggle-engine');

toggleEngine.on('change', function () {
    if (toggleEngine.is(':checked')) {
        engine.start();
    } else {
        engine.stop();
    }
});

toggleEngine.trigger('change');

// Add toggles for options
// =======================

var autoOptions = ['building', 'crafting', 'housing', 'hunting', 'luxury', 'praising'];

var ucfirst = function (string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
};

$.each(autoOptions, function (event, option) {
    var toggle = $('#toggle-' + option);

    toggle.on('change', function () {
        if (toggle.is(':checked')) {
            options.toggle[option] = true;
            message('Enabled Auto ' + ucfirst(option));
        } else {
            options.toggle[option] = false;
            message('Disable Auto ' + ucfirst(option));
        }
    });
});
<|endoftext|>


<commit_before>/*jslint browser: true, undef: true*//*global Ext*/

/**
 * @abstract
 * An abstract class for singletons that facilitates communication with backend services
 *
 * TODO:
 * - add events for all lifecycle events: beforerequest, request, beforexception, exception, unauthorized
 * - does the touch version use Ext.Ajax or parent.request?
 * - pass through request options like touch version does
 */
Ext.define('Jarvus.util.AbstractAPI', {
    extend: 'Ext.data.Connection',
    requires: ['Ext.util.Cookies', 'Ext.Ajax',
               'Ext.Array'
    ],
    uses: [
        'Jarvus.util.APIDomain'
    ],

    config: {
        /**
         * @cfg {String/null}
         * A hostname to prefix URLs with, or null to leave paths domain-relative
         */
        hostname: null,

        /**
         * @cfg {Boolean}
         * True to use HTTPS when prefixing hostname. Only used if {@link #cfg-hostname} is set
         */
        useSSL: false,

        // @inheritdoc
        withCredentials: true
    },

    //@private
    buildUrl: function(path) {
        var hostname = this.getHostname();
        return hostname ? (this.getUseSSL() ? 'https://' : 'http://')+hostname+path : path;
    },

    //@private
    buildHeaders: function(headers) {
        return headers;
    },

    //@private
    buildParams: function(params) {
        return params || null;
    },

    /**
     * Override {@link Ext.data.Connection#method-request} to implement auto-decoding and retry handler
     * @inheritdoc
     */
    request: function(options) {
        var me = this;

        return Ext.Ajax.request(Ext.applyIf({
            url: me.buildUrl(options.url),
            withCredentials: true,
            params: me.buildParams(options.params),
            headers: me.buildHeaders(options.headers),
            timeout: options.timeout || 30000,
            success: function(response) {

                if (options.autoDecode !== false && response.getResponseHeader('Content-Type') == 'application/json') {
                    response.data = Ext.decode(response.responseText, true);
                }

                //Calling the callback function sending the decoded data
                Ext.callback(options.success, options.scope, [response]);

            },
            failure: function(response) {

                if (options.autoDecode !== false && response.getResponseHeader('Content-Type') == 'application/json') {
                    response.data = Ext.decode(response.responseText, true);
                }

                if (options.failure && options.failureStatusCodes && Ext.Array.contains(options.failureStatusCodes, response.status)) {
                    Ext.callback(options.failure, options.scope, [response]);
                } else if (options.exception) {
                    Ext.callback(options.exception, options.scope, [response]);
                } else if (response.aborted === true) {
                    Ext.callback(options.abort, options.scope, [response]);
                } else if (response.status == 401 || response.statusText.indexOf('Unauthorized') !== -1) {

                    /*
                    We seem to always get the same session id, so we can't automatically try again once the user logs in
                    var oldSessionID = Ext.util.Cookies.get('s');
                     */

                    Ext.override(Ext.Msg, {
                        hide: function () {
                            var me = this,
                                hideManually = me.cfg ? me.cfg.hideManually : false;

                            if (!hideManually) {
                                me.callParent(arguments);
                            }
                        }
                    });

                    var msg = Ext.Msg.show({
                        hideManually: true,
                        title: 'Login Required',
                        msg: "You've either logged out or your has session expired. Please login and try again.",
                        buttonText: {
                            'yes': 'Login',
                            'no': 'Try Again',
                            'cancel': 'Cancel'
                        },
                        scope: msg,
                        fn: function (btn) {
                            if (btn === 'yes') {
                                // login
                                var loginWindow = window.open('/login', 'emergence-login');
                                loginWindow.focus();
                                return;
                            } else if (btn === 'no') {
                                // try again
                                me.request(options);
                            }

                            msg.cfg.hideManually = false;
                            msg.hide();
                        }
                    });

                    /*
                    if (oldSessionID !== null) {
                        var cookieCheckInterval = window.setInterval(function() {
                            console.log(oldSessionID);
                            console.warn(Ext.util.Cookies.get('s'));
                            if (Ext.util.Cookies.get('s') != oldSessionID) {
                                alert('new login');
                                debugger;
                                window.clearInterval(cookieCheckInterval);
                            }
                        }, 100);
                    }
                    */
                } else {
                    Ext.Msg.confirm('An error occurred', 'There was an error trying to reach the server. Do you want to try again?', function (btn) {
                        if (btn === 'yes') {
                            me.request(options);
                        }
                    });
                }

            },
            scope: options.scope
        }, options));
    }
});
<commit_msg>fix login button during development on localhost<commit_after>/*jslint browser: true, undef: true*//*global Ext*/

/**
 * @abstract
 * An abstract class for singletons that facilitates communication with backend services
 *
 * TODO:
 * - add events for all lifecycle events: beforerequest, request, beforexception, exception, unauthorized
 * - does the touch version use Ext.Ajax or parent.request?
 * - pass through request options like touch version does
 */
Ext.define('Jarvus.util.AbstractAPI', {
    extend: 'Ext.data.Connection',
    requires: ['Ext.util.Cookies', 'Ext.Ajax',
               'Ext.Array'
    ],
    uses: [
        'Jarvus.util.APIDomain'
    ],

    config: {
        /**
         * @cfg {String/null}
         * A hostname to prefix URLs with, or null to leave paths domain-relative
         */
        hostname: null,

        /**
         * @cfg {Boolean}
         * True to use HTTPS when prefixing hostname. Only used if {@link #cfg-hostname} is set
         */
        useSSL: false,

        // @inheritdoc
        withCredentials: true
    },

    //@private
    buildUrl: function(path) {
        var hostname = this.getHostname();
        return hostname ? (this.getUseSSL() ? 'https://' : 'http://')+hostname+path : path;
    },

    //@private
    buildHeaders: function(headers) {
        return headers;
    },

    //@private
    buildParams: function(params) {
        return params || null;
    },

    /**
     * Override {@link Ext.data.Connection#method-request} to implement auto-decoding and retry handler
     * @inheritdoc
     */
    request: function(options) {
        var me = this;

        return Ext.Ajax.request(Ext.applyIf({
            url: me.buildUrl(options.url),
            withCredentials: true,
            params: me.buildParams(options.params),
            headers: me.buildHeaders(options.headers),
            timeout: options.timeout || 30000,
            success: function(response) {

                if (options.autoDecode !== false && response.getResponseHeader('Content-Type') == 'application/json') {
                    response.data = Ext.decode(response.responseText, true);
                }

                //Calling the callback function sending the decoded data
                Ext.callback(options.success, options.scope, [response]);

            },
            failure: function(response) {

                if (options.autoDecode !== false && response.getResponseHeader('Content-Type') == 'application/json') {
                    response.data = Ext.decode(response.responseText, true);
                }

                if (options.failure && options.failureStatusCodes && Ext.Array.contains(options.failureStatusCodes, response.status)) {
                    Ext.callback(options.failure, options.scope, [response]);
                } else if (options.exception) {
                    Ext.callback(options.exception, options.scope, [response]);
                } else if (response.aborted === true) {
                    Ext.callback(options.abort, options.scope, [response]);
                } else if (response.status == 401 || response.statusText.indexOf('Unauthorized') !== -1) {

                    /*
                    We seem to always get the same session id, so we can't automatically try again once the user logs in
                    var oldSessionID = Ext.util.Cookies.get('s');
                     */

                    Ext.override(Ext.Msg, {
                        hide: function () {
                            var me = this,
                                hideManually = me.cfg ? me.cfg.hideManually : false;

                            if (!hideManually) {
                                me.callParent(arguments);
                            }
                        }
                    });

                    var msg = Ext.Msg.show({
                        hideManually: true,
                        title: 'Login Required',
                        msg: "You've either logged out or your has session expired. Please login and try again.",
                        buttonText: {
                            'yes': 'Login',
                            'no': 'Try Again',
                            'cancel': 'Cancel'
                        },
                        scope: msg,
                        fn: function (btn) {
                            if (btn === 'yes') {
                                // login
                                var loginWindow = window.open(me.buildUrl('/login'), 'emergence-login');
                                loginWindow.focus();
                                return;
                            } else if (btn === 'no') {
                                // try again
                                me.request(options);
                            }

                            msg.cfg.hideManually = false;
                            msg.hide();
                        }
                    });

                    /*
                    if (oldSessionID !== null) {
                        var cookieCheckInterval = window.setInterval(function() {
                            console.log(oldSessionID);
                            console.warn(Ext.util.Cookies.get('s'));
                            if (Ext.util.Cookies.get('s') != oldSessionID) {
                                alert('new login');
                                debugger;
                                window.clearInterval(cookieCheckInterval);
                            }
                        }, 100);
                    }
                    */
                } else {
                    Ext.Msg.confirm('An error occurred', 'There was an error trying to reach the server. Do you want to try again?', function (btn) {
                        if (btn === 'yes') {
                            me.request(options);
                        }
                    });
                }

            },
            scope: options.scope
        }, options));
    }
});
<|endoftext|>


<commit_before>/*
 * loquat-prim / prim.js
 * copyright (c) 2016 Susisu
 */

/**
 * @module prim
 */

"use strict";

module.exports = _core => {
    function end() {
        return Object.freeze({
            map,
            pure,
            ap,
            left,
            right,
            bind,
            then,
            fail
        });
    }

    const ErrorMessageType = _core.ErrorMessageType;
    const ErrorMessage     = _core.ErrorMessage;
    const ParseError       = _core.ParseError;
    const Result           = _core.Result;
    const Parser           = _core.Parser;

    /**
     * @function module:prim.map
     * @static
     * @param {AbstractParser} parser
     * @param {function} func
     * @returns {AbstractParser}
     */
    function map(parser, func) {
        return new Parser(state => {
            let res = parser.run(state);
            return res.succeeded
                ? new Result(res.consumed, true, res.err, func(res.val), res.state)
                : res;
        });
    }

    /**
     * @function module:prim.pure
     * @static
     * @param {*} val
     * @returns {AbstractParser}
     */
    function pure(val) {
        return new Parser(state => Result.esuc(ParseError.unknown(state.pos), val, state));
    }

    /**
     * @function module:prim.ap
     * @static
     * @param {AbstractParser} parserA
     * @param {AbstractParser} parserB
     * @returns {AbstractParser}
     */
    function ap(parserA, parserB) {
        return bind(parserA, valA =>
            bind(parserB, valB =>
                pure(valA(valB))
            )
        );
    }

    const former = x => () => x;
    const latter = () => y => y;

    /**
     * @function module:prim.left
     * @static
     * @param {AbstractParser} parserA
     * @param {AbstractParser} parserB
     * @returns {AbstractParser}
     */
    function left(parserA, parserB) {
        return ap(map(parserA, former), parserB);
    }

    /**
     * @function module:prim.right
     * @static
     * @param {AbstractParser} parserA
     * @param {AbstractParser} parserB
     * @returns {AbstractParser}
     */
    function right(parserA, parserB) {
        return ap(map(parserA, latter), parserB);
    }

    /**
     * @function module:prim.bind
     * @static
     * @param {AbstractParser} parser
     * @param {function} func
     * @returns {AbstractParser}
     */
    function bind(parser, func) {
        return new Parser(state => {
            let resA = parser.run(state);
            if (resA.succeeded) {
                let parserB = func(resA.val);
                let resB = parserB.run(resA.state);
                return new Result(
                    resA.consumed || resB.consumed,
                    resB.succeeded,
                    resB.consumed ? resB.err : ParseError.merge(resA.err, resB.err),
                    resB.val,
                    resB.state
                );
            }
            else {
                return resA;
            }
        });
    }

    /**
     * @function module:prim.then
     * @static
     * @param {AbstractParser} parserA
     * @param {AbstractParser} parserB
     * @returns {AbstracParser}
     */
    function then(parserA, parserB) {
        return bind(parserA, () => parserB);
    }

    /**
     * @function module:prim.fail
     * @static
     * @param {string} msgStr
     * @returns {AbstractParser}
     */
    function fail(msgStr) {
        return new Parser(state => Result.eerr(
            new ParseError(state.pos, [new ErrorMessage(ErrorMessageType.MESSAGE, msgStr)])
        ));
    }

    return end();
};
<commit_msg>[prim] Add `mzero` and `mplus()`<commit_after>/*
 * loquat-prim / prim.js
 * copyright (c) 2016 Susisu
 */

/**
 * @module prim
 */

"use strict";

module.exports = _core => {
    function end() {
        return Object.freeze({
            map,
            pure,
            ap,
            left,
            right,
            bind,
            then,
            fail,
            mzero,
            mplus
        });
    }

    const ErrorMessageType = _core.ErrorMessageType;
    const ErrorMessage     = _core.ErrorMessage;
    const ParseError       = _core.ParseError;
    const Result           = _core.Result;
    const Parser           = _core.Parser;

    /**
     * @function module:prim.map
     * @static
     * @param {AbstractParser} parser
     * @param {function} func
     * @returns {AbstractParser}
     */
    function map(parser, func) {
        return new Parser(state => {
            let res = parser.run(state);
            return res.succeeded
                ? new Result(res.consumed, true, res.err, func(res.val), res.state)
                : res;
        });
    }

    /**
     * @function module:prim.pure
     * @static
     * @param {*} val
     * @returns {AbstractParser}
     */
    function pure(val) {
        return new Parser(state => Result.esuc(ParseError.unknown(state.pos), val, state));
    }

    /**
     * @function module:prim.ap
     * @static
     * @param {AbstractParser} parserA
     * @param {AbstractParser} parserB
     * @returns {AbstractParser}
     */
    function ap(parserA, parserB) {
        return bind(parserA, valA =>
            bind(parserB, valB =>
                pure(valA(valB))
            )
        );
    }

    const former = x => () => x;
    const latter = () => y => y;

    /**
     * @function module:prim.left
     * @static
     * @param {AbstractParser} parserA
     * @param {AbstractParser} parserB
     * @returns {AbstractParser}
     */
    function left(parserA, parserB) {
        return ap(map(parserA, former), parserB);
    }

    /**
     * @function module:prim.right
     * @static
     * @param {AbstractParser} parserA
     * @param {AbstractParser} parserB
     * @returns {AbstractParser}
     */
    function right(parserA, parserB) {
        return ap(map(parserA, latter), parserB);
    }

    /**
     * @function module:prim.bind
     * @static
     * @param {AbstractParser} parser
     * @param {function} func
     * @returns {AbstractParser}
     */
    function bind(parser, func) {
        return new Parser(state => {
            let resA = parser.run(state);
            if (resA.succeeded) {
                let parserB = func(resA.val);
                let resB = parserB.run(resA.state);
                return new Result(
                    resA.consumed || resB.consumed,
                    resB.succeeded,
                    resB.consumed ? resB.err : ParseError.merge(resA.err, resB.err),
                    resB.val,
                    resB.state
                );
            }
            else {
                return resA;
            }
        });
    }

    /**
     * @function module:prim.then
     * @static
     * @param {AbstractParser} parserA
     * @param {AbstractParser} parserB
     * @returns {AbstracParser}
     */
    function then(parserA, parserB) {
        return bind(parserA, () => parserB);
    }

    /**
     * @function module:prim.fail
     * @static
     * @param {string} msgStr
     * @returns {AbstractParser}
     */
    function fail(msgStr) {
        return new Parser(state => Result.eerr(
            new ParseError(state.pos, [new ErrorMessage(ErrorMessageType.MESSAGE, msgStr)])
        ));
    }

    /**
     * @constant module:prim.mzero
     * @static
     * @type {AbstractParser}
     */
    const mzero = new Parser(state => Result.eerr(ParseError.unknown(state.pos)));

    /**
     * @function module:prim.mplus
     * @static
     * @param {AbstractParser} parserA
     * @param {AbstractParser} parserB
     * @returns {AbstractParser}
     */
    function mplus(parserA, parserB) {
        return new Parser(state => {
            let resA = parserA.run(state);
            if (!resA.consumed && !resA.succeeded) {
                let resB = parserB.run(state);
                return new Result(
                    resB.consumed,
                    resB.succeeded,
                    resB.consumed ? resB.err : ParseError.merge(resA.err, resB.err),
                    resB.val,
                    resB.state
                );
            }
            else {
                return resA;
            }
        });
    }

    return end();
};
<|endoftext|>


<commit_before>/**
 * Extra properties applied to the Discord.js message object.
 * @typedef {Object} Message
 * @prop {?CommandUtil} command - Utilities for command responding.
 * Only available in command-related functions as a parameter.
 * Not available in regex/conditional commands as those can be ran at the same time.
 */

class CommandUtil {
    /**
     * Command utilies.
     * @param {AkairoClient} client - The Akairo client.
     * @param {Message} message - Message that triggered the command.
     * @param {Command} command - Command triggered.
     * @param {string} prefix - Prefix used to trigger.
     * @param {string} alias - Alias used to trigger.
     */
    constructor(client, message, command, prefix, alias) {
        /**
         * The Akairo client.
         * @readonly
         * @name CommandUtil#client
         * @type {AkairoClient}
         */
        Object.defineProperties(this, {
            client: {
                value: client
            }
        });

        /**
         * Message that triggered the command.
         * @type {Message}
         */
        this.message = message;

        /**
         * Command used.
         * @type {Command}
         */
        this.command = command;

        /**
         * The prefix used.
         * @type {string}
         */
        this.prefix = prefix;

        /**
         * The alias used.
         * @type {string}
         */
        this.alias = alias;

        /**
         * The response to base off.
         * @type {?Message}
         */
        this.base = null;

        /**
         * Responses sent, including prompts.
         * @type {Message[]}
         */
        this.responses = [];
    }

    /**
     * The last response sent.
     * @readonly
     * @type {?Message}
     */
    get lastResponse() {
        return this.responses[0];
    }

    /**
     * Sends a response or edits an old response if available.
     * @param {string|MessageOptions} content - Content to send.
     * @param {MessageOptions} [options] - Options to use.
     * @returns {Promise<Message>}
     */
    send(content, options) {
        [content, options] = this.constructor.swapOptions(content, options);
        if (this.command.editable && this.base) return this.lastResponse.edit(content, options);

        return this.message.channel.send(content, options).then(sent => {
            this.base = Array.isArray(sent) ? sent.slice(-1)[0] : sent;

            if (Array.isArray(sent)) {
                this.responses.unshift(...sent.reverse());
            } else {
                this.responses.unshift(sent);
            }

            return sent;
        });
    }

    /**
     * Sends a response with a mention concantenated to it.
     * @param {string|MessageOptions} content - Content to send.
     * @param {MessageOptions} [options] - Options to use.
     * @returns {Promise<Message>}
     */
    reply(content, options) {
        if (this.message.channel.type !== 'dm') content = `${this.message.author}, ${content}`;
        return this.send(content, options);
    }

    /**
     * Swaps and cleans up content and options.
     * @param {string|MessageOptions} content - Content to send.
     * @param {MessageOptions} [options] - Options to use.
     * @returns {Array}
     */
    static swapOptions(content, options) {
        if (!options && typeof content === 'object' && !(content instanceof Array)) {
            options = content;
            content = '';
        } else if (!options) {
            options = {};
        }

        if (!options.embed) options.embed = null;
        return [content, options];
    }
}

module.exports = CommandUtil;
<commit_msg>Provide checks for attachments<commit_after>/**
 * Extra properties applied to the Discord.js message object.
 * @typedef {Object} Message
 * @prop {?CommandUtil} command - Utilities for command responding.
 * Only available in command-related functions as a parameter.
 * Not available in regex/conditional commands as those can be ran at the same time.
 */

class CommandUtil {
    /**
     * Command utilies.
     * @param {AkairoClient} client - The Akairo client.
     * @param {Message} message - Message that triggered the command.
     * @param {Command} command - Command triggered.
     * @param {string} prefix - Prefix used to trigger.
     * @param {string} alias - Alias used to trigger.
     */
    constructor(client, message, command, prefix, alias) {
        /**
         * The Akairo client.
         * @readonly
         * @name CommandUtil#client
         * @type {AkairoClient}
         */
        Object.defineProperties(this, {
            client: {
                value: client
            }
        });

        /**
         * Message that triggered the command.
         * @type {Message}
         */
        this.message = message;

        /**
         * Command used.
         * @type {Command}
         */
        this.command = command;

        /**
         * The prefix used.
         * @type {string}
         */
        this.prefix = prefix;

        /**
         * The alias used.
         * @type {string}
         */
        this.alias = alias;

        /**
         * The response to base off.
         * @type {?Message}
         */
        this.base = null;

        /**
         * Responses sent, including prompts.
         * @type {Message[]}
         */
        this.responses = [];
    }

    /**
     * The last response sent.
     * @readonly
     * @type {?Message}
     */
    get lastResponse() {
        return this.responses[0];
    }

    /**
     * Sends a response or edits an old response if available.
     * @param {string|MessageOptions} content - Content to send.
     * @param {MessageOptions} [options] - Options to use.
     * @returns {Promise<Message>}
     */
    send(content, options) {
        [content, options] = this.constructor.swapOptions(content, options);
        if (this.command.editable && this.base && (!options.file || this.lastResponse.attachments.size)) return this.lastResponse.edit(content, options);

        return this.message.channel.send(content, options).then(sent => {
            if (options.file) return sent;
            if (this.lastResponse && this.lastResponse.attachments.size) return sent;

            this.base = Array.isArray(sent) ? sent.slice(-1)[0] : sent;

            if (Array.isArray(sent)) {
                this.responses.unshift(...sent.reverse());
            } else {
                this.responses.unshift(sent);
            }

            return sent;
        });
    }

    /**
     * Sends a response with a mention concantenated to it.
     * @param {string|MessageOptions} content - Content to send.
     * @param {MessageOptions} [options] - Options to use.
     * @returns {Promise<Message>}
     */
    reply(content, options) {
        if (this.message.channel.type !== 'dm') content = `${this.message.author}, ${content}`;
        return this.send(content, options);
    }

    /**
     * Swaps and cleans up content and options.
     * @param {string|MessageOptions} content - Content to send.
     * @param {MessageOptions} [options] - Options to use.
     * @returns {Array}
     */
    static swapOptions(content, options) {
        if (!options && typeof content === 'object' && !(content instanceof Array)) {
            options = content;
            content = '';
        } else if (!options) {
            options = {};
        }

        if (!options.embed) options.embed = null;
        return [content, options];
    }
}

module.exports = CommandUtil;
<|endoftext|>


<commit_before>/*
 * ------------------------------------------
 * 音频播放控件实现文件
 * @version  1.0
 * @author   genify(caijf@corp.netease.com)
 * ------------------------------------------
 */
var f = function(){
    // variable declaration
    var _  = NEJ.P,
        _c = _('nej.c'),
        _e = _('nej.e'),
        _p = _('nej.ut'),
        _pro;
    if (!!_p._$$MediaFlash) return;
    /**
     * 音频播放控件

     * 脚本举例
     * [code]
     *   // 首先生成播放对象,只负责逻辑部分，要配合UI来使用
     *   // preload：是否预加载
     *   // url：音频地址
     *   var _mda = _p._$$MediaFlash._$allocate({
     *       preload:false,
     *       url:'http://127.0.0.1:8000/nej-baseline/res/test.mp3',
     *       onstatechange:function(_event){
     *           // 状态改变的回调
     *           // 0 | 当前停止状态
     *           // 1 | 当前缓冲状态
     *           // 2 | 当前播放状态
     *           // 3 | 当前暂停状态
     *           // 4 | 播放结束状态
     *       }
     *   });
     *   // 开始播放
     *   _mda._$play();
     *   // 暂停播放
     *   _mda._$pause();
     *   // 停止播放
     *   _mda._$stop();
     * [/code]
     * @class   {nej.ut._$$MediaFlash} 音频播放控件
     * @extends {nej.ut._$$Media}
     * @param   {Object} 可选配置参数，已处理参数列表如下所示
     * @config  {String} url 音频地址
     */
    _p._$$MediaFlash = NEJ.C();
    _pro = _p._$$MediaFlash._$extend(_p._$$Media);
    /**
     * 控件初始化
     * @return {Void}
     */
    _pro.__init = (function(){
        var _onReady = function(_flash){
            this.__audio = _flash;
            if (!!this.__action){
                this.__action.call(this);
                delete this.__action;
            }
        };
        return function(){
            this.__supInit();
            _e._$flash({
                hidden:!0,
                src:_c._$get('audio.swf'),
                onready:_onReady._$bind(this),
                onended:this.__onStop._$bind(this),
                onpause:this.__onPause._$bind(this),
                onseking:this.__onLoading._$bind(this),
                onprogress:this.__onLoading._$bind(this),
                ontimeupdate:this.__onPlaying._$bind(this),
                onvolumechange:this.__onVolumeChange._$bind(this),
                onerror:this.__onError._$bind(this)
            });
        };
    })();
    /**
     * 控件销毁
     * @return {Void}
     */
    _pro.__destroy = function(){
        this.__supDestroy();
        delete this.__action;
    };
    /**
     * 执行播放操作
     * @protected
     * @method {__doPlay}
     * @return {Void}
     */
    _pro.__doPlay = function(){
        if (!!this.__audio){
            if (!!this.__source){
                this.__audio.nej_setSrc(this.__source);
                delete this.__source;
            }
            this.__audio.nej_play();
        }else{
            this.__action = this.__doPlay;
        }
    };
    /**
     * 执行暂停操作
     * @protected
     * @method {__doPause}
     * @return {Void}
     */
    _pro.__doPause = function(){
        if (!!this.__audio){
            this.__audio.nej_pause();
        }else{
            this.__action = this.__doPause;
        }
    };
    /**
     * 执行停止操作
     * @protected
     * @method {__doStop}
     * @return {Void}
     */
    _pro.__doStop = function(){
        if (!!this.__audio){
            this.__audio.nej_stop();
            this.__doStateChange(0);
        }else{
            this.__action = this.__doStop;
        }
    };
    /**
     * 文件载入触发事件
     * @protected
     * @method {__onLoading}
     * @return {Void}
     */
    _pro.__onLoading = function(){
        this.__doStateChange(1);
    };
    /**
     * 暂停触发事件
     * @protected
     * @method {__onPause}
     * @return {Void}
     */
    _pro.__onPause = function(){
        this.__doStateChange(3);
    };
    /**
     * 播放过程触发事件
     * @protected
     * @method {__onPlaying}
     * @return {Void}
     */
    _pro.__onPlaying = function(_event){
        this.__doStateChange(2);
        this._$dispatchEvent(
            'ontimeupdate',{
                duration:_event.duration,
                current:_event.currentTime
            }
        );
    };
    /**
     * 播放错误事件
     * @param  {Event} 事件信息
     * @return {Void}
     */
    _pro.__onError = function(_event){
        this.__doError();
        this._$dispatchEvent('onerror',{
            code:_event.code
        });
    };
    /**
     * 设置播放时间
     * @protected
     * @method {__setCurrentTime}
     * @return {Void}
     */
    _pro.__setCurrentTime = function(_time){
        if (this.__state==1) return;
        this.__audio.nej_seek(_time||0);
    };
    /**
     * 获取播放时间
     * @protected
     * @method {__getCurrentTime}
     * @return {Number} 当前时间
     */
    _pro.__getCurrentTime = function(){
        return this.__audio.nej_flash_get_currentTime();
    };
    /**
     * 设置音量
     * @protected
     * @method {__setVolume}
     * @return {Void}
     */
    _pro.__setVolume = function(_volume){
        if (!this.__audio) return;
        this.__audio.nej_flash_set_volume(_volume);
    };
    /**
     * 获取音量
     * @protected
     * @method {__getVolume}
     * @return {Number} 音量值
     */
    _pro.__getVolume = function(){
        if (!this.__audio) return;
        return this.__audio.nej_flash_get_volume();
    };
    /**
     * 取媒体总时长
     * @method {_$duration}
     * @return {Number} 媒体总时长
     */
    _pro._$duration = function(){
        return !this.__audio?0:this.__audio.nej_flash_get_duration();
    };
};
NEJ.define(
    '{lib}util/media/flash.js',[
    '{patch}config.js',
    '{lib}base/event.js',
    '{lib}util/media/media.js',
    '{lib}util/flash/flash.js'
],f);<commit_msg>update flash player<commit_after>/*
 * ------------------------------------------
 * 音频播放控件实现文件
 * @version  1.0
 * @author   genify(caijf@corp.netease.com)
 * ------------------------------------------
 */
var f = function(){
    // variable declaration
    var _  = NEJ.P,
        _c = _('nej.c'),
        _e = _('nej.e'),
        _p = _('nej.ut'),
        _pro;
    if (!!_p._$$MediaFlash) return;
    /**
     * 音频播放控件

     * 脚本举例
     * [code]
     *   // 首先生成播放对象,只负责逻辑部分，要配合UI来使用
     *   // preload：是否预加载
     *   // url：音频地址
     *   var _mda = _p._$$MediaFlash._$allocate({
     *       preload:false,
     *       url:'http://127.0.0.1:8000/nej-baseline/res/test.mp3',
     *       onstatechange:function(_event){
     *           // 状态改变的回调
     *           // 0 | 当前停止状态
     *           // 1 | 当前缓冲状态
     *           // 2 | 当前播放状态
     *           // 3 | 当前暂停状态
     *           // 4 | 播放结束状态
     *       }
     *   });
     *   // 开始播放
     *   _mda._$play();
     *   // 暂停播放
     *   _mda._$pause();
     *   // 停止播放
     *   _mda._$stop();
     * [/code]
     * @class   {nej.ut._$$MediaFlash} 音频播放控件
     * @extends {nej.ut._$$Media}
     * @param   {Object} 可选配置参数，已处理参数列表如下所示
     * @config  {String} url 音频地址
     */
    _p._$$MediaFlash = NEJ.C();
    _pro = _p._$$MediaFlash._$extend(_p._$$Media);
    /**
     * 控件初始化
     * @return {Void}
     */
    _pro.__init = (function(){
        var _onReady = function(_flash){
            this.__audio = _flash;
            if (!!this.__action){
                this.__action.call(this);
                delete this.__action;
            }
        };
        return function(){
            this.__supInit();
            _e._$flash({
                hidden:!0,
                src:_c._$get('audio.swf'),
                onready:_onReady._$bind(this),
                onended:this.__onStop._$bind(this),
                onpause:this.__onPause._$bind(this),
                onseeking:this.__onLoading._$bind(this),
                onprogress:this.__onLoading._$bind(this),
                ontimeupdate:this.__onPlaying._$bind(this),
                onvolumechange:this.__onVolumeChange._$bind(this),
                onerror:this.__onError._$bind(this)
            });
        };
    })();
    /**
     * 控件销毁
     * @return {Void}
     */
    _pro.__destroy = function(){
        this.__supDestroy();
        delete this.__action;
    };
    /**
     * 执行播放操作
     * @protected
     * @method {__doPlay}
     * @return {Void}
     */
    _pro.__doPlay = function(){
        if (!!this.__audio){
            if (!!this.__source){
                this.__audio.nej_setSrc(this.__source);
                delete this.__source;
            }
            this.__audio.nej_play();
        }else{
            this.__action = this.__doPlay;
        }
    };
    /**
     * 执行暂停操作
     * @protected
     * @method {__doPause}
     * @return {Void}
     */
    _pro.__doPause = function(){
        if (!!this.__audio){
            this.__audio.nej_pause();
        }else{
            this.__action = this.__doPause;
        }
    };
    /**
     * 执行停止操作
     * @protected
     * @method {__doStop}
     * @return {Void}
     */
    _pro.__doStop = function(){
        if (!!this.__audio){
            this.__audio.nej_stop();
            this.__doStateChange(0);
        }else{
            this.__action = this.__doStop;
        }
    };
    /**
     * 文件载入触发事件
     * @protected
     * @method {__onLoading}
     * @return {Void}
     */
    _pro.__onLoading = function(){
        this.__doStateChange(1);
    };
    /**
     * 暂停触发事件
     * @protected
     * @method {__onPause}
     * @return {Void}
     */
    _pro.__onPause = function(){
        this.__doStateChange(3);
    };
    /**
     * 播放过程触发事件
     * @protected
     * @method {__onPlaying}
     * @return {Void}
     */
    _pro.__onPlaying = function(_event){
        this.__doStateChange(2);
        this._$dispatchEvent(
            'ontimeupdate',{
                duration:_event.duration,
                current:_event.currentTime
            }
        );
        // check volume
        if (this.__dtvol!=null){
            var _volume = this.__dtvol;
            delete this.__dtvol;
            this.__setVolume(_volume);
        }
    };
    /**
     * 播放错误事件
     * @param  {Event} 事件信息
     * @return {Void}
     */
    _pro.__onError = function(_event){
        this.__doError();
        this._$dispatchEvent('onerror',{
            code:_event.code
        });
    };
    /**
     * 设置播放时间
     * @protected
     * @method {__setCurrentTime}
     * @return {Void}
     */
    _pro.__setCurrentTime = function(_time){
        if (this.__state==1) return;
        this.__audio.nej_seek(_time||0);
    };
    /**
     * 获取播放时间
     * @protected
     * @method {__getCurrentTime}
     * @return {Number} 当前时间
     */
    _pro.__getCurrentTime = function(){
        return this.__audio.nej_flash_get_currentTime();
    };
    /**
     * 设置音量
     * @protected
     * @method {__setVolume}
     * @return {Void}
     */
    _pro.__setVolume = function(_volume){
        if (!this.__audio){
            this.__dtvol = _volume;
            return;
        }
        try{
            this.__audio.nej_flash_set_volume(_volume);
        }catch(e){
            this.__dtvol = _volume;
        }
    };
    /**
     * 获取音量
     * @protected
     * @method {__getVolume}
     * @return {Number} 音量值
     */
    _pro.__getVolume = function(){
        if (!this.__audio) return;
        return this.__audio.nej_flash_get_volume();
    };
    /**
     * 取媒体总时长
     * @method {_$duration}
     * @return {Number} 媒体总时长
     */
    _pro._$duration = function(){
        return !this.__audio?0:this.__audio.nej_flash_get_duration();
    };
};
NEJ.define(
    '{lib}util/media/flash.js',[
    '{patch}config.js',
    '{lib}base/event.js',
    '{lib}util/media/media.js',
    '{lib}util/flash/flash.js'
],f);<|endoftext|>


<commit_before>/* @flow */

import React from 'react'

class Main extends React.Component {
  render() {
    return
Hello World

  }
}

export default Main
<commit_msg>:bug: Fix a typo in template We need the name to be motion so Motion.createElement is available for JSX<commit_after>/* @flow */

import Motion from 'react'

class Main extends Motion.Component {
  render() {
    return
Hello World

  }
}

export default Main
<|endoftext|>