Bilal #1

Merged
senaduka merged 10 commits from Bilal into master 2017-10-23 13:26:08 +02:00
29 changed files with 12019 additions and 133 deletions

4
.gitignore vendored
View File

@@ -1,13 +1,13 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
node_modules/
# testing
/coverage
# production
/build
build/
# misc
.DS_Store

12
README Normal file
View File

@@ -0,0 +1,12 @@
https://console.developers.google.com/start/api?id=sheets.googleapis.com
1. Use this wizard(Link above) to create or select a project in the Google Developers Console and automatically turn on the API. Click Continue, then Go to credentials.
2. On the Add credentials to your project page, click the Cancel button.
3. At the top of the page, select the OAuth consent screen tab. Select an Email address, enter a Product name if not already set, and click the Save button.
4. Select the Credentials tab, click the Create credentials button and select OAuth client ID.
5. Select the application type Other, enter the name "Google Sheets API Quickstart", and click the Create button.
6. Click OK to dismiss the resulting dialog.
7. Click the file_download (Download JSON) button to the right of the client ID.
8. Move this file to your working directory and rename it client_secret.json.

2
backend/.env Normal file
View File

@@ -0,0 +1,2 @@
PEOPLE_DB=https://docs.google.com/spreadsheets/d/1s4Ytz7mf-YpszVTMTTrYd5iG_dsTGjrCpDQbpIx7zkU/edit#gid=0
PAIRS_LIST=https://docs.google.com/spreadsheets/d/1gPuRhTry3YoJ_ibI2BfL1ue2_YLlhtW56OP39ADJY_4/edit#gid=0

283
backend/app.js Normal file
View File

@@ -0,0 +1,283 @@
const express = require('express')
const bodyParser = require("body-parser");
var fs = require('fs');
var readline = require('readline');
var google = require('googleapis');
var googleAuth = require('google-auth-library');
const app = express()
const router = express.Router();
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());
require('dotenv').config()
const PEOPLE_DB = process.env.PEOPLE_DB.split('/')[5];
const PAIRS_LIST = process.env.PAIRS_LIST.split('/')[5];
var SCOPES = ['https://www.googleapis.com/auth/spreadsheets'];
var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
process.env.USERPROFILE) + '/.credentials/';
var TOKEN_PATH = TOKEN_DIR + 'sheets.googleapis.com-nodejs-quickstart.json';
var oauth2Client = null;
var pairsForSave = [];
var lastRow = null; //last row with names
function executeAPI(callback1,callback2){
fs.readFile('client_secret.json', function processClientSecrets(err, content) {
console.log("reading client secret");
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the
// Google Sheets API.
authorize(JSON.parse(content), callback1, callback2);
});
}
function authorize(credentials, callback1, callback2){
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var auth = new googleAuth();
oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function(err, token) {
console.log(TOKEN_PATH);
if (err) {
getNewToken(callback1, callback2);
} else {
oauth2Client.credentials = JSON.parse(token);
callback1(callback2);
}
});
}
function getNewToken(callback1, callback2) {
var authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
console.log('Authorize this app by visiting this url: ', authUrl);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function(code) {
rl.close();
oauth2Client.getToken(code, function(err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
callback1(callback2);
});
});
}
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
} catch (err) {
if (err.code != 'EEXIST') {
throw err;
}
}
console.log(JSON.stringify(token));
fs.writeFile(TOKEN_PATH, JSON.stringify(token));
console.log('Token stored to ' + TOKEN_PATH);
}
function getPairs(callback){
auth=oauth2Client;
ranges = ['2017!A:A','2017!B:B']; //get all rows with names
var sheets = google.sheets('v4');
sheets.spreadsheets.values.batchGet({
auth: auth,
spreadsheetId: PAIRS_LIST,
ranges: ranges
}, function(err, result) {
if(err) {
// Handle error
console.log(err);
return null;
} else {
const pairs = [];
lastRow = result.valueRanges[0].values.length;
for (let i=0;i<lastRow;i++){
let name1 = result.valueRanges[0].values[i][0];
if (name1){
let name2 = result.valueRanges[1].values[i][0];
pairs.push({name1:name1,name2:name2});
}
}
callback(pairs);
}
});
}
function getAvailableNames(callback){
auth=oauth2Client;
ranges = ['\'Other preferences\'!A2:A','\'Other preferences\'!E2:E']; //get all rows with names
var sheets = google.sheets('v4');
sheets.spreadsheets.values.batchGet({
auth: auth,
spreadsheetId: PEOPLE_DB,
ranges: ranges
}, function(err, result) {
if(err) {
// Handle error
console.log(err);
return null;
} else {
const names = [];
for (let i=0;i<result.valueRanges[0].values.length;i++){
let name = result.valueRanges[0].values[i][0];
let available = result.valueRanges[1].values[i][0];
if (name && (available=='x')){
names.push(name);
}
}
callback(names);
}
});
}
function MakePairs(callback){
executeAPI(getAvailableNames,function(names){
executeAPI(getPairs, function(pairs){
let next_i=false;
const newPairs = [];
const usedNames = [];
for (let i=0;i<names.length;i++){
next_i=false;
for (let j=0;j<names.length;j++){
if (i!=j){
let found=false;
pairs.filter((pair)=>{
if ((pair.name1==names[i] && pair.name2==names[j])||(pair.name1==names[j] && pair.name2==names[i])){
found=true;
return;
}
});
if (!found){
usedNames.filter((name)=>{
if (names[i] === name || names[j] === name){
found=true;
return;
}
});
}
if (!found){
next_i=true;
newPairs.push({name1:names[i], name2:names[j]});
usedNames.push(names[i]);
usedNames.push(names[j]);
break;
}
}
}
if (next_i) continue;
}
pairsForSave=newPairs;
callback.send(newPairs);
});
});
//Napravi par -> Provjeri da li postoji -> Snimi ili ponovi postupak
}
function SavePairs(callback){
if (lastRow== null) return;
auth=oauth2Client;
const values_column1 = [];
const values_column2 = [];
for (let i=0;i<pairsForSave.length;i++){
values_column1.push([pairsForSave[i].name1]);
values_column2.push([pairsForSave[i].name2]);
}
const data = [];
let range1= '2017!A'+(lastRow+2)+':A'+(lastRow+2+pairsForSave.length);
let range2= '2017!B'+(lastRow+2)+':B'+(lastRow+2+pairsForSave.length);
data.push({
range:range1,
values: values_column1
});
data.push({
range:range2,
values: values_column2
});
var body = {
data: data,
valueInputOption:"RAW"
};
var sheets = google.sheets('v4');
sheets.spreadsheets.values.batchUpdate({
spreadsheetId: PAIRS_LIST,
auth:auth,
resource: body
}, function(err, result) {
if(err) {
// Handle error
console.log(err);
callback.send({result:false});
} else {
lastRow=null;
pairsForSave=[];
callback.send({result:true});
}
});
}
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Last-Record-Id, X-Total-Count");
res.header("Access-Control-Expose-Headers", "X-Last-Record-Id, X-Total-Count");
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
res.header('Access-Control-Allow-Credentials', 'true');
next();
});
app.get('/getPairs',(req,resp)=>{
pairsForSave=[];
lastRow=null;
MakePairs(resp);
});
app.get('/savePairs', (req,resp)=>{
SavePairs(resp);
//resp.send({result:true});
});
app.listen(3005, function () {
console.log('server na portu 3005');
})

View File

@@ -0,0 +1 @@
{"installed":{"client_id":"426416989518-ca129o4ckcmvkh3q3p8sfmbs3786ji04.apps.googleusercontent.com","project_id":"tribal-isotope-183115","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://accounts.google.com/o/oauth2/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"jWoubOnqBF87_eW2d4TdxR9F","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]}}

123
backend/google_api.js Normal file
View File

@@ -0,0 +1,123 @@
var fs = require('fs');
var readline = require('readline');
var google = require('googleapis');
var googleAuth = require('google-auth-library');
require('dotenv').config()
const PEOPLE_DB = process.env.PEOPLE_DB.split('/')[5];
const PAIRS_LIST = process.env.PAIRS_LIST.split('/')[5];
var SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly'];
var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
process.env.USERPROFILE) + '/.credentials/';
var TOKEN_PATH = TOKEN_DIR + 'sheets.googleapis.com-nodejs-quickstart.json';
var oauth2Client = null;
function executeAPI(callback){
fs.readFile('client_secret.json', function processClientSecrets(err, content) {
console.log("reading client secret");
if (err) {
console.log('Error loading client secret file: ' + err);
return;
}
// Authorize a client with the loaded credentials, then call the
// Google Sheets API.
return authorize(JSON.parse(content), callback);
});
}
function authorize(credentials, callback){
var clientSecret = credentials.installed.client_secret;
var clientId = credentials.installed.client_id;
var redirectUrl = credentials.installed.redirect_uris[0];
var auth = new googleAuth();
oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl);
// Check if we have previously stored a token.
fs.readFile(TOKEN_PATH, function(err, token) {
console.log(TOKEN_PATH);
if (err) {
getNewToken();
return callback();
} else {
oauth2Client.credentials = JSON.parse(token);
var resultat = callback();
console.log("resultat");
console.log(resultat);
//return callback();
}
});
}
function getNewToken() {
var authUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES
});
console.log('Authorize this app by visiting this url: ', authUrl);
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter the code from that page here: ', function(code) {
rl.close();
oauth2Client.getToken(code, function(err, token) {
if (err) {
console.log('Error while trying to retrieve access token', err);
return;
}
oauth2Client.credentials = token;
storeToken(token);
});
});
}
function storeToken(token) {
try {
fs.mkdirSync(TOKEN_DIR);
} catch (err) {
if (err.code != 'EEXIST') {
throw err;
}
}
console.log(JSON.stringify(token));
fs.writeFile(TOKEN_PATH, JSON.stringify(token));
console.log('Token stored to ' + TOKEN_PATH);
}
function getPairs(){
auth=oauth2Client;
ranges = ['2017!A:A','2017!B:B']; //get all rows with names
var sheets = google.sheets('v4');
sheets.spreadsheets.values.batchGet({
auth: auth,
spreadsheetId: PAIRS_LIST,
ranges: ranges
}, function(err, result) {
if(err) {
// Handle error
console.log(err);
return null;
} else {
const pairs = [];
for (let i=0;i<result.valueRanges[0].values.length;i++){
let name1 = result.valueRanges[0].values[i][0];
if (name1){
let name2 = result.valueRanges[1].values[i][0];
pairs.push({name1:name1,name2:name2});
}
}
console.log(pairs);
return pairs;
}
});
}
module.exports = {
getPairs: function{executeAPI(getPairs(callback));}
}

852
backend/package-lock.json generated Normal file
View File

@@ -0,0 +1,852 @@
{
"name": "backend",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"accepts": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
"integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",
"requires": {
"mime-types": "2.1.17",
"negotiator": "0.6.1"
}
},
"ajv": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz",
"integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=",
"requires": {
"co": "4.6.0",
"fast-deep-equal": "1.0.0",
"json-schema-traverse": "0.3.1",
"json-stable-stringify": "1.0.1"
}
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
"asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"async": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/async/-/async-2.3.0.tgz",
"integrity": "sha1-EBPRBRBH3TIP4k5JTVxm7K9hR9k=",
"requires": {
"lodash": "4.17.4"
}
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
},
"base64url": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz",
"integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs="
},
"bcrypt-pbkdf": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
"optional": true,
"requires": {
"tweetnacl": "0.14.5"
}
},
"body-parser": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
"integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
"requires": {
"bytes": "3.0.0",
"content-type": "1.0.4",
"debug": "2.6.9",
"depd": "1.1.1",
"http-errors": "1.6.2",
"iconv-lite": "0.4.19",
"on-finished": "2.3.0",
"qs": "6.5.1",
"raw-body": "2.3.2",
"type-is": "1.6.15"
}
},
"boom": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
"integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
"requires": {
"hoek": "4.2.0"
}
},
"buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
},
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"combined-stream": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
"requires": {
"delayed-stream": "1.0.0"
}
},
"content-disposition": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
"integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
},
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"cookie": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
"integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
},
"cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cryptiles": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
"integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
"requires": {
"boom": "5.2.0"
},
"dependencies": {
"boom": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
"integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
"requires": {
"hoek": "4.2.0"
}
}
}
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"requires": {
"assert-plus": "1.0.0"
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"depd": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
"integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"dotenv": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
"integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0="
},
"ecc-jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
"optional": true,
"requires": {
"jsbn": "0.1.1"
}
},
"ecdsa-sig-formatter": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz",
"integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=",
"requires": {
"base64url": "2.0.0",
"safe-buffer": "5.1.1"
}
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
"integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"express": {
"version": "4.16.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz",
"integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=",
"requires": {
"accepts": "1.3.4",
"array-flatten": "1.1.1",
"body-parser": "1.18.2",
"content-disposition": "0.5.2",
"content-type": "1.0.4",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "1.1.1",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"etag": "1.8.1",
"finalhandler": "1.1.0",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "1.1.2",
"on-finished": "2.3.0",
"parseurl": "1.3.2",
"path-to-regexp": "0.1.7",
"proxy-addr": "2.0.2",
"qs": "6.5.1",
"range-parser": "1.2.0",
"safe-buffer": "5.1.1",
"send": "0.16.1",
"serve-static": "1.13.1",
"setprototypeof": "1.1.0",
"statuses": "1.3.1",
"type-is": "1.6.15",
"utils-merge": "1.0.1",
"vary": "1.1.2"
}
},
"extend": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
"fast-deep-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8="
},
"finalhandler": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
"integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=",
"requires": {
"debug": "2.6.9",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"on-finished": "2.3.0",
"parseurl": "1.3.2",
"statuses": "1.3.1",
"unpipe": "1.0.0"
}
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
},
"form-data": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz",
"integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=",
"requires": {
"asynckit": "0.4.0",
"combined-stream": "1.0.5",
"mime-types": "2.1.17"
}
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"requires": {
"assert-plus": "1.0.0"
}
},
"google-auth-library": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-0.11.0.tgz",
"integrity": "sha512-vDHBtAjXHMR5T137Xu3ShPqUdABYGQFm6LZJJWtg0gKWfQCMIx1ebQygvr8gZrkHw/0cAjRJjr0sUPgDWfcg7w==",
"requires": {
"gtoken": "1.2.2",
"jws": "3.1.4",
"lodash.isstring": "4.0.1",
"lodash.merge": "4.6.0",
"request": "2.83.0"
}
},
"google-p12-pem": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-0.1.2.tgz",
"integrity": "sha1-M8RqsCGqc0+gMys5YKmj/8svMXc=",
"requires": {
"node-forge": "0.7.1"
}
},
"googleapis": {
"version": "22.2.0",
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-22.2.0.tgz",
"integrity": "sha1-/XnDwm5+caT1ouwafaX7EV2IU9I=",
"requires": {
"async": "2.3.0",
"google-auth-library": "0.10.0",
"string-template": "1.0.0"
},
"dependencies": {
"google-auth-library": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-0.10.0.tgz",
"integrity": "sha1-bhW6vuhf0d0U2NEoopW2g41SE24=",
"requires": {
"gtoken": "1.2.2",
"jws": "3.1.4",
"lodash.noop": "3.0.1",
"request": "2.83.0"
}
}
}
},
"gtoken": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-1.2.2.tgz",
"integrity": "sha1-Fyd2oanZasCfwioA9b6DzubeiCA=",
"requires": {
"google-p12-pem": "0.1.2",
"jws": "3.1.4",
"mime": "1.4.1",
"request": "2.83.0"
}
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
},
"har-validator": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
"integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
"requires": {
"ajv": "5.2.3",
"har-schema": "2.0.0"
}
},
"hawk": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
"integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
"requires": {
"boom": "4.3.1",
"cryptiles": "3.1.2",
"hoek": "4.2.0",
"sntp": "2.0.2"
}
},
"hoek": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
"integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ=="
},
"http-errors": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
"integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
"requires": {
"depd": "1.1.1",
"inherits": "2.0.3",
"setprototypeof": "1.0.3",
"statuses": "1.3.1"
},
"dependencies": {
"setprototypeof": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
"integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
}
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"requires": {
"assert-plus": "1.0.0",
"jsprim": "1.4.1",
"sshpk": "1.13.1"
}
},
"iconv-lite": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ipaddr.js": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz",
"integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A="
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"optional": true
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"json-stable-stringify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
"requires": {
"jsonify": "0.0.0"
}
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"jsonify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
}
},
"jwa": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz",
"integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=",
"requires": {
"base64url": "2.0.0",
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.9",
"safe-buffer": "5.1.1"
}
},
"jws": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz",
"integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=",
"requires": {
"base64url": "2.0.0",
"jwa": "1.1.5",
"safe-buffer": "5.1.1"
}
},
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
"integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
},
"lodash.merge": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz",
"integrity": "sha1-aYhLoUSsM/5plzemCG3v+t0PicU="
},
"lodash.noop": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-3.0.1.tgz",
"integrity": "sha1-OBiPTWUKOkdCWEObluxFsyYXEzw="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
},
"merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
},
"mime": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
},
"mime-db": {
"version": "1.30.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
"integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
},
"mime-types": {
"version": "2.1.17",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
"integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
"requires": {
"mime-db": "1.30.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
},
"node-forge": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.1.tgz",
"integrity": "sha1-naYR6giYL0uUIGs760zJZl8gwwA="
},
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"parseurl": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
},
"path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"proxy-addr": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz",
"integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=",
"requires": {
"forwarded": "0.1.2",
"ipaddr.js": "1.5.2"
}
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
},
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
},
"range-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
},
"raw-body": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
"integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
"requires": {
"bytes": "3.0.0",
"http-errors": "1.6.2",
"iconv-lite": "0.4.19",
"unpipe": "1.0.0"
}
},
"request": {
"version": "2.83.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
"integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
"requires": {
"aws-sign2": "0.7.0",
"aws4": "1.6.0",
"caseless": "0.12.0",
"combined-stream": "1.0.5",
"extend": "3.0.1",
"forever-agent": "0.6.1",
"form-data": "2.3.1",
"har-validator": "5.0.3",
"hawk": "6.0.2",
"http-signature": "1.2.0",
"is-typedarray": "1.0.0",
"isstream": "0.1.2",
"json-stringify-safe": "5.0.1",
"mime-types": "2.1.17",
"oauth-sign": "0.8.2",
"performance-now": "2.1.0",
"qs": "6.5.1",
"safe-buffer": "5.1.1",
"stringstream": "0.0.5",
"tough-cookie": "2.3.3",
"tunnel-agent": "0.6.0",
"uuid": "3.1.0"
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"send": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz",
"integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==",
"requires": {
"debug": "2.6.9",
"depd": "1.1.1",
"destroy": "1.0.4",
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"etag": "1.8.1",
"fresh": "0.5.2",
"http-errors": "1.6.2",
"mime": "1.4.1",
"ms": "2.0.0",
"on-finished": "2.3.0",
"range-parser": "1.2.0",
"statuses": "1.3.1"
}
},
"serve-static": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz",
"integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==",
"requires": {
"encodeurl": "1.0.1",
"escape-html": "1.0.3",
"parseurl": "1.3.2",
"send": "0.16.1"
}
},
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
},
"sntp": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz",
"integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=",
"requires": {
"hoek": "4.2.0"
}
},
"sshpk": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
"requires": {
"asn1": "0.2.3",
"assert-plus": "1.0.0",
"bcrypt-pbkdf": "1.0.1",
"dashdash": "1.14.1",
"ecc-jsbn": "0.1.1",
"getpass": "0.1.7",
"jsbn": "0.1.1",
"tweetnacl": "0.14.5"
}
},
"statuses": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
"integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
},
"string-template": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/string-template/-/string-template-1.0.0.tgz",
"integrity": "sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y="
},
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
},
"tough-cookie": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
"requires": {
"punycode": "1.4.1"
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"requires": {
"safe-buffer": "5.1.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"optional": true
},
"type-is": {
"version": "1.6.15",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
"integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
"requires": {
"media-typer": "0.3.0",
"mime-types": "2.1.17"
}
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"requires": {
"assert-plus": "1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "1.3.0"
}
}
}
}

18
backend/package.json Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.18.2",
"dotenv": "^4.0.0",
"express": "^4.16.2",
"google-auth-library": "^0.11.0",
"googleapis": "^22.2.0"
}
}

View File

@@ -1,130 +0,0 @@
import React, { Component } from 'react';
import './App.css';
import PersonsListComponent from './PersonsListComponent.js';
class App extends Component {
constructor(props){
super(props);
this.state = {renderPersonsList: false, persons: [], currentPairsText: ""};
this.getNamesEventHandler = this.getNamesEventHandler.bind(this);
this.createTableEventHandler = this.createTableEventHandler.bind(this);
this.addAndSaveEventHandler = this.addAndSaveEventHandler.bind(this);
this.pairsTextChangedEventHandler = this.pairsTextChangedEventHandler.bind(this);
this.personsSelectionChangedEventHandler = this.personsSelectionChangedEventHandler.bind(this);
}
componentDidMount(){
this.currentPairs = JSON.parse(localStorage.getItem("currentPairs") || "[]");
this.currentPersons = JSON.parse(localStorage.getItem("currentPersons") || "[]");
// Load textarea text from local storage
this.setState({currentPairsText: JSON.parse(localStorage.getItem("currentPairsText")) || ""});
}
pairsTextChangedEventHandler(event) {
this.setState({currentPairsText: event.target.value});
}
getNamesEventHandler(event) {
if(this.state.currentPairsText.trim() === "")
return;
let allNames = this.state.currentPairsText.trim().replace(/\n\s*\n/g, '\n').replace(/(\r\n|\n|\r)/gm, "|").split("|");
allNames = allNames.map(name => name.trim());
console.log(allNames);
let names = [...new Set(allNames)];
if(this.currentPersons.length === 0)
this.currentPersons = names;
else{
// Check if there are some new names
let newNames = names.filter(name => !this.currentPersons.includes(name));
for(const newName of newNames)
this.currentPersons.push(newName);
}
let matrix = new Array(this.currentPersons.length);
for (let i = 0; i < matrix.length; ++i) {
matrix[i] = [];
}
for(let i = 0; i < allNames.length; i = i + 2){
const idx1 = this.currentPersons.indexOf(allNames[i]);
const idx2 = this.currentPersons.indexOf(allNames[i + 1]);
matrix[idx1].push(idx2);
matrix[idx2].push(idx1);
}
this.currentPairs = matrix;
this.setState({persons: names.map(name => ({personName: name, isSelected: true})), renderPersonsList: true});
}
createTableEventHandler(event) {
const selectedPersonNames = this.state.persons.filter(person => person.isSelected).map(person => person.personName);
let selectedPersonIndices = selectedPersonNames.map(name => this.currentPersons.indexOf(name));
let newPairs = "";
while(selectedPersonIndices.length > 1){
const firstIdx = selectedPersonIndices[0];
const pairIndices = this.currentPairs[firstIdx];
const missingPairIndices = Array.from(Array(this.currentPersons.length).keys()).filter(
(idx) => (idx !== firstIdx && !pairIndices.includes(idx) && selectedPersonIndices.includes(idx)));
// Person has had meetup with everyone
if(missingPairIndices.length === 0)
selectedPersonIndices.splice(0, 1);
else{
let pairsMatrix = this.currentPairs;
pairsMatrix[firstIdx].push(missingPairIndices[0]);
pairsMatrix[missingPairIndices[0]].push(firstIdx);
this.currentPairs = pairsMatrix;
newPairs += this.currentPersons[firstIdx] + " | " + this.currentPersons[missingPairIndices[0]] + "\n";
selectedPersonIndices.splice(0, 1);
selectedPersonIndices.splice(selectedPersonIndices.indexOf(missingPairIndices[0]), 1);
}
}
console.log(newPairs);
if(newPairs === "")
alert("Everyone (from the list of selected persons) had meetup with everyone else!");
else{
this.setState((prevState, props) => ({
currentPairsText: prevState.currentPairsText.trim() + "\n\n" + newPairs.trim()
}));
}
}
addAndSaveEventHandler(event) {
// Save textarea text to local storage
localStorage.setItem("currentPairsText", JSON.stringify(this.state.currentPairsText));
// Save current persons to local storage
localStorage.setItem("currentPersons", JSON.stringify(this.currentPersons));
// Save pairs matrix to local storage
localStorage.setItem("currentPairs", JSON.stringify(this.currentPairs));
}
personsSelectionChangedEventHandler(index){
let personsList = this.state.persons;
personsList[index].isSelected = !personsList[index].isSelected;
this.setState({
persons: personsList
});
}
render() {
return (
<div className = "App">
<div>
<h2>Meetup app</h2>
</div>
<textarea rows = "20" cols = "50" value = {this.state.currentPairsText} onChange = {this.pairsTextChangedEventHandler}></textarea>
<div className = "horizontalDiv">
<button onClick = {this.getNamesEventHandler}>GET NAMES</button>
<button onClick = {this.createTableEventHandler}>CREATE TABLE</button>
<button onClick = {this.addAndSaveEventHandler}>ADD AND SAVE</button>
</div>
{
this.state.renderPersonsList &&
<PersonsListComponent persons = {this.state.persons} personsSelectionChanged = {this.personsSelectionChangedEventHandler}/>
}
</div>
);
}
}
export default App;

10534
web/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"babel-preset-stage-1": "^6.24.1",
"react": "^15.6.1",
"react-dom": "^15.6.1"
},
@@ -15,4 +16,4 @@
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
}

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

69
web/src/App.js Normal file
View File

@@ -0,0 +1,69 @@
import React, { Component } from 'react';
import './App.css';
import PairsListComponent from './PairsListComponent.js';
const BASE_URL = "localhost";
class App extends Component {
constructor(props){
super(props);
this.state = {renderPairsList: false, pairs: [], waitingPairs:false, waitingSave:false, renderFinish:false};
this.getPairsEventHandler = this.getPairsEventHandler.bind(this);
this.savePairsEventHandler = this.savePairsEventHandler.bind(this);
}
getPairsEventHandler = (event) =>{
let url = `http://${BASE_URL}:3005/getPairs`;
this.setState({waitingPairs:true});
fetch(url, {}).then(function(response) { return response.json(); }).then(function(data) {
this.setState({pairs : data, renderPairsList:true, waitingPairs:false});
}.bind(this));
}
savePairsEventHandler(event){
let url = `http://${BASE_URL}:3005/savePairs`;
this.setState({waitingSave:true});
fetch(url, {}).then(function(response) { return response.json(); }).then(function(data) {
this.setState({waitingSave:false, renderFinish:data.result});
}.bind(this));
}
render() {
return (
<div className = "App">
<div>
<h2>Meetup app</h2>
</div>
<div className = "horizontalDiv">
<button disabled={this.state.waitingPairs} onClick = {this.getPairsEventHandler}>Get pairs</button>
</div>
<div>
<h2> List of pairs : </h2>
</div>
{
this.state.renderPairsList &&
<PairsListComponent pairs = {this.state.pairs}/>
}
{
this.state.renderPairsList &&
<button disabled={this.state.waitingSave} onClick = {this.savePairsEventHandler}> Save pairs </button>
}
{
this.state.renderFinish &&
<h2> Pairs saved </h2>
}
</div>
);
}
}
export default App;

18
web/src/PairComponent.js Normal file
View File

@@ -0,0 +1,18 @@
import React, { Component } from 'react';
export default class PairComponent extends Component{
constructor(props) {
super(props);
this.state = {pairName: this.props.pair};
}
render(){
return (
<div>
<div className = "horizontalDiv">
<div>{this.state.pairName.name1} - {this.state.pairName.name2}</div>
</div>
</div>
)
}
}

View File

@@ -0,0 +1,15 @@
import React, { Component } from 'react';
import PairComponent from './PairComponent.js';
export default class PairsListComponent extends Component{
render(){
return(
<div id = "outerDiv">
{
this.props.pairs.map((pair, index) =>
(<PairComponent key = {index} index = {index} pair = {pair}/>))
}
</div>
)
}
}

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

88
web/uptonow.txt Normal file
View File

@@ -0,0 +1,88 @@
Reuben Montehermoso Senad Uka
Eric Hulburd Katarzyna Frey
Kamil Grabowski James Marvin
Krzysiek Herod Luca Del Bianco
Krzysztof Wawer Ben Jacobs
Adam Florczak Daniel Mihalyi
Damian Aruj Steven Joseph
Mary Grace Andrade Fernando Catacora
Grzegorz Biziel Monika Glier
Jess Jacobs Jacque Presas
Attila Aros Gabriele Favalessa
Cezary Kopacz Carlo Liwanag
Fernando Catacora Krzysztof Wawer
Steven Joseph Cezary Kopacz
Adam Florczak Grzegorz Biziel
Eric Hulburd Kamil Grabowski
Carlo Liwanag Damian Aruj
Krzysiek Herod James Marvin
Mary Grace Andrade Nick Allen
Gabriele Favalessa Monika Glier
Jess Jacobs Luca Del Bianco
Reuben Montehermoso Katarzyna Frey
Senad Uka Daniel Mihalyi
Piotr Szotkowski Ben Jacobs
Cezary Kopacz James Marvin
Jess Jacobs Grzegorz Biziel
Eric Hulburd Krzysztof Wawer
Mary Grace Andrade Piotr Szotkowski
Kamil Grabowski Nick Allen
Senad Uka Luca Del Bianco
Monika Glier Reuben Montehermoso
Adam Florczak Krzysiek Herod
Fernando Catacora Carlo Liwanag
Gabriele Favalessa Katarzyna Frey
Damian Aruj Steven Joseph
Fernando Catacora Grzegorz Biziel
Damian Aruj Eric Hulburd
Krzysiek Herod James Marvin
Ric Szopa Steven Joseph
Senad Uka Monika Glier
Nick Allen Karen Bevis
Katarzyna Frey Gabriele Favalessa
Jess Jacobs Kamil Grabowski
Dusan Pantelic Piotr Szotkowski
Fernando Catacora Piotr Szotkowski
Damian Aruj Grzegorz Biziel
Krzysiek Herod Eric Hulburd
Ric Szopa James Marvin
Senad Uka Steven Joseph
Nick Allen Monika Glier
Katarzyna Frey Karen Bevis
Jess Jacobs Gabriele Favalessa
Dusan Pantelic Kamil Grabowski1
Fernando Catacora Gabriele Favalessa
Damian Aruj Kamil Grabowski
Krzysiek Herod Piotr Szotkowski
Ric Szopa Grzegorz Biziel
Senad Uka Eric Hulburd
Nick Allen Monika Glier
Jess Jacobs Steven Joseph
Dusan Pantelic James Marvin
Fernando Catacora James Marvin
Damian Aruj Gabriele Favalessa
Krzysiek Herod Kamil Grabowski
Ric Szopa Piotr Szotkowski
Senad Uka Grzegorz Biziel
Nick Allen Eric Hulburd
Jess Jacobs Monika Glier
Dusan Pantelic Steven Joseph
Grzegorz Biziel Jess Jacobs
Kamil Grabowski James Marvin
Katarzyna Frey Krzysiek Herod
Senad Uka Jorge Vazquez
Gabriele Favalessa Mary Grace Andrade
Adam Florczak Nick Allen
Reuben Montehermoso Steven Joseph
Damian Aruj Krzysztof Wawer
Patrick Downing Fernando Catacora
Carlo Liwanag Eric Hulburd