<commit_before>import find from 'array-find';
import React from 'react';
import UserStore from '../../../stores/UserStore';

import Bold from './Bold';
import Code from './Code';
import Italic from './Italic';
import StrikeThrough from './StrikeThrough';
import Mention from './Mention';
import Link from './Link';

function Token(type, text, raw = text) {
  this.type = type;
  this.text = text;
  this.raw = raw;
}

function tokenize(text) {
  let chunk;
  let i = 0;
  const tokens = [];
  // adds a token of type `type` if the current chunk starts with
  // a `delim`-delimited string
  const delimited = (delim, type) => {
    if (chunk[0] === delim && chunk[1] !== delim) {
      const end = chunk.indexOf(delim, 1);
      if (end !== -1) {
        tokens.push(new Token(type, chunk.slice(1, end)));
        i += end + 1;
        return true;
      }
    }
  };
  const mention = (start, type) => {
    if (chunk[0] === start) {
      let end = chunk.indexOf(' ');
      if (end === 1) {
        return false;
      }
      if (end === -1) {
        end = chunk.length;
      }
      tokens.push(new Token(type, chunk.slice(1, end), chunk.slice(0, end)));
      i += end;
      return true;
    }
  };
  const link = type => {
    const match = /^https?:\/\/[\S]+/.exec(chunk);
    if (match) {
      tokens.push(new Token(type, chunk.slice(0, match[0].length)));
      i += match[0].length;
      return true;
    }
  };
  // eat spaces
  const space = () => {
    // .slice again because `i` changed
    const m = /^\s+/.exec(text.slice(i));
    if (m) {
      tokens.push(new Token('word', m[0]));
      i += m[0].length;
    }
  };
  // tokenize text, just loop until it's done!
  chunk = text;
  while (chunk) {
    const found =
      delimited('_', 'italic') ||
      delimited('*', 'bold') ||
      delimited('`', 'code') ||
      delimited('~', 'strike') ||
      mention('@', 'mention') ||
      link('link');
    if (!found) {
      let end = chunk.indexOf(' ', 1) + /* eat space */ 1;
      if (end === 0) {// no match, = -1 + 1
        end = chunk.length;
      }
      tokens.push(new Token('word', chunk.slice(0, end)));
      i += end;
    }
    space();
    chunk = text.slice(i);
  }
  return tokens;
}

function parse(message) {
  const users = UserStore.getUsers();
  return tokenize(message).map((tok, i) => {
    switch (tok.type) {
    case 'italic':
      return <Italic key={i}>{parse(tok.text)}</Italic>;
    case 'bold':
      return <Bold key={i}>{parse(tok.text)}</Bold>;
    case 'code':
      return {tok.text};
    case 'strike':
      return <StrikeThrough key={i}>{parse(tok.text)}</StrikeThrough>;
    case 'mention':
      const mention = find(users, user => user.username === tok.text);
      return mention
        ? <Mention key={i} user={mention} />
        : tok.raw;
    case 'link':
      return <Link text={tok.text} href={tok.text} />;
    default:
      return tok.text;
    }
  });
}

export default parse;
<commit_msg>chat: add key prop to link chat markup element<commit_after>import find from 'array-find';
import React from 'react';
import UserStore from '../../../stores/UserStore';

import Bold from './Bold';
import Code from './Code';
import Italic from './Italic';
import StrikeThrough from './StrikeThrough';
import Mention from './Mention';
import Link from './Link';

function Token(type, text, raw = text) {
  this.type = type;
  this.text = text;
  this.raw = raw;
}

function tokenize(text) {
  let chunk;
  let i = 0;
  const tokens = [];
  // adds a token of type `type` if the current chunk starts with
  // a `delim`-delimited string
  const delimited = (delim, type) => {
    if (chunk[0] === delim && chunk[1] !== delim) {
      const end = chunk.indexOf(delim, 1);
      if (end !== -1) {
        tokens.push(new Token(type, chunk.slice(1, end)));
        i += end + 1;
        return true;
      }
    }
  };
  const mention = (start, type) => {
    if (chunk[0] === start) {
      let end = chunk.indexOf(' ');
      if (end === 1) {
        return false;
      }
      if (end === -1) {
        end = chunk.length;
      }
      tokens.push(new Token(type, chunk.slice(1, end), chunk.slice(0, end)));
      i += end;
      return true;
    }
  };
  const link = type => {
    const match = /^https?:\/\/[\S]+/.exec(chunk);
    if (match) {
      tokens.push(new Token(type, chunk.slice(0, match[0].length)));
      i += match[0].length;
      return true;
    }
  };
  // eat spaces
  const space = () => {
    // .slice again because `i` changed
    const m = /^\s+/.exec(text.slice(i));
    if (m) {
      tokens.push(new Token('word', m[0]));
      i += m[0].length;
    }
  };
  // tokenize text, just loop until it's done!
  chunk = text;
  while (chunk) {
    const found =
      delimited('_', 'italic') ||
      delimited('*', 'bold') ||
      delimited('`', 'code') ||
      delimited('~', 'strike') ||
      mention('@', 'mention') ||
      link('link');
    if (!found) {
      let end = chunk.indexOf(' ', 1) + /* eat space */ 1;
      if (end === 0) {// no match, = -1 + 1
        end = chunk.length;
      }
      tokens.push(new Token('word', chunk.slice(0, end)));
      i += end;
    }
    space();
    chunk = text.slice(i);
  }
  return tokens;
}

function parse(message) {
  const users = UserStore.getUsers();
  return tokenize(message).map((tok, i) => {
    switch (tok.type) {
    case 'italic':
      return <Italic key={i}>{parse(tok.text)}</Italic>;
    case 'bold':
      return <Bold key={i}>{parse(tok.text)}</Bold>;
    case 'code':
      return {tok.text};
    case 'strike':
      return <StrikeThrough key={i}>{parse(tok.text)}</StrikeThrough>;
    case 'mention':
      const mention = find(users, user => user.username === tok.text);
      return mention
        ? <Mention key={i} user={mention} />
        : tok.raw;
    case 'link':
      return <Link key={i} text={tok.text} href={tok.text} />;
    default:
      return tok.text;
    }
  });
}

export default parse;
<|endoftext|>


<commit_before>// @flow

import React, { Component } from 'react';
import { View, Animated, StyleSheet, ScrollView, Easing, Dimensions } from 'react-native';
import AnimatedOverlay from 'react-native-animated-overlay';

import Animation from './Animation';

const { width: WIDTH } = Dimensions.get('window');

// action sheet states
const ACTION_SHEET_OPENING: string = 'opening';
const ACTION_SHEET_OPENED: string = 'opened';
const ACTION_SHEET_CLOSING: string = 'closing';
const ACTION_SHEET_CLOSED: string = 'closed';

const DEFAULT_ANIMATION_DURATION: number = 250;
const SHOW_POSITION: number = 0;
const INITIAL_POSITION: number = -180;

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    top: 0,
    left: 0,
    backgroundColor: 'white',
    zIndex: 1000,
  },
  contentContainer: {
    width: WIDTH,
    backgroundColor: 'white',
  },
  scrollView: {
    paddingTop: 30,
  },
  hidden: {
    top: -10000,
    left: 0,
    height: 0,
    width: 0,
  },
});

type Props = {
  onShow?: () => void;
  onHide?: () => void;
  show?: boolean;
  animationDuration?: number;
  overlayOpacity?: number;
  children?: any;
};

const defaultProps = {
  onShow: () => {},
  onHide: () => {},
  show: false,
  animationDuration: DEFAULT_ANIMATION_DURATION,
  overlayOpacity: 0.3,
  children: null,
};

class ActionSheet extends Component {
  props: Props

  static defaultProps = defaultProps

  constructor(props) {
    super(props);

    this.state = {
      show: props.show,
      actionSheetState: ACTION_SHEET_CLOSED,
      // animation: new Animation(0),
      transformOffsetY: new Animated.Value(INITIAL_POSITION),
    };

    this.animation = new Animation(INITIAL_POSITION);
  }

  componentDidMount() {
    if (this.props.show) {
      this.show();
    }
  }

  doAnimation(toValue, onFinished?: Function = () => {}) {
    const { animationDuration } = this.props;

    Animated.timing(this.state.transformOffsetY, {
      toValue,
      duration: animationDuration,
      easing: Easing.inOut(Easing.quad),
    }).start(onFinished);
  }

  onOverlayPress = () => {
    this.hide();
  }

  setActionSheetState(toValue: number, callback?: Function = () => {}): void {
    const { animationDuration } = this.props;
    const isClosed = (this.state.actionSheetState === ACTION_SHEET_CLOSED);

    let actionSheetState = isClosed ? ACTION_SHEET_OPENING : ACTION_SHEET_CLOSING;

    this.setState({ actionSheetState });

    this.animation.toValue(toValue, animationDuration, () => {
      const isClosing = (this.state.actionSheetState === ACTION_SHEET_CLOSING);
      actionSheetState = isClosing ? ACTION_SHEET_CLOSED : ACTION_SHEET_OPENED;

      this.setState({ actionSheetState });
      callback();
    });
  }

  show = (callback?: Function = () => {}): void => {
    const { onShow } = this.props;

    this.setActionSheetState(SHOW_POSITION);
    onShow();
    callback();
  }

  hide = (callback?: Function = () => {}): void => {
    const { onHide } = this.props;

    this.setActionSheetState(INITIAL_POSITION);
    onHide();
    callback();
  }

  render() {
    const { children, animationDuration, overlayOpacity } = this.props;
    const { actionSheetState } = this.state;

    const overlayShow = [ACTION_SHEET_OPENED, ACTION_SHEET_OPENING].includes(actionSheetState);
    const hidden = actionSheetState === ACTION_SHEET_CLOSED && styles.hidden;

    return (
      <View style={[styles.container, hidden]}>
        <AnimatedOverlay
          onPress={this.onOverlayPress}
          overlayShow={overlayShow}
          duration={animationDuration}
          opacity={overlayOpacity}
        />
        <Animated.View
          style={[styles.contentContainer, this.animation.animations]}
        >
          <ScrollView style={styles.scrollView}>
            {children}
          </ScrollView>
        </Animated.View>
      </View>
    );
  }
}

export default ActionSheet;
<commit_msg>code refactoring - remove unused code<commit_after>// @flow

import React, { Component } from 'react';
import { View, Animated, StyleSheet, ScrollView, Easing, Dimensions } from 'react-native';
import AnimatedOverlay from 'react-native-animated-overlay';

import Animation from './Animation';

const { width: WIDTH } = Dimensions.get('window');

// action sheet states
const ACTION_SHEET_OPENING: string = 'opening';
const ACTION_SHEET_OPENED: string = 'opened';
const ACTION_SHEET_CLOSING: string = 'closing';
const ACTION_SHEET_CLOSED: string = 'closed';

const DEFAULT_ANIMATION_DURATION: number = 250;
const SHOW_POSITION: number = 0;
const INITIAL_POSITION: number = -180;

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    top: 0,
    left: 0,
    backgroundColor: 'white',
    zIndex: 1000,
  },
  contentContainer: {
    width: WIDTH,
    backgroundColor: 'white',
  },
  scrollView: {
    paddingTop: 30,
  },
  hidden: {
    top: -10000,
    left: 0,
    height: 0,
    width: 0,
  },
});

type Props = {
  onShow?: () => void;
  onHide?: () => void;
  show?: boolean;
  animationDuration?: number;
  overlayOpacity?: number;
  children?: any;
};

const defaultProps = {
  onShow: () => {},
  onHide: () => {},
  show: false,
  animationDuration: DEFAULT_ANIMATION_DURATION,
  overlayOpacity: 0.3,
  children: null,
};

class ActionSheet extends Component {
  props: Props

  static defaultProps = defaultProps

  constructor(props) {
    super(props);

    this.state = {
      show: props.show,
      actionSheetState: ACTION_SHEET_CLOSED,
      // animation: new Animation(0),
      transformOffsetY: new Animated.Value(INITIAL_POSITION),
    };

    this.animation = new Animation(INITIAL_POSITION);
  }

  componentDidMount() {
    if (this.props.show) {
      this.show();
    }
  }

  onOverlayPress = () => {
    this.hide();
  }

  setActionSheetState(toValue: number, callback?: Function = () => {}): void {
    const { animationDuration } = this.props;
    const isClosed = (this.state.actionSheetState === ACTION_SHEET_CLOSED);

    let actionSheetState = isClosed ? ACTION_SHEET_OPENING : ACTION_SHEET_CLOSING;

    this.setState({ actionSheetState });

    this.animation.toValue(toValue, animationDuration, () => {
      const isClosing = (this.state.actionSheetState === ACTION_SHEET_CLOSING);
      actionSheetState = isClosing ? ACTION_SHEET_CLOSED : ACTION_SHEET_OPENED;

      this.setState({ actionSheetState });
      callback();
    });
  }

  show = (callback?: Function = () => {}): void => {
    const { onShow } = this.props;

    this.setActionSheetState(SHOW_POSITION);
    onShow();
    callback();
  }

  hide = (callback?: Function = () => {}): void => {
    const { onHide } = this.props;

    this.setActionSheetState(INITIAL_POSITION);
    onHide();
    callback();
  }

  render() {
    const { children, animationDuration, overlayOpacity } = this.props;
    const { actionSheetState } = this.state;

    const overlayShow = [ACTION_SHEET_OPENED, ACTION_SHEET_OPENING].includes(actionSheetState);
    const hidden = actionSheetState === ACTION_SHEET_CLOSED && styles.hidden;

    return (
      <View style={[styles.container, hidden]}>
        <AnimatedOverlay
          onPress={this.onOverlayPress}
          overlayShow={overlayShow}
          duration={animationDuration}
          opacity={overlayOpacity}
        />
        <Animated.View
          style={[styles.contentContainer, this.animation.animations]}
        >
          <ScrollView style={styles.scrollView}>
            {children}
          </ScrollView>
        </Animated.View>
      </View>
    );
  }
}

export default ActionSheet;
<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var unirest = require('unirest');
var bcrypt = require('bcryptjs');
var config = require('./config');

var app = express();

var users = {};
var auths = {};

app.use(express.static(path.join(__dirname, './public')));
app.use(bodyParser.urlencoded({
  extended: true
}));

app.post('/api/login', function (req, res) {
	if(!auths[req.body.authorization_code]) {
		unirest.post('http://illidan.sia/api/oauth/token')
		.send({ grant_type: "authorization_code", authorization_code: req.body.authorization_code })
		.auth(config.etu.api_client_id, config.etu.api_client_secret, true)
		.end(function (response) {
			var data = JSON.parse(response.body);
			if(data.response.access_token) {
				var access_token = data.response.access_token;
				auths[req.body.authorization_code] = access_token;

				unirest.get('http://illidan.sia/api/public/user/account')
				.query({ access_token: access_token})
				.end(function (response) {
					var data = JSON.parse(response.body);
					var login = data.response.data.login;

					unirest.post('http://'+config.backend.host+':'+config.backend.port+'/api/services/login')
					.headers({'Accept': 'application/json'})
					.type('json')
					.send({MeanOfLoginId: 1, data: login, pin: req.body.pin})
					.end(function (response) {
						var data = response.body;
						if(data.token) {
							users[data.token] = data.user.id;
							delete auths[req.body.authorization_code];
							res.send({success: 1, token: data.token });
						} else {
							res.status(500).send({error: "pin"});
						}

					});

				});
			} else {
				res.status(500).send({error: "user"});
			}
		});
	} else {
		var access_token = auths[req.body.authorization_code];

		unirest.get('http://illidan.sia/api/public/user/account')
		.query({ access_token: access_token})
		.end(function (response) {
			var data = JSON.parse(response.body);
			var login = data.response.data.login;

			unirest.post('http://'+config.backend.host+':'+config.backend.port+'/api/services/login')
			.headers({'Accept': 'application/json'})
			.type('json')
			.send({MeanOfLoginId: 1, data: login, pin: req.body.pin})
			.end(function (response) {
				var data = response.body;
				if(data.token) {
					users[data.token] = data.user.id;
					delete auths[req.body.authorization_code];
					res.send({success: 1, token: data.token });
				} else {
					res.status(500).send({error: "pin"});
				}

			});
		});
	}
});

app.post('/api/transfer', function (req, res) {
	if (req.headers.authorization) {
		if (req.body.userId) {
			req.body.userId = parseInt(req.body.userId, 10);
			if (req.body.amount) {
				req.body.amount = parseInt(req.body.amount, 10);
				unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/users')
				.header('Authorization', req.headers.authorization)
				.type('json')
				.query({ id: users[req.headers.authorization.replace('Bearer ','')] })
				.end(function (user) {
					bcrypt.compare(req.body.pin, user.body.data.pin, function(err, statecrypt) {
					    if(statecrypt) {
							unirest.post('http://'+config.backend.host+':'+config.backend.port+'/api/services/transfer')
							.header('Authorization', req.headers.authorization)
							.type('json')
							.send({ amount: req.body.amount*100, userId: req.body.userId})
							.end(function (resTransfer) {
								if (resTransfer.body.data) {
									res.send({status: 1, transfer: resTransfer.body.data});
								} else {
									res.status(500).send({error: resTransfer.body.error});
								}
							});
					    } else {
					    	res.status(500).send({error: "wrongPin"});
					    }
					});
				});
			} else {
				res.status(500).send({error: "amount"});
			}
		} else {
			res.status(500).send({error: "user"});
		}
	} else {
		res.status(500).send({error: "bearer"});
	}
});

app.get('/api/getEtuName', function (req,res) {
	if(req.headers.authorization) {
		if (!req.query.cardId) {
			return res.status(500).send({error: "card"});
		}

		unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/meanofloginsusers')
		.header('Authorization', req.headers.authorization)
		.type('json')
		.query({ data: req.query.cardId, MeanOfLoginId: '2' })
		.end(function (meanoflogin) {
			if (meanoflogin.body.data) {
				unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/users')
				.header('Authorization', req.headers.authorization)
				.type('json')
				.query({ id: meanoflogin.body.data.UserId })
				.end(function (user) {
					if (user.body.data) {
						res.json({ username: user.body.data.firstname + ' ' + user.body.data.lastname, id: user.body.data.id });
					} else {
						res.status(500).send({error: "user"});
					}
				});
			} else {
				res.status(500).send({error: "user"});
			}
		});
	} else {
		res.status(500).send({error: "bearer"});
	}
});

app.get('/api/history', function (req, res) {
	if(req.headers.authorization) {
		unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/purchases')
		.header('Authorization', req.headers.authorization)
		.type('json')
		.query({ BuyerId: users[req.headers.authorization.replace('Bearer ','')], embed: 'Point,Article,Seller', order: 'date', asc: 'DESC' })
		.end(function (purchases) {
			if(purchases.body) {
				purchases.body.data = purchases.body.data || [];
				unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/reloads')
				.header('Authorization', req.headers.authorization)
				.type('json')
				.query({ BuyerId: users[req.headers.authorization.replace('Bearer ','')], embed: 'Point,Operator,ReloadType', order: 'date', asc: 'DESC' })
				.end(function (reloads) {
					if(reloads.body) {
						reloads.body.data = reloads.body.data || [];
						unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/transfers')
						.header('Authorization', req.headers.authorization)
						.type('json')
						.query({ FromId: users[req.headers.authorization.replace('Bearer ','')], embed: 'From,To', order: 'date', asc: 'DESC' })
						.end(function (transfersFrom) {
							if(transfersFrom.body) {
								transfersFrom.body.data = transfersFrom.body.data || [];
								transfersFrom.body.data = transfersFrom.body.data.map(function (transferItem) {
									transferItem.amount = -1 * transferItem.amount;
									return transferItem;
								});
								unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/transfers')
								.header('Authorization', req.headers.authorization)
								.type('json')
								.query({ ToId: users[req.headers.authorization.replace('Bearer ','')], embed: 'From,To', order: 'date', asc: 'DESC' })
								.end(function (transfersTo) {
									if(transfersTo.body) {
										transfersTo.body.data = transfersTo.body.data || [];
										var history = purchases.body.data.concat(reloads.body.data.concat(transfersFrom.body.data.concat(transfersTo.body.data))).sort(function(a,b) { return new Date(b.date)-new Date(a.date); });
										res.send({ success: 1, history: history });
									} else {
										res.status(500).send({error: "disconnected"});
									}
								});
							} else {
								res.status(500).send({error: "disconnected"});
							}
						});
					} else {
						res.status(500).send({error: "disconnected"});
					}
				});
			} else {
				res.status(500).send({error: "disconnected"});
			}
		});
	} else {
		res.status(500).send({error: "bearer"});
	}
});

app.put('/api/pin', function (req, res) {
	if(req.headers.authorization) {
		if(req.body.newPin == req.body.checkPin) {
			if(typeof parseInt(req.body.newPin) == "number" && req.body.newPin.length == 4) {
				unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/users')
				.header('Authorization', req.headers.authorization)
				.type('json')
				.query({ id: users[req.headers.authorization.replace('Bearer ','')] })
				.end(function (user) {
					bcrypt.compare(req.body.oldPin, user.body.data.pin, function(err, statecrypt) {
					    if(statecrypt) {
							bcrypt.genSalt(10, function(err, salt) {
							    bcrypt.hash(req.body.newPin, salt, function(err, hash) {
									unirest.put('http://'+config.backend.host+':'+config.backend.port+'/api/users/' + users[req.headers.authorization.replace('Bearer ','')])
									.header('Authorization', req.headers.authorization)
									.type('json')
									.send({ pin: hash })
									.end(function (user) {
										res.send({ success: "changePin" });
									});
							    });
							});
					    } else {
					    	res.status(500).send({error: "wrongPin"});
					    }
					});
				});
			} else {
				res.status(500).send({error: "formatPin"});
			}
		} else {
			res.status(500).send({error: "checkFailed"});
		}
	}
});

var server = app.listen(config.port, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('App listening at http://%s:%s', host, port);
});
<commit_msg>Add credit route<commit_after>var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var unirest = require('unirest');
var bcrypt = require('bcryptjs');
var config = require('./config');

var app = express();

var users = {};
var auths = {};

app.use(express.static(path.join(__dirname, './public')));
app.use(bodyParser.urlencoded({
  extended: true
}));

app.post('/api/login', function (req, res) {
	if(!auths[req.body.authorization_code]) {
		unirest.post('http://illidan.sia/api/oauth/token')
		.send({ grant_type: "authorization_code", authorization_code: req.body.authorization_code })
		.auth(config.etu.api_client_id, config.etu.api_client_secret, true)
		.end(function (response) {
			var data = JSON.parse(response.body);
			if(data.response.access_token) {
				var access_token = data.response.access_token;
				auths[req.body.authorization_code] = access_token;

				unirest.get('http://illidan.sia/api/public/user/account')
				.query({ access_token: access_token})
				.end(function (response) {
					var data = JSON.parse(response.body);
					var login = data.response.data.login;

					unirest.post('http://'+config.backend.host+':'+config.backend.port+'/api/services/login')
					.headers({'Accept': 'application/json'})
					.type('json')
					.send({MeanOfLoginId: 1, data: login, pin: req.body.pin})
					.end(function (response) {
						var data = response.body;
						if(data.token) {
							users[data.token] = data.user.id;
							delete auths[req.body.authorization_code];
							res.send({success: 1, token: data.token });
						} else {
							res.status(500).send({error: "pin"});
						}

					});

				});
			} else {
				res.status(500).send({error: "user"});
			}
		});
	} else {
		var access_token = auths[req.body.authorization_code];

		unirest.get('http://illidan.sia/api/public/user/account')
		.query({ access_token: access_token})
		.end(function (response) {
			var data = JSON.parse(response.body);
			var login = data.response.data.login;

			unirest.post('http://'+config.backend.host+':'+config.backend.port+'/api/services/login')
			.headers({'Accept': 'application/json'})
			.type('json')
			.send({MeanOfLoginId: 1, data: login, pin: req.body.pin})
			.end(function (response) {
				var data = response.body;
				if(data.token) {
					users[data.token] = data.user.id;
					delete auths[req.body.authorization_code];
					res.send({success: 1, token: data.token });
				} else {
					res.status(500).send({error: "pin"});
				}

			});
		});
	}
});

app.post('/api/transfer', function (req, res) {
	if (req.headers.authorization) {
		if (req.body.userId) {
			req.body.userId = parseInt(req.body.userId, 10);
			if (req.body.amount) {
				req.body.amount = parseInt(req.body.amount, 10);
				unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/users')
				.header('Authorization', req.headers.authorization)
				.type('json')
				.query({ id: users[req.headers.authorization.replace('Bearer ','')] })
				.end(function (user) {
					bcrypt.compare(req.body.pin, user.body.data.pin, function(err, statecrypt) {
					    if(statecrypt) {
							unirest.post('http://'+config.backend.host+':'+config.backend.port+'/api/services/transfer')
							.header('Authorization', req.headers.authorization)
							.type('json')
							.send({ amount: req.body.amount*100, userId: req.body.userId})
							.end(function (resTransfer) {
								if (resTransfer.body.data) {
									res.send({status: 1, transfer: resTransfer.body.data});
								} else {
									res.status(500).send({error: resTransfer.body.error});
								}
							});
					    } else {
					    	res.status(500).send({error: "wrongPin"});
					    }
					});
				});
			} else {
				res.status(500).send({error: "amount"});
			}
		} else {
			res.status(500).send({error: "user"});
		}
	} else {
		res.status(500).send({error: "bearer"});
	}
});

app.get('/api/getEtuName', function (req,res) {
	if(req.headers.authorization) {
		if (!req.query.cardId) {
			return res.status(500).send({error: "card"});
		}

		unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/meanofloginsusers')
		.header('Authorization', req.headers.authorization)
		.type('json')
		.query({ data: req.query.cardId, MeanOfLoginId: '2' })
		.end(function (meanoflogin) {
			if (meanoflogin.body.data) {
				unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/users')
				.header('Authorization', req.headers.authorization)
				.type('json')
				.query({ id: meanoflogin.body.data.UserId })
				.end(function (user) {
					if (user.body.data) {
						res.json({ username: user.body.data.firstname + ' ' + user.body.data.lastname, id: user.body.data.id });
					} else {
						res.status(500).send({error: "user"});
					}
				});
			} else {
				res.status(500).send({error: "user"});
			}
		});
	} else {
		res.status(500).send({error: "bearer"});
	}
});

app.get('/api/history', function (req, res) {
	if(req.headers.authorization) {
		unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/purchases')
		.header('Authorization', req.headers.authorization)
		.type('json')
		.query({ BuyerId: users[req.headers.authorization.replace('Bearer ','')], embed: 'Point,Article,Seller', order: 'date', asc: 'DESC' })
		.end(function (purchases) {
			if(purchases.body) {
				purchases.body.data = purchases.body.data || [];
				unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/reloads')
				.header('Authorization', req.headers.authorization)
				.type('json')
				.query({ BuyerId: users[req.headers.authorization.replace('Bearer ','')], embed: 'Point,Operator,ReloadType', order: 'date', asc: 'DESC' })
				.end(function (reloads) {
					if(reloads.body) {
						reloads.body.data = reloads.body.data || [];
						unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/transfers')
						.header('Authorization', req.headers.authorization)
						.type('json')
						.query({ FromId: users[req.headers.authorization.replace('Bearer ','')], embed: 'From,To', order: 'date', asc: 'DESC' })
						.end(function (transfersFrom) {
							if(transfersFrom.body) {
								transfersFrom.body.data = transfersFrom.body.data || [];
								transfersFrom.body.data = transfersFrom.body.data.map(function (transferItem) {
									transferItem.amount = -1 * transferItem.amount;
									return transferItem;
								});
								unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/transfers')
								.header('Authorization', req.headers.authorization)
								.type('json')
								.query({ ToId: users[req.headers.authorization.replace('Bearer ','')], embed: 'From,To', order: 'date', asc: 'DESC' })
								.end(function (transfersTo) {
									if(transfersTo.body) {
										transfersTo.body.data = transfersTo.body.data || [];
										var history = purchases.body.data.concat(reloads.body.data.concat(transfersFrom.body.data.concat(transfersTo.body.data))).sort(function(a,b) { return new Date(b.date)-new Date(a.date); });
										res.send({ success: 1, history: history });
									} else {
										res.status(500).send({error: "disconnected"});
									}
								});
							} else {
								res.status(500).send({error: "disconnected"});
							}
						});
					} else {
						res.status(500).send({error: "disconnected"});
					}
				});
			} else {
				res.status(500).send({error: "disconnected"});
			}
		});
	} else {
		res.status(500).send({error: "bearer"});
	}
});

app.get('/api/credit', function (req, res) {
	if(req.headers.authorization) {
		unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/users')
		.header('Authorization', req.headers.authorization)
		.type('json')
		.query({ id: users[req.headers.authorization.replace('Bearer ','')] })
		.end(function (user) {
			res.json({ credit: user.body.data.credit });
		});
	} else {
		res.status(500).send({error: "bearer"});
	}
});

app.put('/api/pin', function (req, res) {
	if(req.headers.authorization) {
		if(req.body.newPin == req.body.checkPin) {
			if(typeof parseInt(req.body.newPin) == "number" && req.body.newPin.length == 4) {
				unirest.get('http://'+config.backend.host+':'+config.backend.port+'/api/users')
				.header('Authorization', req.headers.authorization)
				.type('json')
				.query({ id: users[req.headers.authorization.replace('Bearer ','')] })
				.end(function (user) {
					bcrypt.compare(req.body.oldPin, user.body.data.pin, function(err, statecrypt) {
					    if(statecrypt) {
							bcrypt.genSalt(10, function(err, salt) {
							    bcrypt.hash(req.body.newPin, salt, function(err, hash) {
									unirest.put('http://'+config.backend.host+':'+config.backend.port+'/api/users/' + users[req.headers.authorization.replace('Bearer ','')])
									.header('Authorization', req.headers.authorization)
									.type('json')
									.send({ pin: hash })
									.end(function (user) {
										res.send({ success: "changePin" });
									});
							    });
							});
					    } else {
					    	res.status(500).send({error: "wrongPin"});
					    }
					});
				});
			} else {
				res.status(500).send({error: "formatPin"});
			}
		} else {
			res.status(500).send({error: "checkFailed"});
		}
	}
});

var server = app.listen(config.port, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('App listening at http://%s:%s', host, port);
});
<|endoftext|>


<commit_before>require( [ "dojo/dom", "dojo/query", "dojo/dom-attr", "dojo/dom-class", "dojo/dom-construct",
	   "dojo/on",
	   "dojo/NodeList-dom" ],
	 function(dom, query, domAttr, domClass, domConstruct, on) {

	   // Add some classes to the cells of the table.
	   var i;
	   for (i = 1; i <= 6; i++) {
	     var tr = dom.byId("ca0" + i + "-row-under");
	     var j = 0;
	     query("td", tr).forEach(function(node) {
	       domClass.add(node, "space-under" + j);
	       if (j === 5 || j === 10 || j === 11) {
		 domClass.add(node, "breaktime");
	       }
	       j++;
	     });

	     tr = dom.byId("ca0" + i + "-row-over");
	     j = 0;
	     query("td", tr).forEach(function(node) {
	       domClass.add(node, "space-over" + j);
	       j++;
	     });

	   }

	   // Highlight an area.
	   var highlightStart = {
	     'antenna': null,
	     'box': null
	   };
	   var highlightStop = {
	     'antenna': null,
	     'box': null
	   };

	   var highlightArea = function() {

	   };

	   // Make some event responders.
	   on(dom.byId('array-table-over'), 'mousedown', function(e) {
	     console.log(domAttr.get(e.target, 'class'));
	     console.log('mouse button pressed');
	     console.log(e.target);
	   });

	   on(dom.byId('array-table-over'), 'mouseup', function(e) {
	     console.log(domAttr.get(e.target, 'class'));
	     console.log('mouse button released');
	     console.log(e.target);
	   });
	 });
<commit_msg>Trying to get the ID from the event target's parent node.<commit_after>require( [ "dojo/dom", "dojo/query", "dojo/dom-attr", "dojo/dom-class", "dojo/dom-construct",
	   "dojo/on",
	   "dojo/NodeList-dom" ],
	 function(dom, query, domAttr, domClass, domConstruct, on) {

	   // Add some classes to the cells of the table.
	   var i;
	   for (i = 1; i <= 6; i++) {
	     var tr = dom.byId("ca0" + i + "-row-under");
	     var j = 0;
	     query("td", tr).forEach(function(node) {
	       domClass.add(node, "space-under" + j);
	       if (j === 5 || j === 10 || j === 11) {
		 domClass.add(node, "breaktime");
	       }
	       j++;
	     });

	     tr = dom.byId("ca0" + i + "-row-over");
	     j = 0;
	     query("td", tr).forEach(function(node) {
	       domClass.add(node, "space-over" + j);
	       j++;
	     });

	   }

	   // Highlight an area.
	   var highlightStart = {
	     'antenna': null,
	     'box': null
	   };
	   var highlightStop = {
	     'antenna': null,
	     'box': null
	   };

	   var highlightArea = function() {

	   };

	   // Make some event responders.
	   on(dom.byId('array-table-over'), 'mousedown', function(e) {
	     console.log(domAttr.get(e.target, 'class'));
	     console.log(domAttr.get(e.target.parentNode, 'id'));
	     console.log('mouse button pressed');
	     console.log(e.target);
	   });

	   on(dom.byId('array-table-over'), 'mouseup', function(e) {
	     console.log(domAttr.get(e.target, 'class'));
	     console.log(domAttr.get(e.target.parentNode, 'id'));
	     console.log('mouse button released');
	     console.log(e.target);
	   });
	 });
<|endoftext|>


<commit_before>import colors from '../settings/colors';
import styles from '../settings/styles';

export default {
  root: {
    position: 'absolute',
    top: '100%',
    right: '50%',
    minWidth: '200px',
    backgroundColor: colors.white,
    borderRadius: '3px',
    boxShadow: styles.depthShadows[0],
    margin: 0,
    paddingLeft: 0,
    overflow: 'auto',
    zIndex: '2',
    maxWidth: '85%'
  },
  header: {
    paddingTop: '10px',
    paddingRight: '10px',
    paddingBottom: '10px',
    paddingLeft: '16px',
    margin: '0',
    fontSize: '16px',
    fontWeight: 'bolder',
    color: colors.secondaryText,
    overflow: 'hidden',
    textOverflow: 'ellipsis'
  }
};
<commit_msg>:lipstick: It's over nine thousand! (#715)<commit_after>import colors from '../settings/colors';
import styles from '../settings/styles';

export default {
  root: {
    position: 'absolute',
    top: '100%',
    right: '50%',
    minWidth: '200px',
    backgroundColor: colors.white,
    borderRadius: '3px',
    boxShadow: styles.depthShadows[0],
    margin: 0,
    paddingLeft: 0,
    overflow: 'auto',
    zIndex: 9001,
    maxWidth: '85%'
  },
  header: {
    paddingTop: '10px',
    paddingRight: '10px',
    paddingBottom: '10px',
    paddingLeft: '16px',
    margin: '0',
    fontSize: '16px',
    fontWeight: 'bolder',
    color: colors.secondaryText,
    overflow: 'hidden',
    textOverflow: 'ellipsis'
  }
};
<|endoftext|>


<commit_before>var game = new Phaser.Game(800, 600, Phaser.AUTO, 'game', {
    preload: preload, create: create, update: update });

// Declare the sprites globally so we can modify them later
var background;
var plots;
var flowers;
var weeds;
var weapons;

// Declare the text fields
var gameInfoText;
var flowerText;
var weedText;

// Declare our buttons
var acid_button;
var fireball_button;
var sawblade_button;
var uav_button;

// Declare our score trackers
var flowerCount = 0;
var weedCount = 0;

// Set our default weapon
var currentWeapon = 0;

// Declare the game timers
var time;
var weaponLastFired;

// Declare our sound effects
var acid_sound;
var fireball_sound;
var sawblade_sound;
var uav_sound;
var flower_pain_sound_1;
var flower_pain_sound_2;
var weed_pain_sound;

// Declare our game state
var paused = true;
var gameOver = false;

function preload() {
    // Load the background image and game sprites
    // TODO: Combine sprites into an atlas
    game.load.image('background', 'assets/sprites/background.png');
    game.load.image('acid_icon', 'assets/sprites/acid_icon.png');
    game.load.image('fireball_icon', 'assets/sprites/fireball_icon.png');
    game.load.image('sawblade_icon', 'assets/sprites/sawblade_icon.png');
    game.load.image('uav_icon', 'assets/sprites/uav_icon.png');
    game.load.image('plot', 'assets/sprites/plot.png');
    game.load.image('flower_1', 'assets/sprites/flower_1.png');
    game.load.image('flower_2', 'assets/sprites/flower_2.png');
    game.load.image('weed_1', 'assets/sprites/weed_1.png');
    game.load.image('acid_weapon', 'assets/sprites/acid_weapon.png');
    game.load.image('fireball_weapon', 'assets/sprites/fireball_weapon.png');
    game.load.image('sawblade_weapon', 'assets/sprites/sawblade_weapon.png');
    game.load.image('uav_weapon', 'assets/sprites/uav_weapon.png');

    // Load sound effects
    game.load.audio('acid', 'assets/sounds/acid.wav');
    game.load.audio('fireball', 'assets/sounds/fireball.wav');
    game.load.audio('sawblade', 'assets/sounds/sawblade.wav');
    game.load.audio('uav', 'assets/sounds/uav.wav');
    game.load.audio('flower_pain_1', 'assets/sounds/flower_pain_1.wav');
    game.load.audio('flower_pain_2', 'assets/sounds/flower_pain_2.wav');
    game.load.audio('weed_pain', 'assets/sounds/weed_pain.wav');
}

function create() {
    // Enable the physics engine
    game.physics.startSystem(Phaser.Physics.ARCADE);

    // Apply the background sprite and set the initial background color
    background = game.add.sprite(0,0, 'background');
    background.tint = 0x0EE68;

    // Add the weapon selection buttons
    acid_button = game.add.sprite(25, 479, 'acid_icon');
    fireball_button = game.add.sprite(146, 479, 'fireball_icon');
    sawblade_button = game.add.sprite(558, 479, 'sawblade_icon');
    uav_button = game.add.sprite(679, 479, 'uav_icon');

    // Add our sound effects
    acid_sound = game.add.audio('acid');
    fireball_sound = game.add.audio('fireball');
    sawblade_sound = game.add.audio('sawblade');
    uav_sound = game.add.audio('uav');
    flower_pain_sound_1 = game.add.audio('flower_pain_1');
    flower_pain_sound_2 = game.add.audio('flower_pain_2');
    weed_pain_sound = game.add.audio('weed_pain');

    // Generate the flower/weed plots
    // TODO: Prevent overlapping plots during generation
    plots = game.add.group();
    for (var i = 0; i < 10; i++) {
        // Determine valid X/Y coordinates in the game area
        var x = Math.floor(Math.random() * (800 - (i * 8)) + 1);
        var y = Math.floor(Math.random() * (600 - (i * 6)) + 1);

        // Prevent sprite from extending off of the right or bottom
        if (x > 736) {
            x = 736;
        }
        if (y > 400) {
            // Leave room for bottom text and interaction area
            y = 400;
        } else if (y < 110) {
            // Leave enough room for flower to prevent clipping
            y = 110;
        }

        plot = plots.create(x, y, 'plot');
        plot.occupied = false;
    }

    // Define the flowers group and add physics properties
    flowers = game.add.group();
    flowers.enableBody = true;
    flowers.physicsBodyType = Phaser.Physics.ARCADE;
    // Spawn 10 random flowers outside the viewport
    for (var i = 0; i < 10; i++) {
        var whichFlower = Math.floor(Math.random() * 2 + 1);
        flower = flowers.create(-100, 800, 'flower_' + whichFlower);
    }

    // Define the weeds group and add physics properties
    weeds = game.add.group();
    weeds.enableBody = true;
    weeds.physicsBodyType = Phaser.Physics.ARCADE;
    // Spawn 10 random weeds outside the viewport
    for (var i = 0; i < 10; i++) {
        var whichWeed = Math.floor(Math.random() * 1 + 1);
        weed = weeds.create(-100, 800, 'weed_' + whichWeed);
    }

    // Define the weaopns group and add physics properties
    weapons = game.add.group();
    weapons.enableBody = true;
    weapons.physicsBodyType = Phaser.Physics.ARCADE;
    weapons.create(-200, 800, 'acid_weapon');
    weapons.create(-200, 800, 'fireball_weapon');
    weapons.create(-200, 800, 'sawblade_weapon');
    weapons.create(-200, 800, 'uav_weapon');

    // Set up inital clock for update();
    time = game.time.now;
    // Set up initial clock for weapon firing
    weaponLastFired = game.time.now;

    // Tint acid_button since it's our default weapon
    acid_button.tint = 0xAABBCC;

    // Add and configure the score text fields
    var style = { fill: '#B208C4' };
    flowerText = game.add.text(5, 0, 'Flowers: 0', style);
    flowerText.bringToTop();
    style = { fill: '#D4691E' };
    weedText = game.add.text(5, 25, 'Weeds: 0', style);
    weedText.bringToTop();

    // Add and configure our game info text
    var description = 'This is your garden.\nDon\'t let it fall into the wrong hands.';
    style = { font: '50px Arial', align: 'center', fill: '#3B5A75' };
    gameInfoText = game.add.text(game.world.centerX - 395, game.world.centerY - 50, description, style);
    gameInfoText.bringToTop();
}

function update() {
    if (paused && gameOver === false) {
        if (game.input.activePointer.isDown) {
            // Delete our info text
            game.world.remove(gameInfoText);
            // Start the game
            paused = false;
        }
    } else if (flowerCount === 10 || weedCount === 10) {
        // Detect 10 flowers or weeds and end the game accordingly
        gameOver = true;
        paused = true;
        var style;
        if (flowerCount === 10) {
            // Display win text
            style = { font: '50px Arial', align: 'center', fill: '#FFEE77' };
            var winText = "You've saved the garden!\nGive yourself a pat on the back.\nYou've earned it.";
            var won = game.add.text(game.world.centerX - 360, game.world.centerY - 70, winText, style);
            won.bringToTop();
        } else {
            // Display lose text
            style = { font: '50px Arial', align: 'center', fill: '#FF0000' };
            var loseText = "Your garden is lost.\nGet a new hobby, black thumb.";
            var lost = game.add.text(game.world.centerX - 340, game.world.centerY - 50, loseText, style);
            lost.bringToTop();
        }
    } else {
        spawnOccupants();
        tintBackground();
        checkInput();
        checkCollision();
    }
}

// Set all buttons to normal before tinting the currently selected button
function resetButtons() {
    acid_button.tint = 0xFFFFFF;
    fireball_button.tint = 0xFFFFFF;
    sawblade_button.tint = 0xFFFFFF;
    uav_button.tint = 0xFFFFFF;
}

// Tint the background color based on the ratio of flowers to weeds
function tintBackground() {
    var ratioFlowersToWeeds = flowerCount / weedCount;

    if (ratioFlowersToWeeds < 1.0) {
        background.tint = 0x869E82;
    } else if (ratioFlowersToWeeds < 0.43) {
        background.tint = 0xA6AB79;
    } else if (ratioFlowersToWeeds < 0.12) {
        background.tint = 0x917B56;
    } else {
        background.tint = 0x0EE68;
    }
}

// Every two seconds, spawn a flower or a weed on empty plots
function spawnOccupants() {
    if (game.time.now > time + 2000) {
        // Modify a random plot
        // TODO: Refactor to generate an index between 0 and 9
        var currentPlot = Math.floor(Math.random() * 10 + 1);
        if (currentPlot > 9) {
            currentPlot = 0;
        }

        // Save the plot's position and modify y for flower/weed placement
        var x = plots.children[currentPlot].x;
        var y = plots.children[currentPlot].y - 110;

        // If the plot isn't occupied, add a flower or weed
        if (plots.children[currentPlot].occupied === false) {
            var determineOccupant = Math.floor(Math.random() * 2);
            if (determineOccupant === 0) {
                // Spawn a flower
                flowers.children[currentPlot].x = x;
                flowers.children[currentPlot].y = y;

                flowerCount++;
                flowerText.text = 'Flowers: ' + flowerCount;
            } else {
                // Spawn a weed
                weeds.children[currentPlot].x = x;
                weeds.children[currentPlot].y = y;

                weedCount++;
                weedText.text = 'Weeds: ' + weedCount;
            }

            plots.children[currentPlot].occupied = true;
        }

        time = game.time.now;
    }
}

// Check for weapon selection and firing and spawn projectile
function checkInput() {
    if (game.input.activePointer.isDown) {
        // Get tap/click position
        var xInput = game.input.activePointer.x;
        var yInput = game.input.activePointer.y;

        // If y < 470, shoot the current weapon
        if (yInput < 470 && game.time.now > (weaponLastFired + 1000)) {
            // Position the correct projectile at the bottom of the viewport
            var weapon = weapons.children[currentWeapon];
            weapon.x = 400;
            weapon.y = 500;

            // Shoot selected weapon in direction of tap/click
            game.physics.arcade.moveToPointer(weapon, 500);

            // Play the appropriate weapon sound
            switch (currentWeapon) {
                case 0:
                    acid_sound.play();
                    break;
                case 1:
                    fireball_sound.play();
                    break;
                case 2:
                    sawblade_sound.play();
                    break;
                case 3:
                    uav_sound.play();
                    break;
            }

            weaponLastFired = game.time.now;
        } else if (yInput > 470) {
            // Detect weapon selection
            if (xInput > 25 && xInput < 121) {
                currentWeapon = 0;
                resetButtons();
                acid_button.tint = 0xAABBCC;
            } else if (xInput > 146 && xInput < 242) {
                currentWeapon = 1;
                resetButtons();
                fireball_button.tint = 0xAABBCC;
            } else if (xInput > 558 && xInput < 654) {
                currentWeapon = 2;
                resetButtons();
                sawblade_button.tint = 0xAABBCC;
            } else if (xInput > 679 && xInput < 775) {
                currentWeapon = 3;
                resetButtons();
                uav_button.tint = 0xAABBCC;
            }
        }
    }
}

// Detect any collision between flowers/weeds and a projectile
function checkCollision() {
    game.physics.arcade.collide(flowers, weapons, killObject, null, this);
    game.physics.arcade.collide(weeds, weapons, killObject, null, this);
}

// Tint whatever was collided with and then queue it for removal
function killObject(_object, _weapon) {
    // Temporarily color the object to a "dead" color
    _object.tint = 0xAABBCC;

    // Immediately disable collision to prevent duplicate hits
    _object.body.enable = false;

    // Decrement flower/weed count, play appropriate pain sound
    if (_object.parent === flowers) {
        flowerCount--;
        flowerText.text = 'Flowers: ' + flowerCount;
        // Play either pain sound
        var whichSound = Math.floor(Math.random() * 2);
        if (whichSound === 0) {
            flower_pain_sound_1.play();
        } else {
            flower_pain_sound_2.play();
        }
    } else {
        weedCount--;
        weedText.text = 'Weeds: ' + weedCount;
        weed_pain_sound.play();
    }

    // Call resetObject() after a half second delay
    setTimeout(function() { resetObject(_object); }, 500);
}

// Reset an object and associated plot to its initial settings
function resetObject(_object) {
    // Reset flower/weed position outside the viewport
    _object.x = -100;
    _object.y = 800;

    // Reset movement to zero
    _object.body.velocity.x = 0;
    _object.body.velocity.y = 0;

    // Reenable physics
    _object.body.enable = true;

    // Reset color
    _object.tint = 0xFFFFFF;

    // Get plot index from the flower/weed we're resetting
    var index = _object.parent.getIndex(_object);

    // Set the plot to unoccupied so it can be filled again
    plots.children[index].occupied = false;
}<commit_msg>Fix plot x axis overlap<commit_after>var game = new Phaser.Game(800, 600, Phaser.AUTO, 'game', {
    preload: preload, create: create, update: update });

// Declare the sprites globally so we can modify them later
var background;
var plots;
var flowers;
var weeds;
var weapons;

// Declare the text fields
var gameInfoText;
var flowerText;
var weedText;

// Declare our buttons
var acid_button;
var fireball_button;
var sawblade_button;
var uav_button;

// Declare our score trackers
var flowerCount = 0;
var weedCount = 0;

// Set our default weapon
var currentWeapon = 0;

// Declare the game timers
var time;
var weaponLastFired;

// Declare our sound effects
var acid_sound;
var fireball_sound;
var sawblade_sound;
var uav_sound;
var flower_pain_sound_1;
var flower_pain_sound_2;
var weed_pain_sound;

// Declare our game state
var paused = true;
var gameOver = false;

function preload() {
    // Load the background image and game sprites
    // TODO: Combine sprites into an atlas
    game.load.image('background', 'assets/sprites/background.png');
    game.load.image('acid_icon', 'assets/sprites/acid_icon.png');
    game.load.image('fireball_icon', 'assets/sprites/fireball_icon.png');
    game.load.image('sawblade_icon', 'assets/sprites/sawblade_icon.png');
    game.load.image('uav_icon', 'assets/sprites/uav_icon.png');
    game.load.image('plot', 'assets/sprites/plot.png');
    game.load.image('flower_1', 'assets/sprites/flower_1.png');
    game.load.image('flower_2', 'assets/sprites/flower_2.png');
    game.load.image('weed_1', 'assets/sprites/weed_1.png');
    game.load.image('acid_weapon', 'assets/sprites/acid_weapon.png');
    game.load.image('fireball_weapon', 'assets/sprites/fireball_weapon.png');
    game.load.image('sawblade_weapon', 'assets/sprites/sawblade_weapon.png');
    game.load.image('uav_weapon', 'assets/sprites/uav_weapon.png');

    // Load sound effects
    game.load.audio('acid', 'assets/sounds/acid.wav');
    game.load.audio('fireball', 'assets/sounds/fireball.wav');
    game.load.audio('sawblade', 'assets/sounds/sawblade.wav');
    game.load.audio('uav', 'assets/sounds/uav.wav');
    game.load.audio('flower_pain_1', 'assets/sounds/flower_pain_1.wav');
    game.load.audio('flower_pain_2', 'assets/sounds/flower_pain_2.wav');
    game.load.audio('weed_pain', 'assets/sounds/weed_pain.wav');
}

function create() {
    // Enable the physics engine
    game.physics.startSystem(Phaser.Physics.ARCADE);

    // Apply the background sprite and set the initial background color
    background = game.add.sprite(0,0, 'background');
    background.tint = 0x0EE68;

    // Add the weapon selection buttons
    acid_button = game.add.sprite(25, 479, 'acid_icon');
    fireball_button = game.add.sprite(146, 479, 'fireball_icon');
    sawblade_button = game.add.sprite(558, 479, 'sawblade_icon');
    uav_button = game.add.sprite(679, 479, 'uav_icon');

    // Add our sound effects
    acid_sound = game.add.audio('acid');
    fireball_sound = game.add.audio('fireball');
    sawblade_sound = game.add.audio('sawblade');
    uav_sound = game.add.audio('uav');
    flower_pain_sound_1 = game.add.audio('flower_pain_1');
    flower_pain_sound_2 = game.add.audio('flower_pain_2');
    weed_pain_sound = game.add.audio('weed_pain');

    // Generate the flower/weed plots
    // TODO: Prevent overlapping plots during generation
    plots = game.add.group();
    for (var i = 0; i < 10; i++) {
        // Determine valid X/Y coordinates in the game area
        var x = i * 80;
        var y = Math.floor(Math.random() * (600 - (i * 6)) + 1);

        // Prevent sprite from extending off of the right or bottom
        if (x > 736) {
            x = 736;
        }
        if (y > 400) {
            // Leave room for bottom text and interaction area
            y = 400;
        } else if (y < 110) {
            // Leave enough room for flower to prevent clipping
            y = 110;
        }

        plot = plots.create(x, y, 'plot');
        plot.occupied = false;
    }

    // Define the flowers group and add physics properties
    flowers = game.add.group();
    flowers.enableBody = true;
    flowers.physicsBodyType = Phaser.Physics.ARCADE;
    // Spawn 10 random flowers outside the viewport
    for (var i = 0; i < 10; i++) {
        var whichFlower = Math.floor(Math.random() * 2 + 1);
        flower = flowers.create(-100, 800, 'flower_' + whichFlower);
    }

    // Define the weeds group and add physics properties
    weeds = game.add.group();
    weeds.enableBody = true;
    weeds.physicsBodyType = Phaser.Physics.ARCADE;
    // Spawn 10 random weeds outside the viewport
    for (var i = 0; i < 10; i++) {
        var whichWeed = Math.floor(Math.random() * 1 + 1);
        weed = weeds.create(-100, 800, 'weed_' + whichWeed);
    }

    // Define the weaopns group and add physics properties
    weapons = game.add.group();
    weapons.enableBody = true;
    weapons.physicsBodyType = Phaser.Physics.ARCADE;
    weapons.create(-200, 800, 'acid_weapon');
    weapons.create(-200, 800, 'fireball_weapon');
    weapons.create(-200, 800, 'sawblade_weapon');
    weapons.create(-200, 800, 'uav_weapon');

    // Set up inital clock for update();
    time = game.time.now;
    // Set up initial clock for weapon firing
    weaponLastFired = game.time.now;

    // Tint acid_button since it's our default weapon
    acid_button.tint = 0xAABBCC;

    // Add and configure the score text fields
    var style = { fill: '#B208C4' };
    flowerText = game.add.text(5, 0, 'Flowers: 0', style);
    flowerText.bringToTop();
    style = { fill: '#D4691E' };
    weedText = game.add.text(5, 25, 'Weeds: 0', style);
    weedText.bringToTop();

    // Add and configure our game info text
    var description = 'This is your garden.\nDon\'t let it fall into the wrong hands.';
    style = { font: '50px Arial', align: 'center', fill: '#3B5A75' };
    gameInfoText = game.add.text(game.world.centerX - 395, game.world.centerY - 50, description, style);
    gameInfoText.bringToTop();
}

function update() {
    if (paused && gameOver === false) {
        if (game.input.activePointer.isDown) {
            // Delete our info text
            game.world.remove(gameInfoText);
            // Start the game
            paused = false;
        }
    } else if (flowerCount === 10 || weedCount === 10) {
        // Detect 10 flowers or weeds and end the game accordingly
        gameOver = true;
        paused = true;
        var style;
        if (flowerCount === 10) {
            // Display win text
            style = { font: '50px Arial', align: 'center', fill: '#FFEE77' };
            var winText = "You've saved the garden!\nGive yourself a pat on the back.\nYou've earned it.";
            var won = game.add.text(game.world.centerX - 360, game.world.centerY - 70, winText, style);
            won.bringToTop();
        } else {
            // Display lose text
            style = { font: '50px Arial', align: 'center', fill: '#FF0000' };
            var loseText = "Your garden is lost.\nGet a new hobby, black thumb.";
            var lost = game.add.text(game.world.centerX - 340, game.world.centerY - 50, loseText, style);
            lost.bringToTop();
        }
    } else {
        spawnOccupants();
        tintBackground();
        checkInput();
        checkCollision();
    }
}

// Set all buttons to normal before tinting the currently selected button
function resetButtons() {
    acid_button.tint = 0xFFFFFF;
    fireball_button.tint = 0xFFFFFF;
    sawblade_button.tint = 0xFFFFFF;
    uav_button.tint = 0xFFFFFF;
}

// Tint the background color based on the ratio of flowers to weeds
function tintBackground() {
    var ratioFlowersToWeeds = flowerCount / weedCount;

    if (ratioFlowersToWeeds < 1.0) {
        background.tint = 0x869E82;
    } else if (ratioFlowersToWeeds < 0.43) {
        background.tint = 0xA6AB79;
    } else if (ratioFlowersToWeeds < 0.12) {
        background.tint = 0x917B56;
    } else {
        background.tint = 0x0EE68;
    }
}

// Every two seconds, spawn a flower or a weed on empty plots
function spawnOccupants() {
    if (game.time.now > time + 2000) {
        // Modify a random plot
        // TODO: Refactor to generate an index between 0 and 9
        var currentPlot = Math.floor(Math.random() * 10 + 1);
        if (currentPlot > 9) {
            currentPlot = 0;
        }

        // Save the plot's position and modify y for flower/weed placement
        var x = plots.children[currentPlot].x;
        var y = plots.children[currentPlot].y - 110;

        // If the plot isn't occupied, add a flower or weed
        if (plots.children[currentPlot].occupied === false) {
            var determineOccupant = Math.floor(Math.random() * 2);
            if (determineOccupant === 0) {
                // Spawn a flower
                flowers.children[currentPlot].x = x;
                flowers.children[currentPlot].y = y;

                flowerCount++;
                flowerText.text = 'Flowers: ' + flowerCount;
            } else {
                // Spawn a weed
                weeds.children[currentPlot].x = x;
                weeds.children[currentPlot].y = y;

                weedCount++;
                weedText.text = 'Weeds: ' + weedCount;
            }

            plots.children[currentPlot].occupied = true;
        }

        time = game.time.now;
    }
}

// Check for weapon selection and firing and spawn projectile
function checkInput() {
    if (game.input.activePointer.isDown) {
        // Get tap/click position
        var xInput = game.input.activePointer.x;
        var yInput = game.input.activePointer.y;

        // If y < 470, shoot the current weapon
        if (yInput < 470 && game.time.now > (weaponLastFired + 1000)) {
            // Position the correct projectile at the bottom of the viewport
            var weapon = weapons.children[currentWeapon];
            weapon.x = 400;
            weapon.y = 500;

            // Shoot selected weapon in direction of tap/click
            game.physics.arcade.moveToPointer(weapon, 500);

            // Play the appropriate weapon sound
            switch (currentWeapon) {
                case 0:
                    acid_sound.play();
                    break;
                case 1:
                    fireball_sound.play();
                    break;
                case 2:
                    sawblade_sound.play();
                    break;
                case 3:
                    uav_sound.play();
                    break;
            }

            weaponLastFired = game.time.now;
        } else if (yInput > 470) {
            // Detect weapon selection
            if (xInput > 25 && xInput < 121) {
                currentWeapon = 0;
                resetButtons();
                acid_button.tint = 0xAABBCC;
            } else if (xInput > 146 && xInput < 242) {
                currentWeapon = 1;
                resetButtons();
                fireball_button.tint = 0xAABBCC;
            } else if (xInput > 558 && xInput < 654) {
                currentWeapon = 2;
                resetButtons();
                sawblade_button.tint = 0xAABBCC;
            } else if (xInput > 679 && xInput < 775) {
                currentWeapon = 3;
                resetButtons();
                uav_button.tint = 0xAABBCC;
            }
        }
    }
}

// Detect any collision between flowers/weeds and a projectile
function checkCollision() {
    game.physics.arcade.collide(flowers, weapons, killObject, null, this);
    game.physics.arcade.collide(weeds, weapons, killObject, null, this);
}

// Tint whatever was collided with and then queue it for removal
function killObject(_object, _weapon) {
    // Temporarily color the object to a "dead" color
    _object.tint = 0xAABBCC;

    // Immediately disable collision to prevent duplicate hits
    _object.body.enable = false;

    // Decrement flower/weed count, play appropriate pain sound
    if (_object.parent === flowers) {
        flowerCount--;
        flowerText.text = 'Flowers: ' + flowerCount;
        // Play either pain sound
        var whichSound = Math.floor(Math.random() * 2);
        if (whichSound === 0) {
            flower_pain_sound_1.play();
        } else {
            flower_pain_sound_2.play();
        }
    } else {
        weedCount--;
        weedText.text = 'Weeds: ' + weedCount;
        weed_pain_sound.play();
    }

    // Call resetObject() after a half second delay
    setTimeout(function() { resetObject(_object); }, 500);
}

// Reset an object and associated plot to its initial settings
function resetObject(_object) {
    // Reset flower/weed position outside the viewport
    _object.x = -100;
    _object.y = 800;

    // Reset movement to zero
    _object.body.velocity.x = 0;
    _object.body.velocity.y = 0;

    // Reenable physics
    _object.body.enable = true;

    // Reset color
    _object.tint = 0xFFFFFF;

    // Get plot index from the flower/weed we're resetting
    var index = _object.parent.getIndex(_object);

    // Set the plot to unoccupied so it can be filled again
    plots.children[index].occupied = false;
}<|endoftext|>


<commit_before>import React from 'react';
import './Dropdown.scss';

export class Dropdown extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      open: false
    };
  }
  handleClick (index) {
    this.setState({ open: false });
    this.props.children[index].action();
  }
  generateRows (dropdownItems) {
    return dropdownItems.map((item, index) => {
      return (
        <button
          key={index}
          className={'btn btn-sm dropdown-row ' + item.style}
          onClick={() => this.handleClick(index)}>

          {item.text}
        </button>
      );
    });
  }
  render () {
    const { children, small, extraSmall } = this.props;
    const dropdownRows = this.generateRows(children);
    return (
       setTimeout(() => this.setState({ open: false }), 180)}>
        <button
          className={
            'btn btn-primary ' +
            (small ? 'btn-sm' : '') +
            (extraSmall ? 'btn-xs' : '')
          }
          onClick={() => this.setState({ open: !this.state.open })}
          >

        </button>
        { this.state.open &&

            {dropdownRows}

        }

    );
  }
};

Dropdown.propTypes = {
  children: React.PropTypes.array.isRequired,
  small: React.PropTypes.boolean,
  extraSmall: React.PropTypes.boolean
};

export default Dropdown;
<commit_msg>Fix props validation<commit_after>import React from 'react';
import './Dropdown.scss';

export class Dropdown extends React.Component {
  constructor (props) {
    super(props);
    this.state = {
      open: false
    };
  }
  handleClick (index) {
    this.setState({ open: false });
    this.props.children[index].action();
  }
  generateRows (dropdownItems) {
    return dropdownItems.map((item, index) => {
      return (
        <button
          key={index}
          className={'btn btn-sm dropdown-row ' + item.style}
          onClick={() => this.handleClick(index)}>

          {item.text}
        </button>
      );
    });
  }
  render () {
    const { children, small, extraSmall } = this.props;
    const dropdownRows = this.generateRows(children);
    return (
       setTimeout(() => this.setState({ open: false }), 180)}>
        <button
          className={
            'btn btn-primary ' +
            (small ? 'btn-sm' : '') +
            (extraSmall ? 'btn-xs' : '')
          }
          onClick={() => this.setState({ open: !this.state.open })}
          >

        </button>
        { this.state.open &&

            {dropdownRows}

        }

    );
  }
};

Dropdown.propTypes = {
  children: React.PropTypes.array.isRequired,
  small: React.PropTypes.bool,
  extraSmall: React.PropTypes.bool
};

export default Dropdown;
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

// @ts-check

const perf = require('./vs/base/common/performance');
const performance = require('perf_hooks').performance;
const product = require('../product.json');
const readline = require('readline');
const http = require('http');

perf.mark('code/server/start');
// @ts-ignore
global.vscodeServerStartTime = performance.now();

async function start() {
	const minimist = require('minimist');

	// Do a quick parse to determine if a server or the cli needs to be started
	const parsedArgs = minimist(process.argv.slice(2), {
		boolean: ['start-server', 'list-extensions', 'print-ip-address', 'help', 'version', 'accept-server-license-terms'],
		string: ['install-extension', 'install-builtin-extension', 'uninstall-extension', 'locate-extension', 'socket-path', 'host', 'port', 'pick-port', 'compatibility']
	});

	const extensionLookupArgs = ['list-extensions', 'locate-extension'];
	const extensionInstallArgs = ['install-extension', 'install-builtin-extension', 'uninstall-extension'];

	const shouldSpawnCli = parsedArgs.help || parsedArgs.version || extensionLookupArgs.some(a => !!parsedArgs[a]) || (extensionInstallArgs.some(a => !!parsedArgs[a]) && !parsedArgs['start-server']);

	if (shouldSpawnCli) {
		loadCode().then((mod) => {
			mod.spawnCli();
		});
		return;
	}

	if (parsedArgs['compatibility'] === '1.63') {
		console.warn(`server.sh is being replaced by 'bin/${product.serverApplicationName}'. Please migrate to the new command and adopt the following new default behaviors:`);
		console.warn('* connection token is mandatody unless --without-connection-token is used');
		console.warn('* host defaults to `localhost`');
	}

	/**
	 * @typedef { import('./vs/server/node/remoteExtensionHostAgentServer').IServerAPI } IServerAPI
	 */
	/** @type {IServerAPI | null} */
	let _remoteExtensionHostAgentServer = null;
	/** @type {Promise<IServerAPI> | null} */
	let _remoteExtensionHostAgentServerPromise = null;
	/** @returns {Promise<IServerAPI>} */
	const getRemoteExtensionHostAgentServer = () => {
		if (!_remoteExtensionHostAgentServerPromise) {
			_remoteExtensionHostAgentServerPromise = loadCode().then((mod) => mod.createServer(address));
		}
		return _remoteExtensionHostAgentServerPromise;
	};

	const http = require('http');
	const os = require('os');

	if (Array.isArray(product.serverLicense) && product.serverLicense.length) {
		console.log(product.serverLicense.join('\n'));
		if (product.serverLicensePrompt && parsedArgs['accept-server-license-terms'] !== true) {
			try {
				const accept = await prompt(product.serverLicensePrompt);
				if (!accept) {
					process.exit();
				}
			} catch (e) {
				console.log(e);
				process.exit();
			}
		}
	}

	let firstRequest = true;
	let firstWebSocket = true;

	/** @type {string | import('net').AddressInfo | null} */
	let address = null;
	const server = http.createServer(async (req, res) => {
		if (firstRequest) {
			firstRequest = false;
			perf.mark('code/server/firstRequest');
		}
		const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer();
		return remoteExtensionHostAgentServer.handleRequest(req, res);
	});
	server.on('upgrade', async (req, socket) => {
		if (firstWebSocket) {
			firstWebSocket = false;
			perf.mark('code/server/firstWebSocket');
		}
		const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer();
		// @ts-ignore
		return remoteExtensionHostAgentServer.handleUpgrade(req, socket);
	});
	server.on('error', async (err) => {
		const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer();
		return remoteExtensionHostAgentServer.handleServerError(err);
	});
	const host = parsedArgs['host'] || (parsedArgs['compatibility'] !== '1.63' ? 'localhost' : undefined);
	const nodeListenOptions = (
		parsedArgs['socket-path']
			? { path: parsedArgs['socket-path'] }
			: { host, port: await parsePort(host, parsedArgs['port'], parsedArgs['pick-port']) }
	);
	server.listen(nodeListenOptions, async () => {
		const serverGreeting = product.serverGreeting.join('\n');
		let output = serverGreeting ? `\n\n${serverGreeting}\n\n` : ``;

		if (typeof nodeListenOptions.port === 'number' && parsedArgs['print-ip-address']) {
			const ifaces = os.networkInterfaces();
			Object.keys(ifaces).forEach(function (ifname) {
				ifaces[ifname].forEach(function (iface) {
					if (!iface.internal && iface.family === 'IPv4') {
						output += `IP Address: ${iface.address}\n`;
					}
				});
			});
		}

		address = server.address();
		if (address === null) {
			throw new Error('Unexpected server address');
		}

		// Do not change this line. VS Code looks for this in the output.
		output += `Extension host agent listening on ${typeof address === 'string' ? address : address.port}\n`;
		console.log(output);

		perf.mark('code/server/started');
		// @ts-ignore
		global.vscodeServerListenTime = performance.now();

		await getRemoteExtensionHostAgentServer();
	});

	process.on('exit', () => {
		server.close();
		if (_remoteExtensionHostAgentServer) {
			_remoteExtensionHostAgentServer.dispose();
		}
	});
}

/**
 * If `--pick - port` and `--port` is specified, connect to that port.
 *
 * If not and a port range is specified through `--pick - port`
 * then find a free port in that range. Throw error if no
 * free port available in range.
 *
 * If only `--port` is provided then connect to that port.
 *
 * In absence of specified ports, connect to port 8000.
 * @param {string | undefined} host
 * @param {string | undefined} strPort
 * @param {string | undefined} strPickPort
 * @returns {Promise<number>}
 * @throws
 */
async function parsePort(host, strPort, strPickPort) {
	let specificPort;
	if (strPort) {
		let range;
		if (strPort.match(/^\d+$/)) {
			specificPort = parseInt(strPort, 10);
			if (specificPort === 0 || !strPickPort) {
				return specificPort;
			}
		} else if (range = parseRange(strPort)) {
			const port = await findFreePort(host, range.start, range.end);
			if (port !== undefined) {
				return port;
			}
			console.warn(`--port: Could not find free port in range: ${range.start} - ${range.end}.`);
			process.exit(1);

		} else {
			console.warn(`--port "${strPort}" is not a valid number or range.`);
			process.exit(1);
		}
	}
	if (strPickPort) {
		const range = parseRange(strPickPort);
		if (range) {
			if (range.start <= specificPort && specificPort <= range.end) {
				return specificPort;
			} else {
				const port = await findFreePort(host, range.start, range.end);
				if (port !== undefined) {
					return port;
				}
				console.log(`--pick - port: Could not find free port in range: ${range.start} - ${range.end}.`);
				process.exit(1);
			}
		} else {
			console.log(`--pick - port "${strPickPort}" is not properly formatted.`);
			process.exit(1);
		}
	}
	return 8000;
}

/**
 * @param {string} strRange
 * @returns {{ start: number; end: number } | undefined}
 */
function parseRange(strRange) {
	const match = strRange.match(/^(\d+)-(\d+)$/);
	if (match) {
		return { start: parseInt(match[1], 10), end: parseInt(match[2], 10) };
	}
	return undefined;
}

/**
 * Starting at the `start` port, look for a free port incrementing
 * by 1 until `end` inclusive. If no free port is found, undefined is returned.
 *
 * @param {string | undefined} host
 * @param {number} start
 * @param {number} end
 * @returns {Promise<number | undefined>}
 * @throws
 */
async function findFreePort(host, start, end) {
	const testPort = (port) => {
		return new Promise((resolve) => {
			const server = http.createServer();
			server.listen(port, host, () => {
				server.close();
				resolve(true);
			}).on('error', () => {
				resolve(false);
			});
		});
	};
	for (let port = start; port < end; port++) {
		if (await testPort(port)) {
			return port;
		}
	}
	return undefined;
}

/** @returns { Promise<typeof import('./vs/server/node/remoteExtensionHostAgent')> } */
function loadCode() {
	return new Promise((resolve, reject) => {
		const path = require('path');

		if (process.env['VSCODE_DEV']) {
			// When running out of sources, we need to load node modules from remote/node_modules,
			// which are compiled against nodejs, not electron
			process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'] = process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'] || path.join(__dirname, '..', 'remote', 'node_modules');
			require('./bootstrap-node').injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']);
		} else {
			delete process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'];
		}
		require('./bootstrap-amd').load('vs/server/node/remoteExtensionHostAgent', resolve, reject);
	});
}

/**
 * @param {string} question
 * @returns { Promise<boolean> }
 */
function prompt(question) {
	const rl = readline.createInterface({
		input: process.stdin,
		output: process.stdout
	});
	return new Promise((resolve, reject) => {
		rl.question(question + ' ', async function (data) {
			rl.close();
			const str = data.toString().trim().toLowerCase();
			if (str === '' || str === 'y' || str === 'yes') {
				resolve(true);
			} else if (str === 'n' || str === 'no') {
				resolve(false);
			} else {
				process.stdout.write('\nInvalid Response. Answer either yes (y, yes) or no (n, no)\n');
				resolve(await prompt(question));
			}
		});
	});
}

start();
<commit_msg>server-cli: typo in compatibility message<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

// @ts-check

const perf = require('./vs/base/common/performance');
const performance = require('perf_hooks').performance;
const product = require('../product.json');
const readline = require('readline');
const http = require('http');

perf.mark('code/server/start');
// @ts-ignore
global.vscodeServerStartTime = performance.now();

async function start() {
	const minimist = require('minimist');

	// Do a quick parse to determine if a server or the cli needs to be started
	const parsedArgs = minimist(process.argv.slice(2), {
		boolean: ['start-server', 'list-extensions', 'print-ip-address', 'help', 'version', 'accept-server-license-terms'],
		string: ['install-extension', 'install-builtin-extension', 'uninstall-extension', 'locate-extension', 'socket-path', 'host', 'port', 'pick-port', 'compatibility']
	});

	const extensionLookupArgs = ['list-extensions', 'locate-extension'];
	const extensionInstallArgs = ['install-extension', 'install-builtin-extension', 'uninstall-extension'];

	const shouldSpawnCli = parsedArgs.help || parsedArgs.version || extensionLookupArgs.some(a => !!parsedArgs[a]) || (extensionInstallArgs.some(a => !!parsedArgs[a]) && !parsedArgs['start-server']);

	if (shouldSpawnCli) {
		loadCode().then((mod) => {
			mod.spawnCli();
		});
		return;
	}

	if (parsedArgs['compatibility'] === '1.63') {
		console.warn(`server.sh is being replaced by 'bin/${product.serverApplicationName}'. Please migrate to the new command and adopt the following new default behaviors:`);
		console.warn('* connection token is mandatory unless --without-connection-token is used');
		console.warn('* host defaults to `localhost`');
	}

	/**
	 * @typedef { import('./vs/server/node/remoteExtensionHostAgentServer').IServerAPI } IServerAPI
	 */
	/** @type {IServerAPI | null} */
	let _remoteExtensionHostAgentServer = null;
	/** @type {Promise<IServerAPI> | null} */
	let _remoteExtensionHostAgentServerPromise = null;
	/** @returns {Promise<IServerAPI>} */
	const getRemoteExtensionHostAgentServer = () => {
		if (!_remoteExtensionHostAgentServerPromise) {
			_remoteExtensionHostAgentServerPromise = loadCode().then((mod) => mod.createServer(address));
		}
		return _remoteExtensionHostAgentServerPromise;
	};

	const http = require('http');
	const os = require('os');

	if (Array.isArray(product.serverLicense) && product.serverLicense.length) {
		console.log(product.serverLicense.join('\n'));
		if (product.serverLicensePrompt && parsedArgs['accept-server-license-terms'] !== true) {
			try {
				const accept = await prompt(product.serverLicensePrompt);
				if (!accept) {
					process.exit();
				}
			} catch (e) {
				console.log(e);
				process.exit();
			}
		}
	}

	let firstRequest = true;
	let firstWebSocket = true;

	/** @type {string | import('net').AddressInfo | null} */
	let address = null;
	const server = http.createServer(async (req, res) => {
		if (firstRequest) {
			firstRequest = false;
			perf.mark('code/server/firstRequest');
		}
		const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer();
		return remoteExtensionHostAgentServer.handleRequest(req, res);
	});
	server.on('upgrade', async (req, socket) => {
		if (firstWebSocket) {
			firstWebSocket = false;
			perf.mark('code/server/firstWebSocket');
		}
		const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer();
		// @ts-ignore
		return remoteExtensionHostAgentServer.handleUpgrade(req, socket);
	});
	server.on('error', async (err) => {
		const remoteExtensionHostAgentServer = await getRemoteExtensionHostAgentServer();
		return remoteExtensionHostAgentServer.handleServerError(err);
	});
	const host = parsedArgs['host'] || (parsedArgs['compatibility'] !== '1.63' ? 'localhost' : undefined);
	const nodeListenOptions = (
		parsedArgs['socket-path']
			? { path: parsedArgs['socket-path'] }
			: { host, port: await parsePort(host, parsedArgs['port'], parsedArgs['pick-port']) }
	);
	server.listen(nodeListenOptions, async () => {
		const serverGreeting = product.serverGreeting.join('\n');
		let output = serverGreeting ? `\n\n${serverGreeting}\n\n` : ``;

		if (typeof nodeListenOptions.port === 'number' && parsedArgs['print-ip-address']) {
			const ifaces = os.networkInterfaces();
			Object.keys(ifaces).forEach(function (ifname) {
				ifaces[ifname].forEach(function (iface) {
					if (!iface.internal && iface.family === 'IPv4') {
						output += `IP Address: ${iface.address}\n`;
					}
				});
			});
		}

		address = server.address();
		if (address === null) {
			throw new Error('Unexpected server address');
		}

		// Do not change this line. VS Code looks for this in the output.
		output += `Extension host agent listening on ${typeof address === 'string' ? address : address.port}\n`;
		console.log(output);

		perf.mark('code/server/started');
		// @ts-ignore
		global.vscodeServerListenTime = performance.now();

		await getRemoteExtensionHostAgentServer();
	});

	process.on('exit', () => {
		server.close();
		if (_remoteExtensionHostAgentServer) {
			_remoteExtensionHostAgentServer.dispose();
		}
	});
}

/**
 * If `--pick - port` and `--port` is specified, connect to that port.
 *
 * If not and a port range is specified through `--pick - port`
 * then find a free port in that range. Throw error if no
 * free port available in range.
 *
 * If only `--port` is provided then connect to that port.
 *
 * In absence of specified ports, connect to port 8000.
 * @param {string | undefined} host
 * @param {string | undefined} strPort
 * @param {string | undefined} strPickPort
 * @returns {Promise<number>}
 * @throws
 */
async function parsePort(host, strPort, strPickPort) {
	let specificPort;
	if (strPort) {
		let range;
		if (strPort.match(/^\d+$/)) {
			specificPort = parseInt(strPort, 10);
			if (specificPort === 0 || !strPickPort) {
				return specificPort;
			}
		} else if (range = parseRange(strPort)) {
			const port = await findFreePort(host, range.start, range.end);
			if (port !== undefined) {
				return port;
			}
			console.warn(`--port: Could not find free port in range: ${range.start} - ${range.end}.`);
			process.exit(1);

		} else {
			console.warn(`--port "${strPort}" is not a valid number or range.`);
			process.exit(1);
		}
	}
	if (strPickPort) {
		const range = parseRange(strPickPort);
		if (range) {
			if (range.start <= specificPort && specificPort <= range.end) {
				return specificPort;
			} else {
				const port = await findFreePort(host, range.start, range.end);
				if (port !== undefined) {
					return port;
				}
				console.log(`--pick - port: Could not find free port in range: ${range.start} - ${range.end}.`);
				process.exit(1);
			}
		} else {
			console.log(`--pick - port "${strPickPort}" is not properly formatted.`);
			process.exit(1);
		}
	}
	return 8000;
}

/**
 * @param {string} strRange
 * @returns {{ start: number; end: number } | undefined}
 */
function parseRange(strRange) {
	const match = strRange.match(/^(\d+)-(\d+)$/);
	if (match) {
		return { start: parseInt(match[1], 10), end: parseInt(match[2], 10) };
	}
	return undefined;
}

/**
 * Starting at the `start` port, look for a free port incrementing
 * by 1 until `end` inclusive. If no free port is found, undefined is returned.
 *
 * @param {string | undefined} host
 * @param {number} start
 * @param {number} end
 * @returns {Promise<number | undefined>}
 * @throws
 */
async function findFreePort(host, start, end) {
	const testPort = (port) => {
		return new Promise((resolve) => {
			const server = http.createServer();
			server.listen(port, host, () => {
				server.close();
				resolve(true);
			}).on('error', () => {
				resolve(false);
			});
		});
	};
	for (let port = start; port < end; port++) {
		if (await testPort(port)) {
			return port;
		}
	}
	return undefined;
}

/** @returns { Promise<typeof import('./vs/server/node/remoteExtensionHostAgent')> } */
function loadCode() {
	return new Promise((resolve, reject) => {
		const path = require('path');

		if (process.env['VSCODE_DEV']) {
			// When running out of sources, we need to load node modules from remote/node_modules,
			// which are compiled against nodejs, not electron
			process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'] = process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'] || path.join(__dirname, '..', 'remote', 'node_modules');
			require('./bootstrap-node').injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']);
		} else {
			delete process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH'];
		}
		require('./bootstrap-amd').load('vs/server/node/remoteExtensionHostAgent', resolve, reject);
	});
}

/**
 * @param {string} question
 * @returns { Promise<boolean> }
 */
function prompt(question) {
	const rl = readline.createInterface({
		input: process.stdin,
		output: process.stdout
	});
	return new Promise((resolve, reject) => {
		rl.question(question + ' ', async function (data) {
			rl.close();
			const str = data.toString().trim().toLowerCase();
			if (str === '' || str === 'y' || str === 'yes') {
				resolve(true);
			} else if (str === 'n' || str === 'no') {
				resolve(false);
			} else {
				process.stdout.write('\nInvalid Response. Answer either yes (y, yes) or no (n, no)\n');
				resolve(await prompt(question));
			}
		});
	});
}

start();
<|endoftext|>