<commit_before>'use strict';

var userAuth = require('./controllers/user-auth.js');
var db = require('./controllers/pg-database.js');
var upload = require('./controllers/upload-files.js');
var email = require('./controllers/email.js');
var googleDrive = require('./controllers/google-drive.js');

var express = require('express');
var bodyParser = require('body-parser');
var multer  = require('multer');
var validator = require('validator');
var fs = require('fs');
var wix = require('wix');
var httpStatus = require('http-status');

var app = express();
var router = express.Router();

wix.secret(require('./connect-keys/wix-key.json').secretKey);
app.use(bodyParser());
app.use(express.static(__dirname));

var MAX_FILE_SIZE = 1073741824;

app.use(multer({
  dest: './tmp/',
  limits: {
    fileSize: MAX_FILE_SIZE,
  }
}));

// parse instance and sets parsed insatnceId
function WixWidget(instance, compId) {

  if (instance === 'whatever') { // for testing purposes
    this.instanceId = instance;
  } else {
    var parsedInstance = wix.parse(instance);
    if (!parsedInstance) {
      throw new Error('invalid instance');
    }
    this.instanceId = parsedInstance.instanceId;
  }
  this.compId = compId;
}

function Visitor(name, email, message) {
  this.name = name;
  this.email = email;
  this.message = message;
}

// set any param to null to avoid it's update
function WidgetSettings(userEmail, provider, settings, serviceSettings) {
  this.userEmail = userEmail;
  this.provider = provider;
  this.settings = settings;
  this.serviceSettings = serviceSettings;
}

function error(message, statusCode) {
  var err = new Error(message);
  err.status = statusCode;
  return err;
}

app.get('/auth/callback/google', function (req, res, next) {
  if (req.query.error) {
    res.redirect('/');
    return;
  }
  userAuth.exchangeCodeForTokens(req.query.code, function (err, tokens) {
    console.log('tokens from google: ', tokens);
    console.log('oauth2callback state: ', req.query.state);

    var wixIds = req.query.state.split('+');
    var currInstance = new WixWidget(wixIds[0], wixIds[1]);

    var provider = 'google';

    db.token.insert(currInstance, tokens, provider, function (err) {
      userAuth.getGoogleEmail(tokens, function (err, widgetEmail) {
        googleDrive.createFolder(tokens.access_token, function (err, folderId) {
          var serviceSettings = {
            folderId: folderId
          };
          var widgetSettings = new WidgetSettings(widgetEmail || '', provider, null, serviceSettings);
          db.widget.getSettings(currInstance, function (err, widgetSettingsFromDb) {
            if (widgetSettingsFromDb) {
              var isEmailSet = widgetSettingsFromDb.user_email !== '';
              // do not update if email already set
              if (isEmailSet) { widgetSettings.userEmail = null; }
              db.widget.updateSettings(currInstance, widgetSettings, function (err) {

                res.redirect('/');
              });
            } else {
              widgetSettings.settings = null;
              db.widget.insertSettings(currInstance, widgetSettings, function (err) {

                res.redirect('/');
              });
            }
          });
        });
      });
    });
  });
});

app.use('/api', function (req, res, next) {

  var instance = 'whatever';//req.header('X-Wix-Instance');

  var currInstance;
  try {
    currInstance = new WixWidget(instance, null);
  } catch (e) {
    return next(error('invalid instance', httpStatus.UNAUTHORIZED));
  }

  req.widgetIds = currInstance;
  next();
});

app.param('compId', function (req, res, next, compId) {
  if (!compId) {
    next(error('invalid component ID', httpStatus.UNAUTHORIZED));
  } else {
    req.widgetIds.compId = compId;
    next();
  }
});

app.get('/api/auth/login/google/:compId', function (req, res, next) {
  db.token.get(req.widgetIds, function (err, tokensFromDb) {
    if (!tokensFromDb) {
      userAuth.getGoogleAuthUrl(req.widgetIds, function (url) {
        res.redirect(url);
      });
    } else {
      next(error('already logged in to ' + tokensFromDb.provider, httpStatus.BAD_REQUEST));
    }
  });
});

app.get('/api/auth/logout/:compId', function (req, res, next) {

  db.token.remove(req.widgetIds, function (err, removedTokens) {
    console.log('removed tokens: ', removedTokens);
    if (!removedTokens) {
      return next(error('not logged in', httpStatus.BAD_REQUEST));
    }

    var widgetSettings = new WidgetSettings(null, '', null, {});

    db.widget.updateSettings(req.widgetIds, widgetSettings, function (err) {
      if (err) {
        return next(error('settings update error', httpStatus.INTERNAL_SERVER_ERROR));
      }
      console.log('updated settings');
      console.log('removedTokens.provider: ', removedTokens.provider);
      if (removedTokens.provider === 'google') {
        console.log('revoking token');
        var oauth2Client = userAuth.createOauth2Client();
        oauth2Client.revokeToken(removedTokens.refresh_token, function (err, result) {
          console.log('revoked token');
          if (err) {
            console.error('token revoking error', err);
            return next(error('token revoking error', httpStatus.INTERNAL_SERVER_ERROR));
          }

          res.status(httpStatus.OK);
          res.json({status: httpStatus.OK});
        });
      }
    });
  });
});

app.get('/login', function (req, res) {
  res.sendfile('./login.html');
});

app.get('/api/files/session/:compId', function (req, res, next) {
  userAuth.getInstanceTokens(req.widgetIds, function (err, tokens) {
    if (!tokens) {
      console.error('getting instance tokens error', err);
      return next(error('widget is not signed in', httpStatus.UNAUTHORIZED));
    }
    upload.getAvailableCapacity(tokens, function (err, capacity) {
      if (err) {
        return next(error('cannot get availble capacity', httpStatus.INTERNAL_SERVER_ERROR));
      }
      db.session.open(req.widgetIds, function (err, sessionId) {

        if (err) {
          return next(error('cannot open session', httpStatus.INTERNAL_SERVER_ERROR));
        }
        var resJson = {
          sessionId: sessionId,
          capacity: capacity,
          status: httpStatus.OK
        };
        res.status(httpStatus.OK);
        res.json(resJson);
      });
    });
  });
});

app.post('/api/files/upload/:compId', function (req, res, next) {

  var MAX_FILE_SIZE = 1073741824;

  var newFile = req.files.sendFile;
  var sessionId = req.query.sessionId;

  var formatError = null;

  if (!validator.isInt(sessionId)) {
    formatError = error('invalid session format', httpStatus.BAD_REQUEST);
  }

  if (newFile.size >= MAX_FILE_SIZE) {
    formatError = error('file is too large', httpStatus.REQUEST_ENTITY_TOO_LARGE);
  }

  if (formatError) {
    fs.unlink(newFile.path, function() {
      return next(formatError);
    });
  } else {

    db.files.updateSessionAndInsert(newFile, sessionId, req.widgetIds, function (err, fileId) {
      if (!fileId) {
        return next(error('cannot insert file', httpStatus.INTERNAL_SERVER_ERROR));
      }

      var resJson = {
        status: httpStatus.OK,
        fileId: fileId
      };
      res.status(httpStatus.OK);
      res.json(resJson);
    });
  }
});

/*

JSON format

{
  "name": "kjasdfasfasdf",
  "email": "whasdfasdfs",
  "message": "asdfasfasdfasf"
  "toUpload": [
    "1",
    "2",
    "3"
  ]
}

*/

app.post('/api/files/send/:compId', function (req, res, next) {

  // parse the request

  var recievedJson = req.body;
  var sessionId = req.query.sessionId;

  if (!validator.isInt(sessionId)) {
    return next(error('invalid session format', httpStatus.BAD_REQUEST));
  }

  if (typeof recievedJson !== 'object') {
    return next(error('request body is not JSON', httpStatus.BAD_REQUEST));
  }

  var visitorEmail = recievedJson.visitorEmail;
  var visitorName = recievedJson.visitorName;
  var toUploadFileIds = recievedJson.fileIds;
  var visitorMessage = recievedJson.message;

  var isRequiredExist = visitorEmail && visitorName && toUploadFileIds && visitorMessage;

  if (!isRequiredExist) {
    return next(error('invalid request format', httpStatus.BAD_REQUEST));
  }
  visitorEmail = visitorEmail.trim();
  visitorName = visitorName.trim();
  visitorMessage = visitorMessage.trim();

  var isValidFormat = validator.isEmail(visitorEmail) &&
                      toUploadFileIds instanceof Array &&
                      !validator.isNull(visitorName) &&
                      !validator.isNull(visitorMessage);

  if (!isValidFormat) {
    return next(error('invalid request format', httpStatus.BAD_REQUEST));
  }

  userAuth.getInstanceTokens(req.widgetIds, function (err, tokens) {

    if (!tokens) {
      console.error('getting instance tokens error', err);
      return next(error('widget is not signed in', httpStatus.UNAUTHORIZED));
    }
    db.files.getByIds(sessionId, toUploadFileIds, function (err, files) {
      if (!files) {
        console.error('cannot find files', err);
        return next(error('cannot find files', httpStatus.BAD_REQUEST));
      }

      if (files[0].sum > MAX_FILE_SIZE) {
        return next(error('total files size is too large', httpStatus.REQUEST_ENTITY_TOO_LARGE));
      }
      upload.getAvailableCapacity(tokens, function (err, capacity) {
        if (err) {
          return next(error('cannot get availble capacity', httpStatus.INTERNAL_SERVER_ERROR));
        }

        if (capacity <= MAX_FILE_SIZE) {
          return next(error('Google Drive is full', httpStatus.BAD_REQUEST));
        }

        res.status(httpStatus.ACCEPTED);
        res.json({status: httpStatus.ACCEPTED});

        console.log('files to be zipped: ', files);
        var zipName = visitorName.replace(/\s+/g, '-');

        db.widget.getSettings(instance, function (err, settings) {

          upload.zip(files, zipName, function (err, archive) {
            console.log('zipped file: ', archive);
            if (err) {
              console.log('zipping error', err);
            }
            upload.insertFile(archive, settings.service_settings, sessionId, tokens, function (err, downloadUrl) {

              if (err) { console.error('uploading to google error', err); }
              result = JSON.parse(result);
              console.log('inserted file: ', result);
              var visitor = new Visitor(visitorName, visitorEmail, visitorMessage);
              email.send(settings.user_email, visitor, downloadUrl, function (err) {
                console.log('sent email');
              });
            });
          });
        });
      });
    });
  });
});

app.get('/api/settings/:compId', function (req, res, next) {

  db.widget.getSettings(req.widgetIds, function (err, widgetSettings) {

    var settingsResponse = {
      userEmail: '',
      provider: '',
      settings: {}
    };

    if (widgetSettings) {
      settingsResponse.userEmail = widgetSettings.user_email;
      settingsResponse.provider = widgetSettings.curr_provider;
      settingsResponse.settings = widgetSettings.settings;
    }

    res.status(httpStatus.OK);
    res.json({widgetSettings: settingsResponse, status: httpStatus.OK});
  });
});

app.put('/api/settings/:compId', function (req, res, next) {

  console.log(req.body);
  var widgetSettings = req.body.widgetSettings;
  var userEmail = widgetSettings.userEmail;
  var isValidSettings = widgetSettings && userEmail !== undefined &&
                        (userEmail.trim() === '' ||
                         validator.isEmail(userEmail)) &&
                        typeof widgetSettings.settings === 'object';

  if (!isValidSettings) {
    return next(error('invalid request format', httpStatus.BAD_REQUEST));
  }

  var settingsRecieved = new WidgetSettings(userEmail, null, widgetSettings.settings, null);
  db.widget.updateSettings(req.widgetIds, settingsRecieved, function (err, updatedWidgetSettings) {
    if (!updatedWidgetSettings) {
      db.widget.insertSettings(req.widgetIds, settingsRecieved, function (err) {
        if (err) {
          console.error('cannot insert settings: ', err);
          return next(error('cannot insert settings', httpStatus.INTERNAL_SERVER_ERROR));
        }

        res.status(httpStatus.CREATED);
        res.json({status: httpStatus.CREATED});
      });
    } else {

      res.status(httpStatus.CREATED);
      res.json({status: httpStatus.CREATED});
    }
  });
});

app.use(function (err, req, res, next) {
  var errorStatus = err.status || httpStatus.INTERNAL_SERVER_ERROR;
  res.json(errorStatus, {status: errorStatus, error: err.message });
});

app.use(function (req, res) {
  res.json(httpStatus.NOT_FOUND, {status: httpStatus.NOT_FOUND, error: 'resource not found' });
});

module.exports = app;
<commit_msg>implements sending errors if they occur after files submission<commit_after>'use strict';

var userAuth = require('./controllers/user-auth.js');
var db = require('./controllers/pg-database.js');
var upload = require('./controllers/upload-files.js');
var email = require('./controllers/email.js');
var googleDrive = require('./controllers/google-drive.js');

var express = require('express');
var bodyParser = require('body-parser');
var multer  = require('multer');
var validator = require('validator');
var fs = require('fs');
var wix = require('wix');
var httpStatus = require('http-status');

var app = express();
var router = express.Router();

wix.secret(require('./connect-keys/wix-key.json').secretKey);
app.use(bodyParser());
app.use(express.static(__dirname));

var MAX_FILE_SIZE = 1073741824;

app.use(multer({
  dest: './tmp/',
  limits: {
    fileSize: MAX_FILE_SIZE,
  }
}));

// parse instance and sets parsed insatnceId
function WixWidget(instance, compId) {

  if (instance === 'whatever') { // for testing purposes
    this.instanceId = instance;
  } else {
    var parsedInstance = wix.parse(instance);
    if (!parsedInstance) {
      throw new Error('invalid instance');
    }
    this.instanceId = parsedInstance.instanceId;
  }
  this.compId = compId;
}

function Visitor(name, email, message) {
  this.name = name;
  this.email = email;
  this.message = message;
}

// set any param to null to avoid it's update
function WidgetSettings(userEmail, provider, settings, serviceSettings) {
  this.userEmail = userEmail;
  this.provider = provider;
  this.settings = settings;
  this.serviceSettings = serviceSettings;
}

function error(message, statusCode) {
  var err = new Error(message);
  err.status = statusCode;
  return err;
}

app.get('/auth/callback/google', function (req, res, next) {
  if (req.query.error) {
    res.redirect('/');
    return;
  }
  userAuth.exchangeCodeForTokens(req.query.code, function (err, tokens) {
    console.log('tokens from google: ', tokens);
    console.log('oauth2callback state: ', req.query.state);

    var wixIds = req.query.state.split('+');
    var currInstance = new WixWidget(wixIds[0], wixIds[1]);

    var provider = 'google';

    db.token.insert(currInstance, tokens, provider, function (err) {
      userAuth.getGoogleEmail(tokens, function (err, widgetEmail) {
        googleDrive.createFolder(tokens.access_token, function (err, folderId) {
          var serviceSettings = {
            folderId: folderId
          };
          var widgetSettings = new WidgetSettings(widgetEmail || '', provider, null, serviceSettings);
          db.widget.getSettings(currInstance, function (err, widgetSettingsFromDb) {
            if (widgetSettingsFromDb) {
              var isEmailSet = widgetSettingsFromDb.user_email !== '';
              // do not update if email already set
              if (isEmailSet) { widgetSettings.userEmail = null; }
              db.widget.updateSettings(currInstance, widgetSettings, function (err) {

                res.redirect('/');
              });
            } else {
              widgetSettings.settings = null;
              db.widget.insertSettings(currInstance, widgetSettings, function (err) {

                res.redirect('/');
              });
            }
          });
        });
      });
    });
  });
});

app.use('/api', function (req, res, next) {

  var instance = 'whatever';//req.header('X-Wix-Instance');

  var currInstance;
  try {
    currInstance = new WixWidget(instance, null);
  } catch (e) {
    return next(error('invalid instance', httpStatus.UNAUTHORIZED));
  }

  req.widgetIds = currInstance;
  next();
});

app.param('compId', function (req, res, next, compId) {
  if (!compId) {
    next(error('invalid component ID', httpStatus.UNAUTHORIZED));
  } else {
    req.widgetIds.compId = compId;
    next();
  }
});

app.get('/api/auth/login/google/:compId', function (req, res, next) {
  db.token.get(req.widgetIds, function (err, tokensFromDb) {
    if (!tokensFromDb) {
      userAuth.getGoogleAuthUrl(req.widgetIds, function (url) {
        res.redirect(url);
      });
    } else {
      next(error('already logged in to ' + tokensFromDb.provider, httpStatus.BAD_REQUEST));
    }
  });
});

app.get('/api/auth/logout/:compId', function (req, res, next) {

  db.token.remove(req.widgetIds, function (err, removedTokens) {
    if (!removedTokens) {
      return next(error('not logged in', httpStatus.BAD_REQUEST));
    }

    var widgetSettings = new WidgetSettings(null, '', null, {});

    db.widget.updateSettings(req.widgetIds, widgetSettings, function (err) {
      if (err) {
        return next(error('settings update error', httpStatus.INTERNAL_SERVER_ERROR));
      }
      if (removedTokens.provider === 'google') {
        var oauth2Client = userAuth.createOauth2Client();
        oauth2Client.revokeToken(removedTokens.refresh_token, function (err) {
          if (err) {
            console.error('token revoking error', err);
            return next(error('token revoking error', httpStatus.INTERNAL_SERVER_ERROR));
          }

          res.status(httpStatus.OK);
          res.json({status: httpStatus.OK});
        });
      }
    });
  });
});

app.get('/login', function (req, res) {
  res.sendfile('./login.html');
});

app.get('/api/files/session/:compId', function (req, res, next) {
  userAuth.getInstanceTokens(req.widgetIds, function (err, tokens) {
    if (!tokens) {
      console.error('getting instance tokens error', err);
      return next(error('widget is not signed in', httpStatus.UNAUTHORIZED));
    }
    upload.getAvailableCapacity(tokens, function (err, capacity) {
      if (err) {
        return next(error('cannot get availble capacity', httpStatus.INTERNAL_SERVER_ERROR));
      }
      db.session.open(req.widgetIds, function (err, sessionId) {

        if (err) {
          return next(error('cannot open session', httpStatus.INTERNAL_SERVER_ERROR));
        }
        var resJson = {
          sessionId: sessionId,
          capacity: capacity,
          status: httpStatus.OK
        };
        res.status(httpStatus.OK);
        res.json(resJson);
      });
    });
  });
});

app.post('/api/files/upload/:compId', function (req, res, next) {

  var MAX_FILE_SIZE = 1073741824;

  var newFile = req.files.sendFile;
  var sessionId = req.query.sessionId;

  var formatError = null;

  if (!validator.isInt(sessionId)) {
    formatError = error('invalid session format', httpStatus.BAD_REQUEST);
  }

  if (newFile.size >= MAX_FILE_SIZE) {
    formatError = error('file is too large', httpStatus.REQUEST_ENTITY_TOO_LARGE);
  }

  if (formatError) {
    fs.unlink(newFile.path, function () {
      return next(formatError);
    });
  } else {

    db.files.updateSessionAndInsert(newFile, sessionId, req.widgetIds, function (err, fileId) {
      if (!fileId) {
        return next(error('cannot insert file', httpStatus.INTERNAL_SERVER_ERROR));
      }

      var resJson = {
        status: httpStatus.OK,
        fileId: fileId
      };
      res.status(httpStatus.OK);
      res.json(resJson);
    });
  }
});

/*

JSON format

{
  "name": "kjasdfasfasdf",
  "email": "whasdfasdfs",
  "message": "asdfasfasdfasf"
  "toUpload": [
    "1",
    "2",
    "3"
  ]
}

*/

app.post('/api/files/send/:compId', function (req, res, next) {

  // parse the request

  var recievedJson = req.body;
  var sessionId = req.query.sessionId;

  if (!validator.isInt(sessionId)) {
    return next(error('invalid session format', httpStatus.BAD_REQUEST));
  }

  if (typeof recievedJson !== 'object') {
    return next(error('request body is not JSON', httpStatus.BAD_REQUEST));
  }

  var visitorEmail = recievedJson.visitorEmail;
  var visitorName = recievedJson.visitorName;
  var toUploadFileIds = recievedJson.fileIds;
  var visitorMessage = recievedJson.message;

  var isRequiredExist = visitorEmail && visitorName && toUploadFileIds && visitorMessage;

  if (!isRequiredExist) {
    return next(error('invalid request format', httpStatus.BAD_REQUEST));
  }
  visitorEmail = visitorEmail.trim();
  visitorName = visitorName.trim();
  visitorMessage = visitorMessage.trim();

  var isValidFormat = validator.isEmail(visitorEmail) &&
                      toUploadFileIds instanceof Array &&
                      !validator.isNull(visitorName) &&
                      !validator.isNull(visitorMessage);

  if (!isValidFormat) {
    return next(error('invalid request format', httpStatus.BAD_REQUEST));
  }

  userAuth.getInstanceTokens(req.widgetIds, function (err, tokens) {

    if (!tokens) {
      console.error('getting instance tokens error', err);
      return next(error('widget is not signed in', httpStatus.UNAUTHORIZED));
    }
    db.files.getByIds(sessionId, toUploadFileIds, function (err, files) {
      if (!files) {
        console.error('cannot find files', err);
        return next(error('cannot find files', httpStatus.BAD_REQUEST));
      }

      if (files[0].sum > MAX_FILE_SIZE) {
        return next(error('total files size is too large', httpStatus.REQUEST_ENTITY_TOO_LARGE));
      }
      upload.getAvailableCapacity(tokens, function (err, capacity) {
        if (err) {
          return next(error('cannot get availble capacity', httpStatus.INTERNAL_SERVER_ERROR));
        }

        if (capacity <= MAX_FILE_SIZE) {
          return next(error('Google Drive is full', httpStatus.BAD_REQUEST));
        }

        res.status(httpStatus.ACCEPTED);
        res.json({status: httpStatus.ACCEPTED});

        console.log('files to be zipped: ', files);

        var visitor = new Visitor(visitorName, visitorEmail, visitorMessage);
        upload.zipAndInsert(files, visitor, req.widgetIds, sessionId, tokens, function (err, downloadUrl, settings) {
          if (err) {
            console.error('zipping and inserting error: ', err);
            email.sendErrors(settings.user_email, visitor, function (err, res) {
              console.log('sent email erros');
            });
          } else {
            email.send(settings.user_email, visitor, downloadUrl, function (err) {
              console.log('sent email');
            });
          }
        });
      });
    });
  });
});

app.get('/api/settings/:compId', function (req, res, next) {

  db.widget.getSettings(req.widgetIds, function (err, widgetSettings) {

    var settingsResponse = {
      userEmail: '',
      provider: '',
      settings: {}
    };

    if (widgetSettings) {
      settingsResponse.userEmail = widgetSettings.user_email;
      settingsResponse.provider = widgetSettings.curr_provider;
      settingsResponse.settings = widgetSettings.settings;
    }

    res.status(httpStatus.OK);
    res.json({widgetSettings: settingsResponse, status: httpStatus.OK});
  });
});

app.put('/api/settings/:compId', function (req, res, next) {

  console.log(req.body);
  var widgetSettings = req.body.widgetSettings;
  var userEmail = widgetSettings.userEmail;
  var isValidSettings = widgetSettings && userEmail !== undefined &&
                        (userEmail.trim() === '' ||
                         validator.isEmail(userEmail)) &&
                        typeof widgetSettings.settings === 'object';

  if (!isValidSettings) {
    return next(error('invalid request format', httpStatus.BAD_REQUEST));
  }

  var settingsRecieved = new WidgetSettings(userEmail, null, widgetSettings.settings, null);
  db.widget.updateSettings(req.widgetIds, settingsRecieved, function (err, updatedWidgetSettings) {
    if (!updatedWidgetSettings) {
      db.widget.insertSettings(req.widgetIds, settingsRecieved, function (err) {
        if (err) {
          console.error('cannot insert settings: ', err);
          return next(error('cannot insert settings', httpStatus.INTERNAL_SERVER_ERROR));
        }

        res.status(httpStatus.CREATED);
        res.json({status: httpStatus.CREATED});
      });
    } else {

      res.status(httpStatus.CREATED);
      res.json({status: httpStatus.CREATED});
    }
  });
});

app.use(function (err, req, res, next) {
  var errorStatus = err.status || httpStatus.INTERNAL_SERVER_ERROR;
  res.json(errorStatus, {status: errorStatus, error: err.message });
});

app.use(function (req, res) {
  res.json(httpStatus.NOT_FOUND, {status: httpStatus.NOT_FOUND, error: 'resource not found' });
});

module.exports = app;
<|endoftext|>


<commit_before>
/**
 * Module dependencies
 */

var express = require('express'),
  http = require('http');

var app = module.exports = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
require('lodash');

io.enable('browser client minification');  // send minified client
io.enable('browser client etag');          // apply etag caching logic based on version number
io.enable('browser client gzip');          // gzip the file
//io.set('log level', 0);                    // reduce logging

/**
 * Configuration
 */

// all environments
app.set('port', process.env.PORT || 3000);

// redirect all others to the index (HTML5 history)

// Socket.io Communication
var apps = {};
io.sockets.on('connection', function (socket) {
    //console.log('socket connected');

    var appId;

    socket.on('createGame', function(data){
        console.log('createGame', data);
        appId = data.appId;
        apps.appId = {slots:[], waitingSockets:[], gameSocket:socket};
        _.each(data.slots, function (playerName){
            apps.appId.slots.push({playerName:playerName, playerSocket:undefined});
        });

        socket.join(appId);
    });

    var assingSlot = function(socket){
            var freeSlots = _.first(apps.appId.slots, function(slot) {
                if(typeof(slot.playerSocket) == "undefined"){
                    return true;
                }else{
                    return false;
                }
            });
            if (freeSlots){
                freeSlots[0].playerSocket = socket;
                socket.playerName = freeSlots[0].playerName;
                console.log('app joined', data);
                socket.join(appId);
                apps.appId.gameSocket.emit('clientPaired', {playerName:freeSlots[0].playerName});
                socket.emit('clientPaired', {success:true});
            }else{
                socket.emit('clientPaired', {success:false, action:'wait'});
                apps.appId.waitingSockets.push(socket);
            }
    };

    socket.on('joinGame', function(data){
        console.log('app join attempt', data);
        appId = data;
        if(apps.appId){
            assingSlot(socket);
        }else{
            //app does not exists
            socket.emit('app Closed','sorry');
        }

    });

    socket.on('disconnect', function(){
        if(socket.playerName){
            socket.volatile.broadcast.to(appId).emit('clientUnpaired', {playerName:socket.playerName});
            var slotToRelease =  _.first(apps.appId.slots, function(slot){
                return  slot.playerName === socket.playerName;
            });
            if(slotToRelease){
                slotToRelease.playerSocket = undefined;
            }
            if(apps.appId.waitingSockets){
                assingSlot(apps.appId.waitingSockets[0]);
            }
        }else{
            delete apps.appId;
            socket.emit('apps closed','sorry');
        }
    });

    socket.on('control', function (data){
        console.log('control', data);
        console.log('sending mesage to appId:', appId);
        data.p = socket.playerName;
        //io.sockets.in(appId).emit('control', data);
        apps.appId.emit('control', data);
    });

});
//io.sockets.on('connection', require('./routes/socket'));

/**
 * Start Server
 */

server.listen(app.get('port'), function () {
  console.log('Express server listening on port ' + app.get('port'));
});
<commit_msg>no conflicts for lodash<commit_after>
/**
 * Module dependencies
 */

var express = require('express'),
  http = require('http');

var app = module.exports = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
require('lodash');
var lodash = _.noConflict();

io.enable('browser client minification');  // send minified client
io.enable('browser client etag');          // apply etag caching logic based on version number
io.enable('browser client gzip');          // gzip the file
//io.set('log level', 0);                    // reduce logging

/**
 * Configuration
 */

// all environments
app.set('port', process.env.PORT || 3000);

// redirect all others to the index (HTML5 history)

// Socket.io Communication
var apps = {};
io.sockets.on('connection', function (socket) {
    //console.log('socket connected');

    var appId;

    socket.on('createGame', function(data){
        console.log('createGame', data);
        appId = data.appId;
        apps.appId = {slots:[], waitingSockets:[], gameSocket:socket};
        lodash.each(data.slots, function (playerName){
            apps.appId.slots.push({playerName:playerName, playerSocket:undefined});
        });

        socket.join(appId);
    });

    var assingSlot = function(socket){
            var freeSlots = lodash.first(apps.appId.slots, function(slot) {
                if(typeof(slot.playerSocket) == "undefined"){
                    return true;
                }else{
                    return false;
                }
            });
            if (freeSlots){
                freeSlots[0].playerSocket = socket;
                socket.playerName = freeSlots[0].playerName;
                console.log('app joined', data);
                socket.join(appId);
                apps.appId.gameSocket.emit('clientPaired', {playerName:freeSlots[0].playerName});
                socket.emit('clientPaired', {success:true});
            }else{
                socket.emit('clientPaired', {success:false, action:'wait'});
                apps.appId.waitingSockets.push(socket);
            }
    };

    socket.on('joinGame', function(data){
        console.log('app join attempt', data);
        appId = data;
        if(apps.appId){
            assingSlot(socket);
        }else{
            //app does not exists
            socket.emit('app Closed','sorry');
        }

    });

    socket.on('disconnect', function(){
        if(socket.playerName){
            socket.volatile.broadcast.to(appId).emit('clientUnpaired', {playerName:socket.playerName});
            var slotToRelease =  lodash.first(apps.appId.slots, function(slot){
                return  slot.playerName === socket.playerName;
            });
            if(slotToRelease){
                slotToRelease.playerSocket = undefined;
            }
            if(apps.appId.waitingSockets){
                assingSlot(apps.appId.waitingSockets[0]);
            }
        }else{
            delete apps.appId;
            socket.emit('apps closed','sorry');
        }
    });

    socket.on('control', function (data){
        console.log('control', data);
        console.log('sending mesage to appId:', appId);
        data.p = socket.playerName;
        //io.sockets.in(appId).emit('control', data);
        apps.appId.emit('control', data);
    });

});
//io.sockets.on('connection', require('./routes/socket'));

/**
 * Start Server
 */

server.listen(app.get('port'), function () {
  console.log('Express server listening on port ' + app.get('port'));
});
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------//
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var databaseUri = 'mongodb://localhost:27017/crow';
var twitter = require('./modules/twitter.module');
var db = require('./modules/db.module');
require('dotenv').config({path: __dirname + '/.env'});
//----------------------------------------------------------------------------//

//---------------------------------- SETUP -----------------------------------//

app.use(express.static('./server/public'));
app.use(bodyParser.json());

//----------------------- MONGOOSE CONNECTION HANDLING -----------------------//

mongoose.connect(databaseUri);

mongoose.connection.on('connected', function() {
  console.log('mongoose connected to ', databaseUri);
});

mongoose.connection.on('error', function(error) {
  console.log('mongoose connection error: ', error);
});

//----------------------------- ROUTES & MODULES -----------------------------//

app.use('/twitter', twitter);
app.use('/db', db);

//------------------------------- START SERVER -------------------------------//
app.listen(3000);
<commit_msg>update database connection for heroku and mLab<commit_after>//----------------------------------------------------------------------------//
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var databaseUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/crow';
var twitter = require('./modules/twitter.module');
var db = require('./modules/db.module');
require('dotenv').config({path: __dirname + '/.env'});
//----------------------------------------------------------------------------//

//---------------------------------- SETUP -----------------------------------//

app.use(express.static('./server/public'));
app.use(bodyParser.json());

//----------------------- MONGOOSE CONNECTION HANDLING -----------------------//

mongoose.connect(databaseUri);

mongoose.connection.on('connected', function() {
  console.log('mongoose connected to ', databaseUri);
});

mongoose.connection.on('error', function(error) {
  console.log('mongoose connection error: ', error);
});

//----------------------------- ROUTES & MODULES -----------------------------//

app.use('/twitter', twitter);
app.use('/db', db);

//------------------------------- START SERVER -------------------------------//
app.listen(3000);
<|endoftext|>


<commit_before>var fs = require('fs')
  , nconf = require('nconf')
  , serialport = require("serialport")
  , sqlite3 = require('sqlite3')
  , express = require('express')
  ;

// Configuration
nconf.argv()
     .env()
     .file({ file: 'config.json' });
nconf.defaults({
    'DEVICE': '/dev/ttyACM0',
    'PORT': '4000'
});

// Database setup
var db = new sqlite3.Database('checkinout.db');
db.serialize(function() {
    db.run("CREATE TABLE people (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(60), cardid VARCHAR(25) UNIQUE, checkin DATETIME, checkinid INTEGER)",
	   function(err) {
	       if (err) {
		   console.log('Database already exists')
	       }
	   });

    db.run("CREATE TABLE checkinlist (id INTEGER PRIMARY KEY NOT NULL, cardid VARCHAR(25), eventtime DATETIME, eventtype INTEGER, FOREIGN KEY(cardid) REFERENCES people(cardid))",
	   function(err) {
	       if (err) {
		   console.log('Database already exists')
	       }
	   });
});

// Serial Port setup
var SerialPort = serialport.SerialPort;
var serialPort = new SerialPort(nconf.get('DEVICE'), {
    baudrate: 115200,
    parser: serialport.parsers.readline("\n")
});

serialPort.on("open", function () {
    console.log("SerialPort Open")
    serialPort.on('data', function(data) {
	var chkdata = data.split(",");
	var ID = chkdata[0];
	var event = chkdata[1];
	console.log("ID: "+ID);
	console.log("Event: "+event);
	addCheckinEvent(ID, event);
    });
});

var addCheckinEvent = function(id, event) {
    var date = new Date();

    db.serialize(function() {
	db.get("SELECT * FROM people WHERE cardid=? LIMIT 1", id, function(err, row) {
    	    if (typeof row === 'undefined') {
		db.run("INSERT INTO people (name, cardid) VALUES(?, ?)", "", id);
		console.log("Added new card: "+id);
    	    } else {
		console.log("Exisiting card: "+row.cardid);
	    }
	});

	db.run("INSERT INTO checkinlist (cardid, eventtime, eventtype) VALUES(?, ?, ?)", id, date, event, function (err, row) {
	    if (err) {
		console.log("Error inserting event!")
	    };
	});

	db.get("SELECT id FROM checkinlist WHERE cardid=? AND eventtime=? LIMIT 1", id, date, function(err, row) {
	    if (err) {
		console.log("Event insertion consitency fail");
	    } else {
		var checkinid = row.id;
		var eventdate = date;
		if (event == 1) {
		    console.log("CHECKIN!");
		} else if (event == 2) {
		    console.log("CHECKOUT!");
		    eventdate = null;
		}
		db.run("UPDATE people SET checkin=?,checkinid=? WHERE cardid=?", eventdate, checkinid, id, function(err){
		    if (err) {
			console.log("People database consistency fail");
		    }
		})
	    };
	});
    });
}

console.log("Arduino on: "+nconf.get('DEVICE'));

// Set up web interface
var app = express();
app.use(express.logger());

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', "*")
};
// app.use(allowCrossDomain);

app.get('/inspace', function(req, res){
    var out = { people: [] }
    db.all("SELECT name,checkin FROM people WHERE checkin IS NOT NULL", function(err, rows) {
	for (var i = 0; i < rows.length; i++) {
	    out.people.push(rows[i]);
	}
	res.header('Access-Control-Allow-Origin', "*")
	res.jsonp(out);
    });
});

app.get('/', function(req, res){
    res.header('Access-Control-Allow-Origin', "*")
    res.send("Not quite there yet.");
});

var port = nconf.get('PORT');
app.listen(port);
console.log('Listening on port '+port);
<commit_msg>Missing semicolon<commit_after>var fs = require('fs')
  , nconf = require('nconf')
  , serialport = require("serialport")
  , sqlite3 = require('sqlite3')
  , express = require('express')
  ;

// Configuration
nconf.argv()
     .env()
     .file({ file: 'config.json' });
nconf.defaults({
    'DEVICE': '/dev/ttyACM0',
    'PORT': '4000'
});

// Database setup
var db = new sqlite3.Database('checkinout.db');
db.serialize(function() {
    db.run("CREATE TABLE people (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(60), cardid VARCHAR(25) UNIQUE, checkin DATETIME, checkinid INTEGER)",
	   function(err) {
	       if (err) {
		   console.log('Database already exists')
	       }
	   });

    db.run("CREATE TABLE checkinlist (id INTEGER PRIMARY KEY NOT NULL, cardid VARCHAR(25), eventtime DATETIME, eventtype INTEGER, FOREIGN KEY(cardid) REFERENCES people(cardid))",
	   function(err) {
	       if (err) {
		   console.log('Database already exists')
	       }
	   });
});

// Serial Port setup
var SerialPort = serialport.SerialPort;
var serialPort = new SerialPort(nconf.get('DEVICE'), {
    baudrate: 115200,
    parser: serialport.parsers.readline("\n")
});

serialPort.on("open", function () {
    console.log("SerialPort Open")
    serialPort.on('data', function(data) {
	var chkdata = data.split(",");
	var ID = chkdata[0];
	var event = chkdata[1];
	console.log("ID: "+ID);
	console.log("Event: "+event);
	addCheckinEvent(ID, event);
    });
});

var addCheckinEvent = function(id, event) {
    var date = new Date();

    db.serialize(function() {
	db.get("SELECT * FROM people WHERE cardid=? LIMIT 1", id, function(err, row) {
    	    if (typeof row === 'undefined') {
		db.run("INSERT INTO people (name, cardid) VALUES(?, ?)", "", id);
		console.log("Added new card: "+id);
    	    } else {
		console.log("Exisiting card: "+row.cardid);
	    }
	});

	db.run("INSERT INTO checkinlist (cardid, eventtime, eventtype) VALUES(?, ?, ?)", id, date, event, function (err, row) {
	    if (err) {
		console.log("Error inserting event!")
	    };
	});

	db.get("SELECT id FROM checkinlist WHERE cardid=? AND eventtime=? LIMIT 1", id, date, function(err, row) {
	    if (err) {
		console.log("Event insertion consitency fail");
	    } else {
		var checkinid = row.id;
		var eventdate = date;
		if (event == 1) {
		    console.log("CHECKIN!");
		} else if (event == 2) {
		    console.log("CHECKOUT!");
		    eventdate = null;
		}
		db.run("UPDATE people SET checkin=?,checkinid=? WHERE cardid=?", eventdate, checkinid, id, function(err){
		    if (err) {
			console.log("People database consistency fail");
		    }
		})
	    };
	});
    });
}

console.log("Arduino on: "+nconf.get('DEVICE'));

// Set up web interface
var app = express();
app.use(express.logger());

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', "*")
};
// app.use(allowCrossDomain);

app.get('/inspace', function(req, res){
    var out = { people: [] }
    db.all("SELECT name,checkin FROM people WHERE checkin IS NOT NULL", function(err, rows) {
	for (var i = 0; i < rows.length; i++) {
	    out.people.push(rows[i]);
	}
	res.header('Access-Control-Allow-Origin', "*");
	res.jsonp(out);
    });
});

app.get('/', function(req, res){
    res.header('Access-Control-Allow-Origin', "*")
    res.send("Not quite there yet.");
});

var port = nconf.get('PORT');
app.listen(port);
console.log('Listening on port '+port);
<|endoftext|>


<commit_before>var _vecticUID = 0;

var _htmlBoiler = '\
\
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" id="{{ROOTID}}">\
    <defs id="palettes"></defs>\
    <defs id="templates"></defs>\
    <g id="objects"></g>\
    <g id="templates_edit"></g>\
  </svg>\
\
';

var _globalVecticStyler = '\
.svgContainer {\
  -webkit-touch-callout: none !important;\
  -webkit-user-select: none !important;\
  -khtml-user-select: none !important;\
  -moz-user-select: none !important;\
  -ms-user-select: none !important;\
  user-select: none !important;\
}\
.svgContainer svg:not([width]) {\
  width: 100% !important;\
}\
';

var _dataWrapperItems = {};   // dataWrapper() objects refered by: '{type}_{id}'. e.g. 'template_abcd01'

var _vecticTags = [
  'circle',
  'rect',
];
var _vecticTagAttributes = [{
  id: 'id',     val: function(data, key) { return 't'+key; } },{
  id: 'objid',  val: function(data, key) { return key; } },{
  id: 'class',  val: function(data, key) { return 'c'+data.color; } },{
  id: 'r',      val: function(data, key) { return data.r; } },{
  id: 'cx',     val: function(data, key) { return data.cx; } },{
  id: 'cy',     val: function(data, key) { return data.cy; } },{
  id: 'x',      val: function(data, key) { return data.x; } },{
  id: 'y',      val: function(data, key) { return data.y; } },{
  id: 'width',  val: function(data, key) { return data.width; } },{
  id: 'height', val: function(data, key) { return data.height; } },];

function vectic(vecticParams) {
  vecticParams = vecticParams || {};
  var _vectic = this;
  _vectic.id = vecticParams.id;
  _vectic.type = vecticParams.type || 'vectic';

  // TODO: Use dataWrapper?
  _vectic.rootID = 'v'+_vectic.id+'_id'+(_vecticUID+=1);
  _vectic.rootElementId = null;
  _vectic.targetObject = vecticParams.target;

  _vectic.svgDom = null;                      // Vectic DOM object (set in _vectic.getDoms)
  _vectic.objectContainerDom = null;          // Vectic DOM object (set in _vectic.getDoms)
  _vectic.templateContainerDom = null;        // Vectic DOM object (set in _vectic.getDoms)
  _vectic.paletteContainerDom = null;         // Vectic DOM object (set in _vectic.getDoms)
  _vectic.templateEditContainerDom = null;    // Vectic DOM object (set in _vectic.getDoms)

  _vectic.Firebase = Firebase;
  if(!_vectic.Firebase) { return console.error('vectic(): could not find Firebase library'); }

  _vectic.pathBase = vecticParams.basePath || 'http://vecticdev.firebaseio.com/';
  _vectic.firebaseRef = null;

  _vectic.connect = function() {
    _vectic.firebaseRef = new _vectic.Firebase(_vectic.pathBase);
  };

  _vectic.initStyles = function() {
    console.log('_vectic.initStyles')
    // Add css styles and reusable content to  if not already added
    if($('body #vecticStyler').length) {return;}

    var vecticStyler = $('');
    $('body').append(vecticStyler);
  };

  _vectic.initHTML = function() {
    console.log('_vectic.initHTML')
    if(!_vectic.targetObject) {return console.error('vectic: Target object missing');}
    _vectic.targetObject.html(_htmlBoiler.replace('{{ROOTID}}', _vectic.rootID));
    // TODO: replace w=this with the dataWrapper?
    _vectic.targetObjectSvg = ($(_vectic.targetObject)).find('svg').get(0);
  };

  _vectic.getDoms = function() {
    console.log('_vectic.getDoms')
    _vectic.svgDom                    = $('svg#'+_vectic.rootID).get(0);
    _vectic.objectContainerDom        = $('svg#'+_vectic.rootID+' g#objects').get(0);
    _vectic.templateContainerDom      = $('svg#'+_vectic.rootID+' defs#templates').get(0);
    _vectic.paletteContainerDom       = $('svg#'+_vectic.rootID+' defs#palettes').get(0);
    _vectic.templateEditContainerDom  = $('svg#'+_vectic.rootID+' g#templates_edit').get(0);
  };

  _vectic.dataWrapper = function(dataWrapperParams) {
    dataWrapperParams = dataWrapperParams || {};
    var _dataWrapper = this;

    _dataWrapper.id = dataWrapperParams.id;
    _dataWrapper.type = dataWrapperParams.type;
    _dataWrapper.elementId = null;      // HTML DOM Object ID
    _dataWrapper.element = null;        // HTML DOM Object (JQuery)
    _dataWrapper.ref = null;            // Firebase connection reference
    _dataWrapper.val = null;            // Snapshot data

    // Decide on data path and html element ID based on type
    switch(_dataWrapper.type) {
      case 'vectic':
        _dataWrapper.elementId = 'v'+_dataWrapper.id;
        _dataWrapper.path = 'vectic/'+_dataWrapper.id;
        break;
      case 'templateedit':
        // TODO: When rendering template content as vectic internal content for user interaction
        _dataWrapper.elementId = 't'+_dataWrapper.id;
        _dataWrapper.path = 'template/'+_dataWrapper.id;
        break;
      case 'template':
        _dataWrapper.elementId = 't'+_dataWrapper.id;
        _dataWrapper.path = 'template/'+_dataWrapper.id;
        break;
      case 'palette':
        _dataWrapper.elementId = 'p'+_dataWrapper.id;
        _dataWrapper.path = 'palette/'+_dataWrapper.id;
        break;
      case 'object':
        _dataWrapper.elementId = 'o'+_dataWrapper.id;
        _dataWrapper.path = 'object/'+_dataWrapper.id;
        break;
    }

    if(!_dataWrapper.id)         { return console.error('vectic.dataWrapper() missing "id" parameter'); }
    if(!_dataWrapper.type)       { return console.error('vectic.dataWrapper() missing "type" parameter'); }
    if(!_dataWrapper.elementId)  { return console.error('vectic.dataWrapper() missing "elementId"'); }

    _dataWrapper.redraw = function() {
      if(!_dataWrapper.val) {
        console.error('_dataWrapper.redraw(): no val available');
      }

      var newElement = null;
      // TODO: Create DOM Object
      switch(_dataWrapper.type) {
        case 'vectic':
          console.log('_dataWrapper.val: ')
          console.log(_dataWrapper.val)
          // Set viewBox
          var viewBox = '0 0 '+_dataWrapper.val.settings.width+' '+_dataWrapper.val.settings.height;
          _vectic.svgDom.setAttributeNS(null, 'viewBox', viewBox);

          // Set palette
          if(_dataWrapper.val.palette) {
            _vectic.svgDom.setAttributeNS(null, 'class', 'p'+_dataWrapper.val.palette);
          }
          break;
        case 'template':
          newElement = document.createElementNS('http://www.w3.org/2000/svg', ('def'));
          break;
        case 'palette':
          // TODO:
          break;
        case 'object':
          newElement = document.createElementNS('http://www.w3.org/2000/svg', ('use'));
          // TODO:
          break;
      }

      console.log('newElement '+_dataWrapper.type+':')
      console.log(newElement)

      // TODO: ^ Above: Add default behaviour (exit without redrawing with error)

      // TODO: Insert inner text from _dataWrapper.val

      // TODO: Apply attributes from _dataWrapper.val

      // TODO: DOM Object to corresponding container DOM element (which triggers html redraw)
      switch(_dataWrapper.type) {
        case 'vectic':
          // TODO:
          break;
        case 'templateedit':
          // TODO: When rendering template content as vectic internal content for user interaction
          break;
        case 'template':
          // Draw child elements
          for(var sChildId in _dataWrapper.val.elements) {
            var childElement = _dataWrapper.val.elements[sChildId];
            if(_vecticTags.indexOf(childElement.tag)<0) { console.error('_dataWrapper.redrawChildElement: tag "'+childElement.tag+'" not supported'); continue; }

            var newChildElement = document.createElementNS('http://www.w3.org/2000/svg', (childElement.tag));
            for(var iAtt in _vecticTagAttributes) {
              var att = _vecticTagAttributes[iAtt];
              var id = att.id;
              var val = att.val(childElement, key);
              var ns = att.ns || null;
              if([null, undefined].indexOf(val)<0) {
                newChildElement.setAttributeNS(ns, id, val);
              }
            }

            newElement.append(newChildElement);
          }

          if(_dataWrapper.element) { _dataWrapper.element.replaceWith(newElement); }
          else if(_vectic.templateContainerDom) { _vectic.templateContainerDom.append(newElement); }    // Append new object
          else { console.error('_dataWrapper.redraw(): type="'+_dataWrapper.type+'": nowhere to draw'); }
          break;
        case 'palette':
          // TODO:
          break;
        case 'object':
          if(_dataWrapper.element) { _dataWrapper.element.replaceWith(newElement); }      // Replace existing element
          else if(_vectic.objectContainerDom) { _vectic.objectContainerDom.append(newElement); }    // Append new object
          else { console.error('_dataWrapper.redraw(): type="'+_dataWrapper.type+'": nowhere to draw'); }
          // TODO:
          break;
      }

      console.log('newElement post population:')
      console.log(newElement)

      if(newElement) {
        _dataWrapper.element = newElement;
      }
    };

    console.log('test 1')
    console.log(_dataWrapper.path)
    console.log(_vectic.firebaseRef)

    if(_vectic.firebaseRef && _dataWrapper.path) {
      _dataWrapper.ref = _vectic.firebaseRef.child(_dataWrapper.path);

      _dataWrapper.ref.on('value', function(snapshot) {
        console.log('on value snapshot: ')
        console.log(snapshot)

        _dataWrapper.val = snapshot.val();
        _dataWrapper.redraw();
      });
    }

    // TODO:
    _dataWrapperItems[_dataWrapper.elementId] = _dataWrapper;
  };

  _vectic.init = function() {
    if(!_vectic.Firebase) {return console.error('vectic.init(): Missing Firebase library');}
    _vectic.connect();
    _vectic.initStyles();
    _vectic.initHTML();
    _vectic.getDoms();

    if(_vectic.id) {
      // TODO:
      var newWrapper = new _vectic.dataWrapper({
        id: _vectic.id,
        type: 'vectic',
      });
    }

    // TODO:
  };

  _vectic.getObjectsRef = function() {
    console.log('TODO: Stop calling _vectic.getObjectsRef! OR, you know, code this function');
  };
}<commit_msg>Correct type parameter on init()<commit_after>var _vecticUID = 0;

var _htmlBoiler = '\
\
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" id="{{ROOTID}}">\
    <defs id="palettes"></defs>\
    <defs id="templates"></defs>\
    <g id="objects"></g>\
    <g id="templates_edit"></g>\
  </svg>\
\
';

var _globalVecticStyler = '\
.svgContainer {\
  -webkit-touch-callout: none !important;\
  -webkit-user-select: none !important;\
  -khtml-user-select: none !important;\
  -moz-user-select: none !important;\
  -ms-user-select: none !important;\
  user-select: none !important;\
}\
.svgContainer svg:not([width]) {\
  width: 100% !important;\
}\
';

var _dataWrapperItems = {};   // dataWrapper() objects refered by: '{type}_{id}'. e.g. 'template_abcd01'

var _vecticTags = [
  'circle',
  'rect',
];
var _vecticTagAttributes = [{
  id: 'id',     val: function(data, key) { return 't'+key; } },{
  id: 'objid',  val: function(data, key) { return key; } },{
  id: 'class',  val: function(data, key) { return 'c'+data.color; } },{
  id: 'r',      val: function(data, key) { return data.r; } },{
  id: 'cx',     val: function(data, key) { return data.cx; } },{
  id: 'cy',     val: function(data, key) { return data.cy; } },{
  id: 'x',      val: function(data, key) { return data.x; } },{
  id: 'y',      val: function(data, key) { return data.y; } },{
  id: 'width',  val: function(data, key) { return data.width; } },{
  id: 'height', val: function(data, key) { return data.height; } },];

function vectic(vecticParams) {
  vecticParams = vecticParams || {};
  var _vectic = this;
  _vectic.id = vecticParams.id;
  _vectic.type = vecticParams.type || 'vectic';

  // TODO: Use dataWrapper?
  _vectic.rootID = 'v'+_vectic.id+'_id'+(_vecticUID+=1);
  _vectic.rootElementId = null;
  _vectic.targetObject = vecticParams.target;

  _vectic.svgDom = null;                      // Vectic DOM object (set in _vectic.getDoms)
  _vectic.objectContainerDom = null;          // Vectic DOM object (set in _vectic.getDoms)
  _vectic.templateContainerDom = null;        // Vectic DOM object (set in _vectic.getDoms)
  _vectic.paletteContainerDom = null;         // Vectic DOM object (set in _vectic.getDoms)
  _vectic.templateEditContainerDom = null;    // Vectic DOM object (set in _vectic.getDoms)

  _vectic.Firebase = Firebase;
  if(!_vectic.Firebase) { return console.error('vectic(): could not find Firebase library'); }

  _vectic.pathBase = vecticParams.basePath || 'http://vecticdev.firebaseio.com/';
  _vectic.firebaseRef = null;

  _vectic.connect = function() {
    _vectic.firebaseRef = new _vectic.Firebase(_vectic.pathBase);
  };

  _vectic.initStyles = function() {
    console.log('_vectic.initStyles')
    // Add css styles and reusable content to  if not already added
    if($('body #vecticStyler').length) {return;}

    var vecticStyler = $('');
    $('body').append(vecticStyler);
  };

  _vectic.initHTML = function() {
    console.log('_vectic.initHTML')
    if(!_vectic.targetObject) {return console.error('vectic: Target object missing');}
    _vectic.targetObject.html(_htmlBoiler.replace('{{ROOTID}}', _vectic.rootID));
    // TODO: replace w=this with the dataWrapper?
    _vectic.targetObjectSvg = ($(_vectic.targetObject)).find('svg').get(0);
  };

  _vectic.getDoms = function() {
    console.log('_vectic.getDoms')
    _vectic.svgDom                    = $('svg#'+_vectic.rootID).get(0);
    _vectic.objectContainerDom        = $('svg#'+_vectic.rootID+' g#objects').get(0);
    _vectic.templateContainerDom      = $('svg#'+_vectic.rootID+' defs#templates').get(0);
    _vectic.paletteContainerDom       = $('svg#'+_vectic.rootID+' defs#palettes').get(0);
    _vectic.templateEditContainerDom  = $('svg#'+_vectic.rootID+' g#templates_edit').get(0);
  };

  _vectic.dataWrapper = function(dataWrapperParams) {
    dataWrapperParams = dataWrapperParams || {};
    var _dataWrapper = this;

    _dataWrapper.id = dataWrapperParams.id;
    _dataWrapper.type = dataWrapperParams.type;
    _dataWrapper.elementId = null;      // HTML DOM Object ID
    _dataWrapper.element = null;        // HTML DOM Object (JQuery)
    _dataWrapper.ref = null;            // Firebase connection reference
    _dataWrapper.val = null;            // Snapshot data

    // Decide on data path and html element ID based on type
    switch(_dataWrapper.type) {
      case 'vectic':
        _dataWrapper.elementId = 'v'+_dataWrapper.id;
        _dataWrapper.path = 'vectic/'+_dataWrapper.id;
        break;
      case 'templateedit':
        // TODO: When rendering template content as vectic internal content for user interaction
        _dataWrapper.elementId = 't'+_dataWrapper.id;
        _dataWrapper.path = 'template/'+_dataWrapper.id;
        break;
      case 'template':
        _dataWrapper.elementId = 't'+_dataWrapper.id;
        _dataWrapper.path = 'template/'+_dataWrapper.id;
        break;
      case 'palette':
        _dataWrapper.elementId = 'p'+_dataWrapper.id;
        _dataWrapper.path = 'palette/'+_dataWrapper.id;
        break;
      case 'object':
        _dataWrapper.elementId = 'o'+_dataWrapper.id;
        _dataWrapper.path = 'object/'+_dataWrapper.id;
        break;
    }

    if(!_dataWrapper.id)         { return console.error('vectic.dataWrapper() missing "id" parameter'); }
    if(!_dataWrapper.type)       { return console.error('vectic.dataWrapper() missing "type" parameter'); }
    if(!_dataWrapper.elementId)  { return console.error('vectic.dataWrapper() missing "elementId"'); }

    _dataWrapper.redraw = function() {
      if(!_dataWrapper.val) {
        console.error('_dataWrapper.redraw(): no val available');
      }

      var newElement = null;
      // TODO: Create DOM Object
      switch(_dataWrapper.type) {
        case 'vectic':
          console.log('_dataWrapper.val: ')
          console.log(_dataWrapper.val)
          // Set viewBox
          var viewBox = '0 0 '+_dataWrapper.val.settings.width+' '+_dataWrapper.val.settings.height;
          _vectic.svgDom.setAttributeNS(null, 'viewBox', viewBox);

          // Set palette
          if(_dataWrapper.val.palette) {
            _vectic.svgDom.setAttributeNS(null, 'class', 'p'+_dataWrapper.val.palette);
          }
          break;
        case 'template':
          newElement = document.createElementNS('http://www.w3.org/2000/svg', ('def'));
          break;
        case 'palette':
          // TODO:
          break;
        case 'object':
          newElement = document.createElementNS('http://www.w3.org/2000/svg', ('use'));
          // TODO:
          break;
      }

      console.log('newElement '+_dataWrapper.type+':')
      console.log(newElement)

      // TODO: ^ Above: Add default behaviour (exit without redrawing with error)

      // TODO: Insert inner text from _dataWrapper.val

      // TODO: Apply attributes from _dataWrapper.val

      // TODO: DOM Object to corresponding container DOM element (which triggers html redraw)
      switch(_dataWrapper.type) {
        case 'vectic':
          // TODO:
          break;
        case 'templateedit':
          // TODO: When rendering template content as vectic internal content for user interaction
          break;
        case 'template':
          // Draw child elements
          for(var sChildId in _dataWrapper.val.elements) {
            var childElement = _dataWrapper.val.elements[sChildId];
            if(_vecticTags.indexOf(childElement.tag)<0) { console.error('_dataWrapper.redrawChildElement: tag "'+childElement.tag+'" not supported'); continue; }

            var newChildElement = document.createElementNS('http://www.w3.org/2000/svg', (childElement.tag));
            for(var iAtt in _vecticTagAttributes) {
              var att = _vecticTagAttributes[iAtt];
              var id = att.id;
              var val = att.val(childElement, key);
              var ns = att.ns || null;
              if([null, undefined].indexOf(val)<0) {
                newChildElement.setAttributeNS(ns, id, val);
              }
            }

            newElement.append(newChildElement);
          }

          if(_dataWrapper.element) { _dataWrapper.element.replaceWith(newElement); }
          else if(_vectic.templateContainerDom) { _vectic.templateContainerDom.append(newElement); }    // Append new object
          else { console.error('_dataWrapper.redraw(): type="'+_dataWrapper.type+'": nowhere to draw'); }
          break;
        case 'palette':
          // TODO:
          break;
        case 'object':
          if(_dataWrapper.element) { _dataWrapper.element.replaceWith(newElement); }      // Replace existing element
          else if(_vectic.objectContainerDom) { _vectic.objectContainerDom.append(newElement); }    // Append new object
          else { console.error('_dataWrapper.redraw(): type="'+_dataWrapper.type+'": nowhere to draw'); }
          // TODO:
          break;
      }

      console.log('newElement post population:')
      console.log(newElement)

      if(newElement) {
        _dataWrapper.element = newElement;
      }
    };

    console.log('test 1')
    console.log(_dataWrapper.path)
    console.log(_vectic.firebaseRef)

    if(_vectic.firebaseRef && _dataWrapper.path) {
      _dataWrapper.ref = _vectic.firebaseRef.child(_dataWrapper.path);

      _dataWrapper.ref.on('value', function(snapshot) {
        console.log('on value snapshot: ')
        console.log(snapshot)

        _dataWrapper.val = snapshot.val();
        _dataWrapper.redraw();
      });
    }

    // TODO:
    _dataWrapperItems[_dataWrapper.elementId] = _dataWrapper;
  };

  _vectic.init = function() {
    if(!_vectic.Firebase) {return console.error('vectic.init(): Missing Firebase library');}
    _vectic.connect();
    _vectic.initStyles();
    _vectic.initHTML();
    _vectic.getDoms();

    if(_vectic.id) {
      // TODO:
      var newWrapper = new _vectic.dataWrapper({
        id:   _vectic.id,
        type: _vectic.type,
      });
    }

    // TODO:
  };

  _vectic.getObjectsRef = function() {
    console.log('TODO: Stop calling _vectic.getObjectsRef! OR, you know, code this function');
  };
}<|endoftext|>


<commit_before>module.exports = function (grunt) {

    /**
     * List of files, per type, provided via bower in the vendor/ directory.
     */
    var vendor = {
        js: [
            'vendor/jquery/dist/jquery.js',
            'vendor/angular/angular.js',
            'vendor/angular-ui-router/release/angular-ui-router.js',
            'vendor/angular-sanitize/angular-sanitize.js',
            'vendor/angular-bootstrap/ui-bootstrap-tpls.js'
        ],
        fonts: [
            'vendor/bootstrap/fonts/glyphicons-halflings-regular.*'
        ]
    };

    grunt.initConfig({

        /**
         * Reads the `package.json` so that its data is available to the Grunt tasks.
         */
        pkg: grunt.file.readJSON('package.json'),

        /**
         * Cleaning all directories
         */
        clean: [
            'target/dev',
            'target/prod',
            'src/assets/main.css'
        ],

        /**
         * Copy of files
         */
        copy: {
            /**
             * Direct copy of JS files in `dev` mode
             */
            dev_js: {
                files: [
                    {
                        cwd: 'src',
                        src: [ '**/*.js' ],
                        dest: 'target/dev',
                        expand: true
                    }
                ]
            },
            /**
             * Copy of application assets
             */
            dev_assets: {
                files: [
                    {
                        cwd: 'src/assets',
                        src: [ '**' ],
                        dest: 'target/dev/assets',
                        expand: true
                    }
                ]
            },
            /**
             * Copy of vendor JS files
             */
            dev_vendor_js: {
                files: [
                    {
                        src: vendor.js,
                        dest: 'target/dev',
                        cwd: '.',
                        expand: true
                    }
                ]
            },
            /**
             * Copy of vendor fonts
             */
            dev_vendor_fonts: {
                files: [
                    {
                        src: vendor.fonts,
                        dest: 'target/dev/app/fonts',
                        cwd: '.',
                        expand: true,
                        flatten: true
                    }
                ]
            },
            /**
             * PROD: Copy of application assets
             */
            prod_assets: {
                files: [
                    {
                        cwd: 'src/assets',
                        src: [ '**' ],
                        dest: 'target/prod/assets',
                        expand: true
                    }
                ]
            }
        },

        /**
         * Less transformation.
         */
        less: {
            dev: {
                files: [
                    {
                        'target/dev/assets/main.css': 'src/less/**/*.less'
                    }
                ]
            },
            prod: {
                options: {
                    compress: true
                },
                files: [
                    {
                        'target/include/assets/main.css': 'src/less/**/*.less'
                    }
                ]
            }
        },

        /**
         * `ngmin` annotates the sources before minifying. That is, it allows us
         * to code without the array syntax in AngularJS.
         */
        ngmin: {
            prod: {
                files: [
                    {
                        src: [ '**/*.js' ],
                        cwd: 'src',
                        dest: 'target/include',
                        expand: true
                    }
                ]
            }
        },

        /**
         * Inclusion of sources
         */
        includeSource: {
            dev: {
                options: {
                    basePath: 'target/dev',
                    baseUrl: ''
                },
                files: {
                    'target/dev/index.html': 'src/index.html'
                }
            }
        }

    });

    /**
     * Loading the plug-ins.
     */

    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-ngmin');
    grunt.loadNpmTasks('grunt-html2js');
    grunt.loadNpmTasks('grunt-include-source');

    /**
     * Registering the tasks
     */

    /**
     * The default task is to prod.
     */
    grunt.registerTask('default', [ 'prod' ]);

    /**
     * The `dev` task gets your app ready to run for development and testing.
     */
    grunt.registerTask('dev', [
        'clean',
        // TODO 'jshint',
        'less:dev',
        'copy:dev_assets',
        // TODO 'copy:dev_vendor_assets',
        'copy:dev_js',
        // TODO 'copy:dev_apptpl',
        'copy:dev_vendor_js',
        'copy:dev_vendor_fonts',
        // TODO 'copy:dev_vendorcss',
        // TODO 'html2js:dev',
        'includeSource:dev'
    ]);

    /**
     * The `prod` task gets your app ready for deployment by concatenating and
     * minifying your code.
     */
    grunt.registerTask('prod', [
        'clean',
        'less:prod',
        'copy:prod_assets',
        // TODO 'html2js:prod',
        'ngmin:prod'
        // TODO 'concat:prod_js',
        // TODO 'concat:prod_css',
        // TODO 'uglify:prod',
        // TODO 'index:prod',
        // TODO 'copy:prod_vendor_fonts'
    ]);

};<commit_msg>Web: production build - concatenation of JS & CSS<commit_after>module.exports = function (grunt) {

    /**
     * List of files, per type, provided via bower in the vendor/ directory.
     */
    var vendor = {
        js: [
            'vendor/jquery/dist/jquery.js',
            'vendor/angular/angular.js',
            'vendor/angular-ui-router/release/angular-ui-router.js',
            'vendor/angular-sanitize/angular-sanitize.js',
            'vendor/angular-bootstrap/ui-bootstrap-tpls.js'
        ],
        fonts: [
            'vendor/bootstrap/fonts/glyphicons-halflings-regular.*'
        ]
    };

    grunt.initConfig({

        /**
         * Reads the `package.json` so that its data is available to the Grunt tasks.
         */
        pkg: grunt.file.readJSON('package.json'),

        /**
         * Cleaning all directories
         */
        clean: [
            'target/dev',
            'target/prod',
            'src/assets/main.css'
        ],

        /**
         * Copy of files
         */
        copy: {
            /**
             * Direct copy of JS files in `dev` mode
             */
            dev_js: {
                files: [
                    {
                        cwd: 'src',
                        src: [ '**/*.js' ],
                        dest: 'target/dev',
                        expand: true
                    }
                ]
            },
            /**
             * Copy of application assets
             */
            dev_assets: {
                files: [
                    {
                        cwd: 'src/assets',
                        src: [ '**' ],
                        dest: 'target/dev/assets',
                        expand: true
                    }
                ]
            },
            /**
             * Copy of vendor JS files
             */
            dev_vendor_js: {
                files: [
                    {
                        src: vendor.js,
                        dest: 'target/dev',
                        cwd: '.',
                        expand: true
                    }
                ]
            },
            /**
             * Copy of vendor fonts
             */
            dev_vendor_fonts: {
                files: [
                    {
                        src: vendor.fonts,
                        dest: 'target/dev/app/fonts',
                        cwd: '.',
                        expand: true,
                        flatten: true
                    }
                ]
            },
            /**
             * PROD: Copy of application assets
             */
            prod_assets: {
                files: [
                    {
                        cwd: 'src/assets',
                        src: [ '**' ],
                        dest: 'target/prod/assets',
                        expand: true
                    }
                ]
            }
        },

        /**
         * Less transformation.
         */
        less: {
            dev: {
                files: [
                    {
                        'target/dev/assets/main.css': 'src/less/**/*.less'
                    }
                ]
            },
            prod: {
                options: {
                    compress: true
                },
                files: [
                    {
                        'target/include/assets/main.css': 'src/less/**/*.less'
                    }
                ]
            }
        },

        /**
         * `ngmin` annotates the sources before minifying. That is, it allows us
         * to code without the array syntax in AngularJS.
         */
        ngmin: {
            prod: {
                files: [
                    {
                        src: [ '**/*.js' ],
                        cwd: 'src',
                        dest: 'target/include',
                        expand: true
                    }
                ]
            }
        },

        /**
         * `grunt concat` concatenates multiple source files into a single file.
         */
        concat: {
            /**
             * The `prod_js` target is the concatenation of our application source
             * code and all specified vendor source code into a single file.
             */
            prod_js: {
                src: [
                    'target/include/**/*.js'
                ],
                dest: 'target/prod/assets/<%= pkg.name %>-<%= pkg.version %>.js'
            },
            /**
             * The `prod_css` target is the concatenation of our application source
             * code and all specified vendor source code into a single file.
             */
            prod_css: {
                src: [
                    'target/include/**/*.css'
                ],
                dest: 'target/prod/assets/<%= pkg.name %>-<%= pkg.version %>.css'
            }
        },

        /**
         * Inclusion of sources
         */
        includeSource: {
            dev: {
                options: {
                    basePath: 'target/dev',
                    baseUrl: ''
                },
                files: {
                    'target/dev/index.html': 'src/index.html'
                }
            }
        }

    });

    /**
     * Loading the plug-ins.
     */

    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-ngmin');
    grunt.loadNpmTasks('grunt-html2js');
    grunt.loadNpmTasks('grunt-include-source');

    /**
     * Registering the tasks
     */

    /**
     * The default task is to prod.
     */
    grunt.registerTask('default', [ 'prod' ]);

    /**
     * The `dev` task gets your app ready to run for development and testing.
     */
    grunt.registerTask('dev', [
        'clean',
        // TODO 'jshint',
        'less:dev',
        'copy:dev_assets',
        // TODO 'copy:dev_vendor_assets',
        'copy:dev_js',
        // TODO 'copy:dev_apptpl',
        'copy:dev_vendor_js',
        'copy:dev_vendor_fonts',
        // TODO 'copy:dev_vendorcss',
        // TODO 'html2js:dev',
        'includeSource:dev'
    ]);

    /**
     * The `prod` task gets your app ready for deployment by concatenating and
     * minifying your code.
     */
    grunt.registerTask('prod', [
        'clean',
        'less:prod',
        'copy:prod_assets',
        // TODO 'html2js:prod',
        'ngmin:prod',
        'concat:prod_js',
        'concat:prod_css'
        // TODO 'uglify:prod',
        // TODO 'index:prod',
        // TODO 'copy:prod_vendor_fonts'
    ]);

};<|endoftext|>


<commit_before>/*
 * Copyright 2013 The Closure Compiler Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Definitions for the JS Internationalization API as defined in
 * http://www.ecma-international.org/ecma-402/1.0/
 *
 * @externs
 */

/** @const */
var Intl = {};

/**
 * NOTE: this API is not from ecma402 and is subject to change.
 * @param {string|Array<string>=} locales
 * @param {{type: (string|undefined)}=}
 *         options
 * @constructor
 */
Intl.v8BreakIterator = function(locales, options) {};

/**
 * @param {string} text
 * @return {undefined}
 */
Intl.v8BreakIterator.prototype.adoptText = function(text) {};

/**
 * @return {string}
 */
Intl.v8BreakIterator.prototype.breakType = function() {};

/**
 * @return {number}
 */
Intl.v8BreakIterator.prototype.current = function() {};

/**
 * @return {number}
 */
Intl.v8BreakIterator.prototype.first = function() {};

/**
 * @return {number}
 */
Intl.v8BreakIterator.prototype.next = function() {};

/**
 * @constructor
 * @param {string|Array<string>=} locales
 * @param {{usage: (string|undefined), localeMatcher: (string|undefined),
 *     sensitivity: (string|undefined), ignorePunctuation: (boolean|undefined),
 *     numeric: (boolean|undefined), caseFirst: (string|undefined)}=}
 *         options
 */
Intl.Collator = function(locales, options) {};

/**
 * @param {Array<string>} locales
 * @param {{localeMatcher: (string|undefined)}=} options
 * @return {Array<string>}
 */
Intl.Collator.supportedLocalesOf = function(locales, options) {};

/**
 * @param {string} arg1
 * @param {string} arg2
 * @return {number}
 */
Intl.Collator.prototype.compare = function(arg1, arg2) {};

/**
 * @return {{locale: string, usage: string, sensitivity: string,
 *     ignorePunctuation: boolean, collation: string, numeric: boolean,
 *     caseFirst: string}}
 */
Intl.Collator.prototype.resolvedOptions = function() {};

/**
 * @constructor
 * @param {string|Array<string>=} locales
 * @param {{
 *     notation: (string|undefined),
 *     localeMatcher: (string|undefined), useGrouping: (boolean|undefined),
 *     numberingSystem: (string|undefined), style: (string|undefined),
 *     currency: (string|undefined), currencyDisplay: (string|undefined),
 *     minimumIntegerDigits: (number|undefined),
 *     minimumFractionDigits: (number|undefined),
 *     maximumFractionDigits: (number|undefined),
 *     minimumSignificantDigits: (number|undefined),
 *     maximumSignificantDigits: (number|undefined),
 *     compactDisplay: (string|undefined), currencySign: (string|undefined),
 *     signDisplay: (string|undefined), unit: (string|undefined),
 *     unitDisplay: (string|undefined)
 *     }=}
 *         options
 */
Intl.NumberFormat = function(locales, options) {};

/**
 * @param {Array<string>} locales
 * @param {{localeMatcher: (string|undefined)}=} options
 * @return {Array<string>}
 */
Intl.NumberFormat.supportedLocalesOf = function(locales, options) {};

/**
 * @param {number} num
 * @return {string}
 */
Intl.NumberFormat.prototype.format = function(num) {};

/**
 * @param {number} num
 * @return {!Array<{type: string, value: string}>}
 * @see http://www.ecma-international.org/ecma-402/#sec-intl.numberformat.prototype.formattoparts
 */
Intl.NumberFormat.prototype.formatToParts = function(num) {};

/**
 * @return {{locale: string, numberingSystem: string, style: string,
 *     currency: (string|undefined), currencyDisplay: (string|undefined),
 *     minimumIntegerDigits: number, minimumFractionDigits: number,
 *     maximumFractionDigits: number, minimumSignificantDigits: number,
 *     maximumSignificantDigits: number, useGrouping: boolean,
 *     compactDisplay: (string|undefined), currencySign: (string|undefined),
 *     signDisplay: (string|undefined), unit: (string|undefined),
 *     unitDisplay: (string|undefined)}}
 */
Intl.NumberFormat.prototype.resolvedOptions = function() {};

/**
 * @constructor
 * @param {string|Array<string>=} locales
 * @param {{localeMatcher: (string|undefined),
 *    formatMatcher: (string|undefined), calendar: (string|undefined),
 *    numberingSystem: (string|undefined), tz: (string|undefined),
 *    weekday: (string|undefined), era: (string|undefined),
 *    year: (string|undefined), month: (string|undefined),
 *    day: (string|undefined), hour: (string|undefined),
 *    minute: (string|undefined), second: (string|undefined),
 *    timeZoneName: (string|undefined), hour12: (boolean|undefined),
 *    dateStyle: (string|undefined), timeStyle: (string|undefined),
 *    timeZone: (string|undefined), dayPeriod: (string|undefined),
 *    hourCycle: (string|undefined),
 *    fractionalSecondDigits: (number|undefined)}=}
 *        options
 */
Intl.DateTimeFormat = function(locales, options) {};

/**
 * @param {Array<string>} locales
 * @param {{localeMatcher: string}=} options
 * @return {Array<string>}
 */
Intl.DateTimeFormat.supportedLocalesOf = function(locales, options) {};

/**
 * @param {(!Date|number)=} date
 * @return {string}
 */
Intl.DateTimeFormat.prototype.format = function(date) {};

/**
 * @param {(!Date|number)=} date
 * @return {Array<{type: string, value: string}>}
 */
Intl.DateTimeFormat.prototype.formatToParts = function(date) {};

/**
 * @return {{locale: string, calendar: string, numberingSystem: string,
 *    timeZone: (string|undefined), weekday: (string|undefined),
 *    era: (string|undefined), year: (string|undefined),
 *    month: (string|undefined), day: (string|undefined),
 *    hour: (string|undefined), minute: (string|undefined),
 *    second: (string|undefined), timeZoneName: (string|undefined),
 *    hour12: (boolean|undefined),
 *    dateStyle: (string|undefined), datimeStyle: (string|undefined),
 *    dayPeriod: (string|undefined), hourCycle: (string|undefined),
 *    fractionalSecondDigits: (number|undefined)}}
 */
Intl.DateTimeFormat.prototype.resolvedOptions = function() {};

/**
 * @constructor
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules#Syntax
 * @param {string|Array<string>=} locales
 * @param {{localeMatcher: (string|undefined), type: (string|undefined),
 *     minimumIntegerDigits: (number|undefined),
 *     minimumFractionDigits: (number|undefined),
 *     maximumFractionDigits: (number|undefined),
 *     minimumSignificantDigits: (number|undefined),
 *     maximumSignificantDigits: (number|undefined)}=}
 *         options
 */
Intl.PluralRules = function(locales, options) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules/supportedLocalesOf#Syntax
 * @param {Array<string>} locales
 * @param {{localeMatcher: string}=} options
 * @return {Array<string>}
 */
Intl.PluralRules.supportedLocalesOf = function(locales, options) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules/resolvedOptions#Syntax
 * @return {{locale: string, pluralCategories: Array<string>, type: string,
 *            minimumIntegerDigits: number, minimumFractionDigits: number,
 *            maximumFractionDigits: number, minimumSignificantDigits: number,
 *            maximumSignificantDigits: number }}
 */
Intl.PluralRules.prototype.resolvedOptions = function() {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules/select#Syntax
 * @param {number} number
 * @return {string}
 */
Intl.PluralRules.prototype.select = function(number) {};

/**
 * @constructor
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat#Syntax
 * @param {string|Array<string>=} locales
 * @param {{localeMatcher: (string|undefined),
 *    numeric: (string|undefined),
 *    style: (string|undefined)}=}
 *        options
 */
Intl.RelativeTimeFormat = function(locales, options) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat/supportedLocalesOf#Syntax
 * @param {Array<string>} locales
 * @param {{localeMatcher: string}=} options
 * @return {Array<string>}
 */
Intl.RelativeTimeFormat.supportedLocalesOf = function(locales, options) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat/format#Syntax
 * @param {number} value
 * @param {string} unit
 * @return {string}
 */
Intl.RelativeTimeFormat.prototype.format = function(value, unit) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat/formatToParts#Syntax
 * @param {number} value
 * @param {string} unit
 * @return {Array<string>}
 */
Intl.RelativeTimeFormat.prototype.formatToParts = function(value, unit) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat/resolvedOptions#Syntax
 * @return {{locale: string, pluralCategories: Array<string>, type: string}}
 */
Intl.RelativeTimeFormat.prototype.resolvedOptions = function() {};

/**
 * @constructor
 * @param {string|Array<string>=} locales
 * @param {{
 *     localeMatcher: (string|undefined),
 *     type: (string|undefined),
 *     style: (string|undefined)
 *     }=} options
 */
Intl.ListFormat = function(locales, options) {};

/**
 * @param {Array<string>} locales
 * @param {{localeMatcher: (string|undefined)}=} options
 * @return {Array<string>}
 */
Intl.ListFormat.supportedLocalesOf = function(locales, options) {};

/**
 * @param {Array<string|number>} items
 * @return {string}
 */
Intl.ListFormat.prototype.format = function(items) {};

/**
 * @param {Array<string|number>} items
 * @return {!Array<{type: string, value: string}>}
 * @see http://www.ecma-international.org/ecma-402/#sec-intl.listformat.prototype.formattoparts
 */
Intl.ListFormat.prototype.formatToParts = function(items) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ListFormat/resolvedOptions#Syntax
 * @return {{locale: string, style: string, type: string}}
 */
Intl.ListFormat.prototype.resolvedOptions = function() {};
<commit_msg>Add ECMAScript Intl DateTimeFormat functions formatRange(...) and formatRangeToParts(...) externs.<commit_after>/*
 * Copyright 2013 The Closure Compiler Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Definitions for the JS Internationalization API as defined in
 * http://www.ecma-international.org/ecma-402/1.0/
 *
 * @externs
 */

/** @const */
var Intl = {};

/**
 * NOTE: this API is not from ecma402 and is subject to change.
 * @param {string|Array<string>=} locales
 * @param {{type: (string|undefined)}=}
 *         options
 * @constructor
 */
Intl.v8BreakIterator = function(locales, options) {};

/**
 * @param {string} text
 * @return {undefined}
 */
Intl.v8BreakIterator.prototype.adoptText = function(text) {};

/**
 * @return {string}
 */
Intl.v8BreakIterator.prototype.breakType = function() {};

/**
 * @return {number}
 */
Intl.v8BreakIterator.prototype.current = function() {};

/**
 * @return {number}
 */
Intl.v8BreakIterator.prototype.first = function() {};

/**
 * @return {number}
 */
Intl.v8BreakIterator.prototype.next = function() {};

/**
 * @constructor
 * @param {string|Array<string>=} locales
 * @param {{usage: (string|undefined), localeMatcher: (string|undefined),
 *     sensitivity: (string|undefined), ignorePunctuation: (boolean|undefined),
 *     numeric: (boolean|undefined), caseFirst: (string|undefined)}=}
 *         options
 */
Intl.Collator = function(locales, options) {};

/**
 * @param {Array<string>} locales
 * @param {{localeMatcher: (string|undefined)}=} options
 * @return {Array<string>}
 */
Intl.Collator.supportedLocalesOf = function(locales, options) {};

/**
 * @param {string} arg1
 * @param {string} arg2
 * @return {number}
 */
Intl.Collator.prototype.compare = function(arg1, arg2) {};

/**
 * @return {{locale: string, usage: string, sensitivity: string,
 *     ignorePunctuation: boolean, collation: string, numeric: boolean,
 *     caseFirst: string}}
 */
Intl.Collator.prototype.resolvedOptions = function() {};

/**
 * @constructor
 * @param {string|Array<string>=} locales
 * @param {{
 *     notation: (string|undefined),
 *     localeMatcher: (string|undefined), useGrouping: (boolean|undefined),
 *     numberingSystem: (string|undefined), style: (string|undefined),
 *     currency: (string|undefined), currencyDisplay: (string|undefined),
 *     minimumIntegerDigits: (number|undefined),
 *     minimumFractionDigits: (number|undefined),
 *     maximumFractionDigits: (number|undefined),
 *     minimumSignificantDigits: (number|undefined),
 *     maximumSignificantDigits: (number|undefined),
 *     compactDisplay: (string|undefined), currencySign: (string|undefined),
 *     signDisplay: (string|undefined), unit: (string|undefined),
 *     unitDisplay: (string|undefined)
 *     }=}
 *         options
 */
Intl.NumberFormat = function(locales, options) {};

/**
 * @param {Array<string>} locales
 * @param {{localeMatcher: (string|undefined)}=} options
 * @return {Array<string>}
 */
Intl.NumberFormat.supportedLocalesOf = function(locales, options) {};

/**
 * @param {number} num
 * @return {string}
 */
Intl.NumberFormat.prototype.format = function(num) {};

/**
 * @param {number} num
 * @return {!Array<{type: string, value: string}>}
 * @see http://www.ecma-international.org/ecma-402/#sec-intl.numberformat.prototype.formattoparts
 */
Intl.NumberFormat.prototype.formatToParts = function(num) {};

/**
 * @return {{locale: string, numberingSystem: string, style: string,
 *     currency: (string|undefined), currencyDisplay: (string|undefined),
 *     minimumIntegerDigits: number, minimumFractionDigits: number,
 *     maximumFractionDigits: number, minimumSignificantDigits: number,
 *     maximumSignificantDigits: number, useGrouping: boolean,
 *     compactDisplay: (string|undefined), currencySign: (string|undefined),
 *     signDisplay: (string|undefined), unit: (string|undefined),
 *     unitDisplay: (string|undefined)}}
 */
Intl.NumberFormat.prototype.resolvedOptions = function() {};

/**
 * @constructor
 * @param {string|Array<string>=} locales
 * @param {{localeMatcher: (string|undefined),
 *    formatMatcher: (string|undefined), calendar: (string|undefined),
 *    numberingSystem: (string|undefined), tz: (string|undefined),
 *    weekday: (string|undefined), era: (string|undefined),
 *    year: (string|undefined), month: (string|undefined),
 *    day: (string|undefined), hour: (string|undefined),
 *    minute: (string|undefined), second: (string|undefined),
 *    timeZoneName: (string|undefined), hour12: (boolean|undefined),
 *    dateStyle: (string|undefined), timeStyle: (string|undefined),
 *    timeZone: (string|undefined), dayPeriod: (string|undefined),
 *    hourCycle: (string|undefined),
 *    fractionalSecondDigits: (number|undefined)}=}
 *        options
 */
Intl.DateTimeFormat = function(locales, options) {};

/**
 * @param {Array<string>} locales
 * @param {{localeMatcher: string}=} options
 * @return {Array<string>}
 */
Intl.DateTimeFormat.supportedLocalesOf = function(locales, options) {};

/**
 * @param {(!Date|number)=} date
 * @return {string}
 */
Intl.DateTimeFormat.prototype.format = function(date) {};

/**
 * @param {(!Date|number)=} date
 * @return {Array<{type: string, value: string}>}
 */
Intl.DateTimeFormat.prototype.formatToParts = function(date) {};

/**
 * @param {(!Date|number)=} date1
 * @param {(!Date|number)=} date2
 * @return {string}
 */
Intl.DateTimeFormat.prototype.formatRange = function(date1, date2) {};

/**
 * @param {(!Date|number)=} date1
 * @param {(!Date|number)=} date2
 * @return {!Array<{type: string, value: string}>}
 */
Intl.DateTimeFormat.prototype.formatRangeToParts = function(date1, date2) {};

/**
 * @return {{locale: string, calendar: string, numberingSystem: string,
 *    timeZone: (string|undefined), weekday: (string|undefined),
 *    era: (string|undefined), year: (string|undefined),
 *    month: (string|undefined), day: (string|undefined),
 *    hour: (string|undefined), minute: (string|undefined),
 *    second: (string|undefined), timeZoneName: (string|undefined),
 *    hour12: (boolean|undefined),
 *    dateStyle: (string|undefined), datimeStyle: (string|undefined),
 *    dayPeriod: (string|undefined), hourCycle: (string|undefined),
 *    fractionalSecondDigits: (number|undefined)}}
 */
Intl.DateTimeFormat.prototype.resolvedOptions = function() {};

/**
 * @constructor
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules#Syntax
 * @param {string|Array<string>=} locales
 * @param {{localeMatcher: (string|undefined), type: (string|undefined),
 *     minimumIntegerDigits: (number|undefined),
 *     minimumFractionDigits: (number|undefined),
 *     maximumFractionDigits: (number|undefined),
 *     minimumSignificantDigits: (number|undefined),
 *     maximumSignificantDigits: (number|undefined)}=}
 *         options
 */
Intl.PluralRules = function(locales, options) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules/supportedLocalesOf#Syntax
 * @param {Array<string>} locales
 * @param {{localeMatcher: string}=} options
 * @return {Array<string>}
 */
Intl.PluralRules.supportedLocalesOf = function(locales, options) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules/resolvedOptions#Syntax
 * @return {{locale: string, pluralCategories: Array<string>, type: string,
 *            minimumIntegerDigits: number, minimumFractionDigits: number,
 *            maximumFractionDigits: number, minimumSignificantDigits: number,
 *            maximumSignificantDigits: number }}
 */
Intl.PluralRules.prototype.resolvedOptions = function() {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules/select#Syntax
 * @param {number} number
 * @return {string}
 */
Intl.PluralRules.prototype.select = function(number) {};

/**
 * @constructor
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat#Syntax
 * @param {string|Array<string>=} locales
 * @param {{localeMatcher: (string|undefined),
 *    numeric: (string|undefined),
 *    style: (string|undefined)}=}
 *        options
 */
Intl.RelativeTimeFormat = function(locales, options) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat/supportedLocalesOf#Syntax
 * @param {Array<string>} locales
 * @param {{localeMatcher: string}=} options
 * @return {Array<string>}
 */
Intl.RelativeTimeFormat.supportedLocalesOf = function(locales, options) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat/format#Syntax
 * @param {number} value
 * @param {string} unit
 * @return {string}
 */
Intl.RelativeTimeFormat.prototype.format = function(value, unit) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat/formatToParts#Syntax
 * @param {number} value
 * @param {string} unit
 * @return {Array<string>}
 */
Intl.RelativeTimeFormat.prototype.formatToParts = function(value, unit) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat/resolvedOptions#Syntax
 * @return {{locale: string, pluralCategories: Array<string>, type: string}}
 */
Intl.RelativeTimeFormat.prototype.resolvedOptions = function() {};

/**
 * @constructor
 * @param {string|Array<string>=} locales
 * @param {{
 *     localeMatcher: (string|undefined),
 *     type: (string|undefined),
 *     style: (string|undefined)
 *     }=} options
 */
Intl.ListFormat = function(locales, options) {};

/**
 * @param {Array<string>} locales
 * @param {{localeMatcher: (string|undefined)}=} options
 * @return {Array<string>}
 */
Intl.ListFormat.supportedLocalesOf = function(locales, options) {};

/**
 * @param {Array<string|number>} items
 * @return {string}
 */
Intl.ListFormat.prototype.format = function(items) {};

/**
 * @param {Array<string|number>} items
 * @return {!Array<{type: string, value: string}>}
 * @see http://www.ecma-international.org/ecma-402/#sec-intl.listformat.prototype.formattoparts
 */
Intl.ListFormat.prototype.formatToParts = function(items) {};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ListFormat/resolvedOptions#Syntax
 * @return {{locale: string, style: string, type: string}}
 */
Intl.ListFormat.prototype.resolvedOptions = function() {};
<|endoftext|>


<commit_before>a
<commit_msg>Update base58.js<commit_after>(function (Bitcoin) {
  Bitcoin.Base58 = {
    alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
    validRegex: /^[1-9A-HJ-NP-Za-km-z]+$/,
    base: BigInteger.valueOf(58),

    /**
     * Convert a byte array to a base58-encoded string.
     *
     * Written by Mike Hearn for BitcoinJ.
     *   Copyright (c) 2011 Google Inc.
     *
     * Ported to JavaScript by Stefan Thomas.
     */
    encode: function (input) {
      var bi = BigInteger.fromByteArrayUnsigned(input);
      var chars = [];

      while (bi.compareTo(B58.base) >= 0) {
        var mod = bi.mod(B58.base);
        chars.unshift(B58.alphabet[mod.intValue()]);
        bi = bi.subtract(mod).divide(B58.base);
      }
      chars.unshift(B58.alphabet[bi.intValue()]);

      // Convert leading zeros too.
      for (var i = 0; i < input.length; i++) {
        if (input[i] == 0x00) {
          chars.unshift(B58.alphabet[0]);
        } else break;
      }

      return chars.join('');
    },

    /**
     * Convert a base58-encoded string to a byte array.
     *
     * Written by Mike Hearn for BitcoinJ.
     *   Copyright (c) 2011 Google Inc.
     *
     * Ported to JavaScript by Stefan Thomas.
     */
    decode: function (input) {
      var bi = BigInteger.valueOf(0);
      var leadingZerosNum = 0;
      for (var i = input.length - 1; i >= 0; i--) {
        var alphaIndex = B58.alphabet.indexOf(input[i]);
        if (alphaIndex < 0) {
          throw "Invalid character";
        }
        bi = bi.add(BigInteger.valueOf(alphaIndex)
                    .multiply(B58.base.pow(input.length - 1 -i)));

        // This counts leading zero bytes
        if (input[i] == "1") leadingZerosNum++;
        else leadingZerosNum = 0;
      }
      var bytes = bi.toByteArrayUnsigned();

      // Add leading zeros
      while (leadingZerosNum-- > 0) bytes.unshift(0);

      return bytes;
    }
  };

  var B58 = Bitcoin.Base58;
})(
  'undefined' != typeof Bitcoin ? Bitcoin : module.exports
);
<|endoftext|>