<commit_before>import React, { Component } from 'react';
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';

import picture from './picture.png';
import mailIcon from './mail.svg';
import githubIcon from './github.svg';
import linkedinIcon from './linkedin.svg';
import './App.css';

class App extends Component {
  render() {
    return (

Hello I'm Max

            Looking for a full-time Software Engineer position

            in Berlin, Germany or remote

            starting November 2017.

            I’m a passionate full-stack software engineer.
            Building projects with purpose drives me.
            I’m a fast learner and a doer who is not afraid of quickly bootstrapping code to embrace changes.
            Rigor is my leitmotiv: if my code is not tested, then it’s not ready.
            If it is not documented, then it’s not ready.
            I’m ready for my next challenge. 🚀

          <Tabs defaultIndex={-1} selectedTabClassName="tab-link--selected">
            <TabList className="tab-list">
              <Tab className="tab-link">Work</Tab>
              <Tab className="tab-link">Education</Tab>
              <Tab className="tab-link">Skills</Tab>
            </TabList>

            <TabPanel>

                  Lead Software Architect - Work4 -
                  Aug. 2012 / Oct. 2017 - San Francisco

                  We built the future of recruiting on social networks.
                  I worked 5 years as a full-time employee and as my experience grew,
                  I took more responsibilities, reaching the role of lead software architect.
                  I crafted and supervised a web stack serving 1M monthly active users.
                  I collaborated with and mentored a team of 5+ engineers,
                  while closely brainstorming and building user experiences with the product team.

                  Stack: Python, Django, MySQL, MongoDB, ElasticSearch, Redis,
                  Celery, Chef, Gherkin testing, Redshift, AWS.

                  Co-Founder - Ethic -
                  May 2015 / Apr. 2016 - San Francisco

                  We created a blockchain-based insurance product with the very early-stage Ethereum technology.
                  I was responsible for the product elaboration and the engineering conception.
                  Building a product on top of Ethereum was very interesting and challenging.
                  The project ended because of different life trajectories
                  (my co-founder wanted to go back to Europe).

                  Stack: NodeJS, Marionette, CoffeeScript, MongoDB, Redis, Solidity, Docker.

                  Co-Founder - House of gigs -
                  Jun. 2016 / Now - San Francisco

                  We are building a platform that brings gig-economy workers together,
                  help them find new opportunities and provide them with tailored services.
                  I am responsible for the product development and engineering.
                  I also take part in a lot of founder-specific tasks such as user acquisition and retention.
                  The iOS app is available on the US App store.

                  Stack: Python, Django, React Native, Dokku, PostgreSQL, Redis, Realm, Algolia, AWS, Datadog, Sentry.

            </TabPanel>
            <TabPanel>

Master of Science, Networks and Communication

Ecole Polytechnique - Sep. 2008 / Sep. 2012

Engineer Diploma, Computer Science

Telecom ParisTech - Sep. 2011 / Sep. 2012

            </TabPanel>
            <TabPanel>

skills content

            </TabPanel>
          </Tabs>

    );
  }
}

export default App;
<commit_msg>Telecom website in english please<commit_after>import React, { Component } from 'react';
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';

import picture from './picture.png';
import mailIcon from './mail.svg';
import githubIcon from './github.svg';
import linkedinIcon from './linkedin.svg';
import './App.css';

class App extends Component {
  render() {
    return (

Hello I'm Max

            Looking for a full-time Software Engineer position

            in Berlin, Germany or remote

            starting November 2017.

            I’m a passionate full-stack software engineer.
            Building projects with purpose drives me.
            I’m a fast learner and a doer who is not afraid of quickly bootstrapping code to embrace changes.
            Rigor is my leitmotiv: if my code is not tested, then it’s not ready.
            If it is not documented, then it’s not ready.
            I’m ready for my next challenge. 🚀

          <Tabs defaultIndex={-1} selectedTabClassName="tab-link--selected">
            <TabList className="tab-list">
              <Tab className="tab-link">Work</Tab>
              <Tab className="tab-link">Education</Tab>
              <Tab className="tab-link">Skills</Tab>
            </TabList>

            <TabPanel>

                  Lead Software Architect - Work4 -
                  Aug. 2012 / Oct. 2017 - San Francisco

                  We built the future of recruiting on social networks.
                  I worked 5 years as a full-time employee and as my experience grew,
                  I took more responsibilities, reaching the role of lead software architect.
                  I crafted and supervised a web stack serving 1M monthly active users.
                  I collaborated with and mentored a team of 5+ engineers,
                  while closely brainstorming and building user experiences with the product team.

                  Stack: Python, Django, MySQL, MongoDB, ElasticSearch, Redis,
                  Celery, Chef, Gherkin testing, Redshift, AWS.

                  Co-Founder - Ethic -
                  May 2015 / Apr. 2016 - San Francisco

                  We created a blockchain-based insurance product with the very early-stage Ethereum technology.
                  I was responsible for the product elaboration and the engineering conception.
                  Building a product on top of Ethereum was very interesting and challenging.
                  The project ended because of different life trajectories
                  (my co-founder wanted to go back to Europe).

                  Stack: NodeJS, Marionette, CoffeeScript, MongoDB, Redis, Solidity, Docker.

                  Co-Founder - House of gigs -
                  Jun. 2016 / Now - San Francisco

                  We are building a platform that brings gig-economy workers together,
                  help them find new opportunities and provide them with tailored services.
                  I am responsible for the product development and engineering.
                  I also take part in a lot of founder-specific tasks such as user acquisition and retention.
                  The iOS app is available on the US App store.

                  Stack: Python, Django, React Native, Dokku, PostgreSQL, Redis, Realm, Algolia, AWS, Datadog, Sentry.

            </TabPanel>
            <TabPanel>

Master of Science, Networks and Communication

Ecole Polytechnique - Sep. 2008 / Sep. 2012

Engineer Diploma, Computer Science

Telecom ParisTech - Sep. 2011 / Sep. 2012

            </TabPanel>
            <TabPanel>

skills content

            </TabPanel>
          </Tabs>

    );
  }
}

export default App;
<|endoftext|>


<commit_before>var demand = require('must');
var TextArrayType = require('../TextArrayType');

exports.initList = function (List) {
	List.add({
		textarr: TextArrayType,
		nested: {
			textarr: TextArrayType,
		},
		customSeparator: { type: TextArrayType, separator: ' * ' },
	});
};

exports.testFieldType = function (List) {
	it('should default to an empty array', function () {
		var testItem = new List.model();
		demand(testItem.get('textarr')).eql([]);
	});

	describe('validateInput', function () {
		it('should validate top level fields', function (done) {
			List.fields.textarr.validateInput({
				textarr: ['a', 'b'],
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should validate nested fields', function (done) {
			List.fields.textarr.validateInput({
				nested: {
					textarr: ['a', 'b'],
				},
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should validate nested fields with flat paths', function (done) {
			List.fields.textarr.validateInput({
				'nested.textarr': ['a', 'b'],
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// A single string will be coerced to an array, so we let it pass
		it('should validate a single string value', function (done) {
			List.fields.textarr.validateInput({
				textarr: 'a',
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// An empty array clears the value, so we let it pass
		it('should validate an empty array', function (done) {
			List.fields.textarr.validateInput({ textarr: [] }, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// A blank string clears the value, so we let it pass
		it('should validate a blank string', function (done) {
			List.fields.textarr.validateInput({ textarr: '' }, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// null clears the value, so we let it pass
		it('should validate null', function (done) {
			List.fields.textarr.validateInput({ textarr: null }, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// undefined doesn't change anything, so we let it pass
		it('should validate undefined', function (done) {
			List.fields.textarr.validateInput({
				textarr: undefined,
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should invalidate false', function (done) {
			List.fields.textarr.validateInput({ textarr: false }, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate true', function (done) {
			List.fields.textarr.validateInput({ textarr: true }, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate a number', function (done) {
			List.fields.textarr.validateInput({ textarr: 1 }, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate an array of numbers', function (done) {
			List.fields.textarr.validateInput({
				textarr: [1, 2, 3],
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate an array with a numbers', function (done) {
			List.fields.textarr.validateInput({
				textarr: ['a', 2, 'b'],
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});
	});

	describe('validateRequiredInput', function () {
		it('should validate an array of strings', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: ['a', 'b'],
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should validate a nested array of strings', function (done) {
			var testItem = new List.model();
			List.fields['nested.textarr'].validateRequiredInput(testItem, {
				nested: {
					textarr: ['a', 'b'],
				},
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should validate a nested array of strings with a flat paths', function (done) {
			List.fields.textarr.validateInput({
				'nested.textarr': ['a', 'b'],
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should invalidate an empty string', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: '',
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate undefined', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: undefined,
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should validate undefined if a value exists', function (done) {
			var testItem = new List.model({
				textarr: ['a'],
			});
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: undefined,
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should invalidate null', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: null,
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate an array with an empty string', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: [''],
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate an array with empty strings', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: ['a', 'b', ''],
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});
	});

	describe('updateItem', function () {
		it('should update top level fields', function (done) {
			var testItem = new List.model();
			List.fields.textarr.updateItem(testItem, {
				textarr: ['a', 'b'],
			}, function () {
				demand(testItem.textarr).eql(['a', 'b']);
				done();
			});
		});

		it('should update nested fields', function (done) {
			var testItem = new List.model();
			List.fields['nested.textarr'].updateItem(testItem, {
				nested: {
					textarr: ['a', 'b'],
				},
			}, function () {
				demand(testItem.nested.textarr).eql(['a', 'b']);
				done();
			});
		});

		it('should update nested fields with flat paths', function (done) {
			var testItem = new List.model();
			List.fields['nested.textarr'].updateItem(testItem, {
				'nested.textarr': ['a', 'b'],
			}, function () {
				demand(testItem.nested.textarr).eql(['a', 'b']);
				done();
			});
		});

		it('should update empty arrays', function (done) {
			var testItem = new List.model();
			List.fields.textarr.updateItem(testItem, {
				textarr: [],
			}, function () {
				demand(testItem.textarr).eql([]);
				done();
			});
		});

		it('should default on null', function (done) {
			var testItem = new List.model();
			List.fields.textarr.updateItem(testItem, {
				textarr: null,
			}, function () {
				demand(testItem.textarr).eql([]);
				done();
			});
		});

		it('should allow a single string value', function (done) {
			var testItem = new List.model();
			List.fields.textarr.updateItem(testItem, {
				textarr: 'a',
			}, function () {
				demand(testItem.textarr).eql(['a']);
				done();
			});
		});

		it('should convert truthy values with toString methods to strings', function (done) {
			var testItem = new List.model();
			var time = new Date();
			List.fields.textarr.updateItem(testItem, {
				textarr: [1, 'a', true, false, null, undefined, [], {}, time],
			}, function () {
				demand(testItem.textarr).eql(['1', 'a', 'true', '[object Object]', String(time)]);
				done();
			});
		});
	});

	describe('addFilterToQuery', function () {
		it('should return a regex with the "i" flag set', function () {
			var result = List.fields.textarr.addFilterToQuery({
				value: 'abc',
			});
			demand(result.textarr).eql({
				$elemMatch: {
					$regex: /abc/i,
				},
			});
		});

		it('should allow case sensitive matching', function () {
			var result = List.fields.textarr.addFilterToQuery({
				value: 'abc',
				caseSensitive: true,
			});
			demand(result.textarr).eql({
				$elemMatch: {
					$regex: /abc/,
				},
			});
		});

		it('should allow inverted matching', function () {
			var result = List.fields.textarr.addFilterToQuery({
				value: 'abc',
				inverted: true,
			});
			demand(result.textarr).eql({
				$not: /abc/i,
			});
		});

		it('should allow exact matching', function () {
			var result = List.fields.textarr.addFilterToQuery({
				value: 'abc',
				mode: 'exactly',
			});
			demand(result.textarr).eql({
				$elemMatch: {
					$regex: /^abc$/i,
				},
			});
		});

		it('should allow matching the end', function () {
			var result = List.fields.textarr.addFilterToQuery({
				value: 'abc',
				mode: 'endsWith',
			});
			demand(result.textarr).eql({
				$elemMatch: {
					$regex: /abc$/i,
				},
			});
		});

		it('should allow matching the start', function () {
			var result = List.fields.textarr.addFilterToQuery({
				value: 'abc',
				mode: 'beginsWith',
			});
			demand(result.textarr).eql({
				$elemMatch: {
					$regex: /^abc/i,
				},
			});
		});

		it('should allow matching empty values in exact mode', function () {
			var result = List.fields.textarr.addFilterToQuery({
				mode: 'exactly',
			});
			demand(result.textarr).eql({
				$elemMatch: {
					$in: ['', null],
				},
			});
		});

		it('should allow matching non-empty values in exact mode with the inverted option', function () {
			var result = List.fields.textarr.addFilterToQuery({
				mode: 'exactly',
				inverted: true,
			});
			demand(result.textarr).eql({
				$elemMatch: {
					$nin: ['', null],
				},
			});
		});
	});

	describe('format', function () {
		it('should use the default separator for formatting', function () {
			var testItem = new List.model({
				textarr: ['one', 'two', 'three'],
			});
			demand(testItem._.textarr.format()).be('one | two | three');
		});

		it('should use the provided separator for formatting', function () {
			var testItem = new List.model({
				textarr: ['one', 'two', 'three'],
			});
			demand(testItem._.textarr.format(', ')).be('one, two, three');
		});

		it('should use the specified separator for formatting', function () {
			var testItem = new List.model({
				customSeparator: ['one', 'two', 'three'],
			});
			demand(testItem._.customSeparator.format()).be('one * two * three');
		});
	});

	/* Deprecated inputIsValid Tests */

	it('should validate input', function () {
		demand(List.fields.textarr.inputIsValid({
			textarr: ['a'],
		})).be.true();
		demand(List.fields.textarr.inputIsValid({
			textarr: ['a', 'b'],
		})).be.true();
	});

	it('should validate no input', function () {
		var testItem = new List.model();
		demand(List.fields.textarr.inputIsValid({})).be.true();
		demand(List.fields.textarr.inputIsValid({}, true)).be.false();
		testItem.textarr = ['a'];
		demand(List.fields.textarr.inputIsValid({}, true, testItem)).be.true();
	});

	it('should validate length when required', function () {
		demand(List.fields.textarr.inputIsValid({
			textarr: [],
		}, true)).be.false();
	});

	it('should invalidate arrays with complex values', function () {
		demand(List.fields.textarr.inputIsValid({
			textarr: [[]],
		}, true)).be.false();
	});
};
<commit_msg>Test textarray presence filtering<commit_after>var demand = require('must');
var TextArrayType = require('../TextArrayType');

exports.initList = function (List) {
	List.add({
		textarr: TextArrayType,
		nested: {
			textarr: TextArrayType,
		},
		customSeparator: { type: TextArrayType, separator: ' * ' },
	});
};

exports.testFieldType = function (List) {
	it('should default to an empty array', function () {
		var testItem = new List.model();
		demand(testItem.get('textarr')).eql([]);
	});

	describe('validateInput', function () {
		it('should validate top level fields', function (done) {
			List.fields.textarr.validateInput({
				textarr: ['a', 'b'],
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should validate nested fields', function (done) {
			List.fields.textarr.validateInput({
				nested: {
					textarr: ['a', 'b'],
				},
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should validate nested fields with flat paths', function (done) {
			List.fields.textarr.validateInput({
				'nested.textarr': ['a', 'b'],
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// A single string will be coerced to an array, so we let it pass
		it('should validate a single string value', function (done) {
			List.fields.textarr.validateInput({
				textarr: 'a',
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// An empty array clears the value, so we let it pass
		it('should validate an empty array', function (done) {
			List.fields.textarr.validateInput({ textarr: [] }, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// A blank string clears the value, so we let it pass
		it('should validate a blank string', function (done) {
			List.fields.textarr.validateInput({ textarr: '' }, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// null clears the value, so we let it pass
		it('should validate null', function (done) {
			List.fields.textarr.validateInput({ textarr: null }, function (result) {
				demand(result).be.true();
				done();
			});
		});

		// undefined doesn't change anything, so we let it pass
		it('should validate undefined', function (done) {
			List.fields.textarr.validateInput({
				textarr: undefined,
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should invalidate false', function (done) {
			List.fields.textarr.validateInput({ textarr: false }, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate true', function (done) {
			List.fields.textarr.validateInput({ textarr: true }, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate a number', function (done) {
			List.fields.textarr.validateInput({ textarr: 1 }, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate an array of numbers', function (done) {
			List.fields.textarr.validateInput({
				textarr: [1, 2, 3],
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate an array with a numbers', function (done) {
			List.fields.textarr.validateInput({
				textarr: ['a', 2, 'b'],
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});
	});

	describe('validateRequiredInput', function () {
		it('should validate an array of strings', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: ['a', 'b'],
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should validate a nested array of strings', function (done) {
			var testItem = new List.model();
			List.fields['nested.textarr'].validateRequiredInput(testItem, {
				nested: {
					textarr: ['a', 'b'],
				},
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should validate a nested array of strings with a flat paths', function (done) {
			List.fields.textarr.validateInput({
				'nested.textarr': ['a', 'b'],
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should invalidate an empty string', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: '',
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate undefined', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: undefined,
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should validate undefined if a value exists', function (done) {
			var testItem = new List.model({
				textarr: ['a'],
			});
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: undefined,
			}, function (result) {
				demand(result).be.true();
				done();
			});
		});

		it('should invalidate null', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: null,
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate an array with an empty string', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: [''],
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});

		it('should invalidate an array with empty strings', function (done) {
			var testItem = new List.model();
			List.fields.textarr.validateRequiredInput(testItem, {
				textarr: ['a', 'b', ''],
			}, function (result) {
				demand(result).be.false();
				done();
			});
		});
	});

	describe('updateItem', function () {
		it('should update top level fields', function (done) {
			var testItem = new List.model();
			List.fields.textarr.updateItem(testItem, {
				textarr: ['a', 'b'],
			}, function () {
				demand(testItem.textarr).eql(['a', 'b']);
				done();
			});
		});

		it('should update nested fields', function (done) {
			var testItem = new List.model();
			List.fields['nested.textarr'].updateItem(testItem, {
				nested: {
					textarr: ['a', 'b'],
				},
			}, function () {
				demand(testItem.nested.textarr).eql(['a', 'b']);
				done();
			});
		});

		it('should update nested fields with flat paths', function (done) {
			var testItem = new List.model();
			List.fields['nested.textarr'].updateItem(testItem, {
				'nested.textarr': ['a', 'b'],
			}, function () {
				demand(testItem.nested.textarr).eql(['a', 'b']);
				done();
			});
		});

		it('should update empty arrays', function (done) {
			var testItem = new List.model();
			List.fields.textarr.updateItem(testItem, {
				textarr: [],
			}, function () {
				demand(testItem.textarr).eql([]);
				done();
			});
		});

		it('should default on null', function (done) {
			var testItem = new List.model();
			List.fields.textarr.updateItem(testItem, {
				textarr: null,
			}, function () {
				demand(testItem.textarr).eql([]);
				done();
			});
		});

		it('should allow a single string value', function (done) {
			var testItem = new List.model();
			List.fields.textarr.updateItem(testItem, {
				textarr: 'a',
			}, function () {
				demand(testItem.textarr).eql(['a']);
				done();
			});
		});

		it('should convert truthy values with toString methods to strings', function (done) {
			var testItem = new List.model();
			var time = new Date();
			List.fields.textarr.updateItem(testItem, {
				textarr: [1, 'a', true, false, null, undefined, [], {}, time],
			}, function () {
				demand(testItem.textarr).eql(['1', 'a', 'true', '[object Object]', String(time)]);
				done();
			});
		});
	});

	describe('addFilterToQuery', function () {
		describe('"some" present', function () {
			it('should return a regex with the "i" flag set', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'some',
					value: 'abc',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /abc/i,
					},
				});
			});

			it('should allow case sensitive matching', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'some',
					value: 'abc',
					caseSensitive: true,
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /abc/,
					},
				});
			});

			it('should allow exact matching', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'some',
					value: 'abc',
					mode: 'exactly',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /^abc$/i,
					},
				});
			});

			it('should allow matching the end', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'some',
					value: 'abc',
					mode: 'endsWith',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /abc$/i,
					},
				});
			});

			it('should allow matching the start', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'some',
					value: 'abc',
					mode: 'beginsWith',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /^abc/i,
					},
				});
			});

			it('should allow matching empty values in exact mode', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'some',
					mode: 'exactly',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$in: ['', null],
					},
				});
			});
		});

		describe('"none" present', function () {
			it('should return a regex with the "i" flag set', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'none',
					value: 'abc',
				});
				demand(result.textarr).eql({
					$not: /abc/i,
				});
			});

			it('should allow case sensitive matching', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'none',
					value: 'abc',
					caseSensitive: true,
				});
				demand(result.textarr).eql({
					$not: /abc/,
				});
			});

			it('should allow exact matching', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'none',
					value: 'abc',
					mode: 'exactly',
				});
				demand(result.textarr).eql({
					$not: /^abc$/i,
				});
			});

			it('should allow matching the end', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'none',
					value: 'abc',
					mode: 'endsWith',
				});
				demand(result.textarr).eql({
					$not: /abc$/i,
				});
			});

			it('should allow matching the start', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'none',
					value: 'abc',
					mode: 'beginsWith',
				});
				demand(result.textarr).eql({
					$not: /^abc/i,
				});
			});

			it('should allow matching empty values in exact mode', function () {
				var result = List.fields.textarr.addFilterToQuery({
					presence: 'none',
					mode: 'exactly',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$nin: ['', null],
					},
				});
			});
		});

		// Presence undefined should behave exactly like presence === 'some'
		describe('no presence option', function () {
			it('should return a regex with the "i" flag set', function () {
				var result = List.fields.textarr.addFilterToQuery({
					value: 'abc',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /abc/i,
					},
				});
			});

			it('should allow case sensitive matching', function () {
				var result = List.fields.textarr.addFilterToQuery({
					value: 'abc',
					caseSensitive: true,
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /abc/,
					},
				});
			});

			it('should allow exact matching', function () {
				var result = List.fields.textarr.addFilterToQuery({
					value: 'abc',
					mode: 'exactly',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /^abc$/i,
					},
				});
			});

			it('should allow matching the end', function () {
				var result = List.fields.textarr.addFilterToQuery({
					value: 'abc',
					mode: 'endsWith',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /abc$/i,
					},
				});
			});

			it('should allow matching the start', function () {
				var result = List.fields.textarr.addFilterToQuery({
					value: 'abc',
					mode: 'beginsWith',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$regex: /^abc/i,
					},
				});
			});

			it('should allow matching empty values in exact mode', function () {
				var result = List.fields.textarr.addFilterToQuery({
					mode: 'exactly',
				});
				demand(result.textarr).eql({
					$elemMatch: {
						$in: ['', null],
					},
				});
			});
		});
	});

	describe('format', function () {
		it('should use the default separator for formatting', function () {
			var testItem = new List.model({
				textarr: ['one', 'two', 'three'],
			});
			demand(testItem._.textarr.format()).be('one | two | three');
		});

		it('should use the provided separator for formatting', function () {
			var testItem = new List.model({
				textarr: ['one', 'two', 'three'],
			});
			demand(testItem._.textarr.format(', ')).be('one, two, three');
		});

		it('should use the specified separator for formatting', function () {
			var testItem = new List.model({
				customSeparator: ['one', 'two', 'three'],
			});
			demand(testItem._.customSeparator.format()).be('one * two * three');
		});
	});

	/* Deprecated inputIsValid Tests */

	it('should validate input', function () {
		demand(List.fields.textarr.inputIsValid({
			textarr: ['a'],
		})).be.true();
		demand(List.fields.textarr.inputIsValid({
			textarr: ['a', 'b'],
		})).be.true();
	});

	it('should validate no input', function () {
		var testItem = new List.model();
		demand(List.fields.textarr.inputIsValid({})).be.true();
		demand(List.fields.textarr.inputIsValid({}, true)).be.false();
		testItem.textarr = ['a'];
		demand(List.fields.textarr.inputIsValid({}, true, testItem)).be.true();
	});

	it('should validate length when required', function () {
		demand(List.fields.textarr.inputIsValid({
			textarr: [],
		}, true)).be.false();
	});

	it('should invalidate arrays with complex values', function () {
		demand(List.fields.textarr.inputIsValid({
			textarr: [[]],
		}, true)).be.false();
	});
};
<|endoftext|>


<commit_before>import React from 'react'
import {compose, lifecycle, withState} from 'recompose'

import {
  BrowserRouter as Router,
  Route,
  Switch
} from 'react-router-dom'

import auth from './auth'

import NotFound from './components/FourOhFour'
import JoinGame from './components/JoinGame'
import ManageGame from './components/ManageGame'
import GameStartReadyScreen from './components/GameStartReadyScreen'

const enhance = compose(
  withState('user', 'updateUser', null),
  lifecycle({
    componentWillMount() {
      this.unsubscribeAuth = auth.onAuthStateChanged((user) => (
        this.props.updateUser(user)
      ))
      auth.signInAnonymously()
    },
    componentWillUnmount() {
      this.unsubscribeAuth()
    }
  })
)

const App = ({user}) => (
  <Router>
    <Switch>
      <Route exact path="/" component={JoinGame}/>
      <Route path="/gamestart" component={GameStartReadyScreen} />
      <Route path="/manage" ><ManageGame user={user}/></Route>
      <Route component={NotFound} />
    </Switch>
  </Router>
)

export default enhance(App)
<commit_msg>Remove fake /gamestart route<commit_after>import React from 'react'
import {compose, lifecycle, withState} from 'recompose'

import {
  BrowserRouter as Router,
  Route,
  Switch
} from 'react-router-dom'

import auth from './auth'

import NotFound from './components/FourOhFour'
import JoinGame from './components/JoinGame'
import ManageGame from './components/ManageGame'
import GameStartReadyScreen from './components/GameStartReadyScreen'

const enhance = compose(
  withState('user', 'updateUser', null),
  lifecycle({
    componentWillMount() {
      this.unsubscribeAuth = auth.onAuthStateChanged((user) => (
        this.props.updateUser(user)
      ))
      auth.signInAnonymously()
    },
    componentWillUnmount() {
      this.unsubscribeAuth()
    }
  })
)

const App = ({user}) => (
  <Router>
    <Switch>
      <Route exact path="/" component={JoinGame}/>
      <Route path="/manage" ><ManageGame user={user}/></Route>
      <Route component={NotFound} />
    </Switch>
  </Router>
)

export default enhance(App)
<|endoftext|>


<commit_before>/* jshint ignore:start */

import Ember from 'ember';
import ENUMS from 'irene/enums';
import ENV from 'irene/config/environment';

const { get, set } = Ember;

const isEmpty = inputValue => Ember.isEmpty(inputValue);

const {inject: {service}} = Ember;

export default Ember.Component.extend({
  findingId: 0,
  findings: [],
  findingTitle: "",
  findingDescription: "",

  session: service(),

  risks: ENUMS.RISK.CHOICES,
  scopes: ENUMS.SCOPE.CHOICES.slice(0, 2),
  statuses: ENUMS.ANALYSIS_STATUS.CHOICES.slice(0),
  attackVectors: ENUMS.ATTACK_VECTOR.CHOICES.slice(0, 4),
  integrityImpacts: ENUMS.INTEGRITY_IMPACT.CHOICES.slice(0, 3),
  userInteractions: ENUMS.USER_INTERACTION.CHOICES.slice(0, 2),
  attackComplexities: ENUMS.ATTACK_COMPLEXITY.CHOICES.slice(0, 2),
  requiredPrevileges: ENUMS.PRIVILEGES_REQUIRED.CHOICES.slice(0, 3),
  availabilityImpacts: ENUMS.AVAILABILITY_IMPACT.CHOICES.slice(0, 3),
  confidentialityImpacts: ENUMS.CONFIDENTIALITY_IMPACT.CHOICES.slice(0, 3),

  ireneFilePath: (function() {
    const fileId = this.get("analysisDetails.file.id");
    const ireneHost = ENV.ireneHost;
    return [ireneHost, "file", fileId].join('/');
  }).property(),

  analysisDetails: (function() {
    return this.get("store").findRecord('security/analysis', this.get("analysis.analysisId"));
  }).property(),

  owasps: (function() {
    return this.get("store").findAll("owasp");
  }).property(),

  pcidsses: (function() {
    return this.get("store").findAll("pcidss");
  }).property(),

  allFindings: (function() {
    let findingId = this.get("findingId");
    const findings = this.get("analysisDetails.findings");
    if(findings) {
      findings.forEach((finding) => {
        findingId = findingId + 1;
        finding.id = findingId;
        this.set("findingId", findingId);
      });
      return findings;
    }
  }).property("analysisDetails.findings"),

  confirmCallback(key) {
    if(key === "findings") {
      this.set("analysisDetails.findings", "");
      return this.set("showClearAllFindingsConfirmBox", false);
    }
    if(key === "attachment") {
      this.deleteFile(this.get("deletedFile"));
      return this.set("showRemoveFileConfirmBox", false);
    }
    if(key === "finding") {
      const availableFindings = this.get("availableFindings");
      this.set("analysisDetails.findings", availableFindings);
      return this.set("showRemoveFindingConfirmBox", false);
    }
    if(key === "passed") {
      this.set("analysisDetails.attackVector", ENUMS.ATTACK_VECTOR.PHYSICAL);
      this.set("analysisDetails.attackComplexity", ENUMS.ATTACK_COMPLEXITY.HIGH);
      this.set("analysisDetails.privilegesRequired", ENUMS.PRIVILEGES_REQUIRED.HIGH);
      this.set("analysisDetails.userInteraction", ENUMS.USER_INTERACTION.REQUIRED);
      this.set("analysisDetails.scope", ENUMS.SCOPE.UNCHANGED);
      this.set("analysisDetails.confidentialityImpact", ENUMS.CONFIDENTIALITY_IMPACT.NONE);
      this.set("analysisDetails.integrityImpact", ENUMS.INTEGRITY_IMPACT.NONE);
      this.set("analysisDetails.availabilityImpact", ENUMS.AVAILABILITY_IMPACT.NONE);
      this.set("analysisDetails.cvssVector", "CVSS:3.0/AV:P/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:N");
      this.updateCVSSScore()
      this.send("saveAnalysis");
      return this.set("showMarkPassedConfirmBox", false);
    }
  },

  availableFindings: Ember.computed.filter('allFindings', function(allFinding) {
    const deletedFinding = this.get("deletedFinding");
    return allFinding.id !== deletedFinding;
  }),

  deleteFile(id) {
    const attachment = this.get("store").peekRecord('security/attachment', id);
    if(attachment) {
      attachment.deleteRecord();
      attachment.save();
    }
  },

  updateCVSSScore() {
    const attackVector = this.get("analysisDetails.attackVector") || ENUMS.ATTACK_VECTOR.PHYSICAL;
    const attackComplexity = this.get("analysisDetails.attackComplexity") || ENUMS.ATTACK_COMPLEXITY.HIGH;
    const privilegesRequired = this.get("analysisDetails.privilegesRequired") || ENUMS.PRIVILEGES_REQUIRED.HIGH ;
    const userInteraction = this.get("analysisDetails.userInteraction") || ENUMS.USER_INTERACTION.REQUIRED ;
    const scope = this.get("analysisDetails.scope") || ENUMS.SCOPE.UNCHANGED ;
    const confidentialityImpact = this.get("analysisDetails.confidentialityImpact") || ENUMS.CONFIDENTIALITY_IMPACT.NONE;
    const integrityImpact = this.get("analysisDetails.integrityImpact") || ENUMS.INTEGRITY_IMPACT.NONE;
    const availabilityImpact = this.get("analysisDetails.availabilityImpact") || ENUMS.AVAILABILITY_IMPACT.NONE;
    const vector =`CVSS:3.0/AV:${attackVector}/AC:${attackComplexity}/PR:${privilegesRequired}/UI:${userInteraction}/S:${scope}/C:${confidentialityImpact}/I:${integrityImpact}/A:${availabilityImpact}`;
    const url = `cvss?vector=${vector}`;
    this.get("ajax").request(url)
    .then((data) => {
      this.set("analysisDetails.cvssBase", data.cvss_base);
      this.set("analysisDetails.risk", data.risk);
      this.set("analysisDetails.cvssVector", vector);
    }, () => {
      this.get("notify").error("Sorry something went wrong, please try again");
    });
  },

  actions: {

    async uploadFile(file) {
      this.set("isUploading", true);
      const fileName = file.blob.name;
      const data = {
        name: fileName
      };
      const analysisId= this.get("analysis.analysisId");
      try {
        var fileData = await this.get("ajax").post(ENV.endpoints.uploadFile,{namespace: 'hudson-api', data});
        await file.uploadBinary(fileData.url, {
          method: 'PUT'
        });
        const fileDetailsData = {
          file_uuid: fileData.file_uuid,
          file_key: fileData.file_key,
          file_key_signed: fileData.file_key_signed,
          name: fileName,
          analysis: analysisId,
          content_type: "ANALYSIS"
        };
        await this.get("ajax").post(ENV.endpoints.uploadedAttachment,{namespace: 'hudson-api', data: fileDetailsData});

        this.set("isUploading", false);
        this.get("store").findRecord('analysis', this.get("analysis.analysisId"));
        this.get("notify").success("File Uploaded Successfully");
        const analysisObj = this.get("store").findRecord('security/analysis', this.get("analysis.analysisId"));
        this.set('analysisDetails', analysisObj);
      } catch(error) {
        this.set("isUploading", false);
        this.get("notify").error("Sorry something went wrong, please try again");
        return;
      }
    },

    selectStatus(param) {
      this.set('analysisDetails.status', param);
    },

    selectAttackVector(param) {
      this.set('analysisDetails.attackVector', param.value);
      this.updateCVSSScore();
    },

    selectAttackComplexity(param) {
      this.set('analysisDetails.attackComplexity', param.value);
      this.updateCVSSScore();
    },

    selectRequiredPrevilege(param) {
      this.set('analysisDetails.privilegesRequired', param.value);
      this.updateCVSSScore();
    },

    selectUserInteraction(param) {
      this.set('analysisDetails.userInteraction', param.value);
      this.updateCVSSScore();
    },

    selectScope(param) {
      this.set('analysisDetails.scope', param.value);
      this.updateCVSSScore();
    },

    selectConfidentialityImpact(param) {
      this.set('analysisDetails.confidentialityImpact', param.value);
      this.updateCVSSScore();
    },

    selectIntegrityImpact(param) {
      this.set('analysisDetails.integrityImpact', param.value);
      this.updateCVSSScore();
    },

    selectAvailabilityImpact(param) {
      this.set('analysisDetails.availabilityImpact', param.value);
      this.updateCVSSScore();
    },

    selectOwaspCategory(param) {
      this.set('analysisDetails.owasp', param);
    },

    selectPcidssCategory(param) {
      this.set('analysisDetails.pcidss', param);
    },

    selectOverriddenRisk(param) {
      this.set('analysisDetails.overriddenRisk', param);
    },

    addFinding() {
      const findingTitle = this.get("findingTitle");
      const findingDescription = this.get("findingDescription");
      if (isEmpty(findingDescription)) return this.get("notify").error("Please fill the description");
      let findingId = this.get("findingId");
      findingId = findingId + 1;
      const findings = this.get("analysisDetails.findings");
      const newFinding = {
        id: findingId,
        title: findingTitle,
        description: findingDescription
      };
      findings.addObject(newFinding);
      this.set("findingId", findingId);
      this.set("analysisDetails.findings", findings);
      this.get("notify").success("Finding Added");
      this.setProperties({
        findingTitle: "",
        findingDescription: ""
      });
    },

    openClearAllFindingConfirmBox() {
      this.set("showClearAllFindingsConfirmBox", true);
    },

    openRemoveFindingConfirmBox(param) {
      this.set("deletedFinding", param);
      this.set("showRemoveFindingConfirmBox", true);
    },

    openRemoveFileConfirmBox(param) {
      this.set("deletedFile", param);
      this.set("showRemoveFileConfirmBox", true);
    },

    openMarkPassedConfirmBox() {
      this.set("showMarkPassedConfirmBox", true);
    },

    downloadAttachment(id) {
      const url = [ENV.endpoints.uploadFile, id, ENV.endpoints.downloadAttachment].join('/');
      return this.get("ajax").request(url, {namespace: 'hudson-api'})
      .then((data) => {
        window.open(data.url, '_blank');
      }, (error) => {
        for (error of error.errors) {
          this.get("notify").error(error.detail.error);
        }
      })
    },

    resetOverriddenAnalysis() {
      this.set("analysisDetails.overriddenRisk", null);
    },

    saveAndContinue() {
      this.send("saveAnalysis");
    },

    saveAndGoBack() {
      this.send("saveAnalysis", 'back');
    },

    saveAnalysis(param) {
      const key = param;
      const risk = this.get("analysisDetails.risk");
      const owasp = this.get("analysisDetails.owasp");
      const pcidss = this.get("analysisDetails.pcidss");
      let status = this.get("analysisDetails.status");
      if(typeof status === "object") {
        status = status.value;
      }
      const analysisId= this.get("analysis.analysisId");
      const findings = this.get("analysisDetails.findings");
      let overriddenRisk = this.get("analysisDetails.overriddenRisk");
      if(typeof overriddenRisk === "object" && !Ember.isEmpty(overriddenRisk)) {
        overriddenRisk = overriddenRisk.value;
      }
      const overriddenRiskToProfile = this.get("analysisDetails.overriddenRiskToProfile");
      const attackVector = this.get("analysisDetails.attackVector");
      const attackComplexity = this.get("analysisDetails.attackComplexity");
      const privilegesRequired = this.get("analysisDetails.privilegesRequired");
      const userInteraction = this.get("analysisDetails.userInteraction");
      const scope = this.get("analysisDetails.scope");
      const confidentialityImpact = this.get("analysisDetails.confidentialityImpact");
      const integrityImpact = this.get("analysisDetails.integrityImpact");
      const availabilityImpact = this.get("analysisDetails.availabilityImpact");

      for (let inputValue of [attackVector, attackComplexity, privilegesRequired, userInteraction, scope, confidentialityImpact, integrityImpact, availabilityImpact]) {
        if (isEmpty(inputValue)) { return this.get("notify").error("Please select all the CVSS Metrics"); }
      }

      const cvssVector = this.get("analysisDetails.cvssVector");
      const data = {
        risk,
        status,
        owasp: owasp.map(a=>a.get('id')),
        pcidss: pcidss.map(a=>a.get('id')),
        findings,
        overridden_risk: overriddenRisk,
        overridden_risk_to_profile: overriddenRiskToProfile,
        cvss_vector: cvssVector,
        attack_vector: attackVector,
        attack_complexity: attackComplexity,
        privileges_required: privilegesRequired,
        user_interaction: userInteraction,
        scope,
        confidentiality_impact: confidentialityImpact,
        integrity_impact: integrityImpact,
        availability_impact: availabilityImpact
      };
      this.set("isSavingAnalyses", true);
      const url = [ENV.endpoints.analyses, analysisId].join('/');
      this.get("ajax").put(url,{ namespace: '/hudson-api', data: JSON.stringify(data), contentType: 'application/json' })
      .then(() => {
        this.set("isSavingAnalyses", false);
        this.get("notify").success("Analyses Updated");
        if(key) {
          Ember.getOwner(this).lookup('route:authenticated').transitionTo("authenticated.security.file", this.get("analysisDetails.file.id"));
        }
      }, () => {
        this.set("isSavingAnalyses", false);
        this.get("notify").error("Sorry something went wrong, please try again");
      })
    }
  }
});

/* jshint ignore:end */
<commit_msg>fix: set findings to an empty array after clearing all findings<commit_after>/* jshint ignore:start */

import Ember from 'ember';
import ENUMS from 'irene/enums';
import ENV from 'irene/config/environment';

const { get, set } = Ember;

const isEmpty = inputValue => Ember.isEmpty(inputValue);

const {inject: {service}} = Ember;

export default Ember.Component.extend({
  findingId: 0,
  findings: [],
  findingTitle: "",
  findingDescription: "",

  session: service(),

  risks: ENUMS.RISK.CHOICES,
  scopes: ENUMS.SCOPE.CHOICES.slice(0, 2),
  statuses: ENUMS.ANALYSIS_STATUS.CHOICES.slice(0),
  attackVectors: ENUMS.ATTACK_VECTOR.CHOICES.slice(0, 4),
  integrityImpacts: ENUMS.INTEGRITY_IMPACT.CHOICES.slice(0, 3),
  userInteractions: ENUMS.USER_INTERACTION.CHOICES.slice(0, 2),
  attackComplexities: ENUMS.ATTACK_COMPLEXITY.CHOICES.slice(0, 2),
  requiredPrevileges: ENUMS.PRIVILEGES_REQUIRED.CHOICES.slice(0, 3),
  availabilityImpacts: ENUMS.AVAILABILITY_IMPACT.CHOICES.slice(0, 3),
  confidentialityImpacts: ENUMS.CONFIDENTIALITY_IMPACT.CHOICES.slice(0, 3),

  ireneFilePath: (function() {
    const fileId = this.get("analysisDetails.file.id");
    const ireneHost = ENV.ireneHost;
    return [ireneHost, "file", fileId].join('/');
  }).property(),

  analysisDetails: (function() {
    return this.get("store").findRecord('security/analysis', this.get("analysis.analysisId"));
  }).property(),

  owasps: (function() {
    return this.get("store").findAll("owasp");
  }).property(),

  pcidsses: (function() {
    return this.get("store").findAll("pcidss");
  }).property(),

  allFindings: (function() {
    let findingId = this.get("findingId");
    const findings = this.get("analysisDetails.findings");
    if(findings) {
      findings.forEach((finding) => {
        findingId = findingId + 1;
        finding.id = findingId;
        this.set("findingId", findingId);
      });
      return findings;
    }
  }).property("analysisDetails.findings"),

  confirmCallback(key) {
    if(key === "findings") {
      this.set("analysisDetails.findings", []);
      return this.set("showClearAllFindingsConfirmBox", false);
    }
    if(key === "attachment") {
      this.deleteFile(this.get("deletedFile"));
      return this.set("showRemoveFileConfirmBox", false);
    }
    if(key === "finding") {
      const availableFindings = this.get("availableFindings");
      this.set("analysisDetails.findings", availableFindings);
      return this.set("showRemoveFindingConfirmBox", false);
    }
    if(key === "passed") {
      this.set("analysisDetails.attackVector", ENUMS.ATTACK_VECTOR.PHYSICAL);
      this.set("analysisDetails.attackComplexity", ENUMS.ATTACK_COMPLEXITY.HIGH);
      this.set("analysisDetails.privilegesRequired", ENUMS.PRIVILEGES_REQUIRED.HIGH);
      this.set("analysisDetails.userInteraction", ENUMS.USER_INTERACTION.REQUIRED);
      this.set("analysisDetails.scope", ENUMS.SCOPE.UNCHANGED);
      this.set("analysisDetails.confidentialityImpact", ENUMS.CONFIDENTIALITY_IMPACT.NONE);
      this.set("analysisDetails.integrityImpact", ENUMS.INTEGRITY_IMPACT.NONE);
      this.set("analysisDetails.availabilityImpact", ENUMS.AVAILABILITY_IMPACT.NONE);
      this.set("analysisDetails.cvssVector", "CVSS:3.0/AV:P/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:N");
      this.updateCVSSScore()
      this.send("saveAnalysis");
      return this.set("showMarkPassedConfirmBox", false);
    }
  },

  availableFindings: Ember.computed.filter('allFindings', function(allFinding) {
    const deletedFinding = this.get("deletedFinding");
    return allFinding.id !== deletedFinding;
  }),

  deleteFile(id) {
    const attachment = this.get("store").peekRecord('security/attachment', id);
    if(attachment) {
      attachment.deleteRecord();
      attachment.save();
    }
  },

  updateCVSSScore() {
    const attackVector = this.get("analysisDetails.attackVector") || ENUMS.ATTACK_VECTOR.PHYSICAL;
    const attackComplexity = this.get("analysisDetails.attackComplexity") || ENUMS.ATTACK_COMPLEXITY.HIGH;
    const privilegesRequired = this.get("analysisDetails.privilegesRequired") || ENUMS.PRIVILEGES_REQUIRED.HIGH ;
    const userInteraction = this.get("analysisDetails.userInteraction") || ENUMS.USER_INTERACTION.REQUIRED ;
    const scope = this.get("analysisDetails.scope") || ENUMS.SCOPE.UNCHANGED ;
    const confidentialityImpact = this.get("analysisDetails.confidentialityImpact") || ENUMS.CONFIDENTIALITY_IMPACT.NONE;
    const integrityImpact = this.get("analysisDetails.integrityImpact") || ENUMS.INTEGRITY_IMPACT.NONE;
    const availabilityImpact = this.get("analysisDetails.availabilityImpact") || ENUMS.AVAILABILITY_IMPACT.NONE;
    const vector =`CVSS:3.0/AV:${attackVector}/AC:${attackComplexity}/PR:${privilegesRequired}/UI:${userInteraction}/S:${scope}/C:${confidentialityImpact}/I:${integrityImpact}/A:${availabilityImpact}`;
    const url = `cvss?vector=${vector}`;
    this.get("ajax").request(url)
    .then((data) => {
      this.set("analysisDetails.cvssBase", data.cvss_base);
      this.set("analysisDetails.risk", data.risk);
      this.set("analysisDetails.cvssVector", vector);
    }, () => {
      this.get("notify").error("Sorry something went wrong, please try again");
    });
  },

  actions: {

    async uploadFile(file) {
      this.set("isUploading", true);
      const fileName = file.blob.name;
      const data = {
        name: fileName
      };
      const analysisId= this.get("analysis.analysisId");
      try {
        var fileData = await this.get("ajax").post(ENV.endpoints.uploadFile,{namespace: 'hudson-api', data});
        await file.uploadBinary(fileData.url, {
          method: 'PUT'
        });
        const fileDetailsData = {
          file_uuid: fileData.file_uuid,
          file_key: fileData.file_key,
          file_key_signed: fileData.file_key_signed,
          name: fileName,
          analysis: analysisId,
          content_type: "ANALYSIS"
        };
        await this.get("ajax").post(ENV.endpoints.uploadedAttachment,{namespace: 'hudson-api', data: fileDetailsData});

        this.set("isUploading", false);
        this.get("store").findRecord('analysis', this.get("analysis.analysisId"));
        this.get("notify").success("File Uploaded Successfully");
        const analysisObj = this.get("store").findRecord('security/analysis', this.get("analysis.analysisId"));
        this.set('analysisDetails', analysisObj);
      } catch(error) {
        this.set("isUploading", false);
        this.get("notify").error("Sorry something went wrong, please try again");
        return;
      }
    },

    selectStatus(param) {
      this.set('analysisDetails.status', param);
    },

    selectAttackVector(param) {
      this.set('analysisDetails.attackVector', param.value);
      this.updateCVSSScore();
    },

    selectAttackComplexity(param) {
      this.set('analysisDetails.attackComplexity', param.value);
      this.updateCVSSScore();
    },

    selectRequiredPrevilege(param) {
      this.set('analysisDetails.privilegesRequired', param.value);
      this.updateCVSSScore();
    },

    selectUserInteraction(param) {
      this.set('analysisDetails.userInteraction', param.value);
      this.updateCVSSScore();
    },

    selectScope(param) {
      this.set('analysisDetails.scope', param.value);
      this.updateCVSSScore();
    },

    selectConfidentialityImpact(param) {
      this.set('analysisDetails.confidentialityImpact', param.value);
      this.updateCVSSScore();
    },

    selectIntegrityImpact(param) {
      this.set('analysisDetails.integrityImpact', param.value);
      this.updateCVSSScore();
    },

    selectAvailabilityImpact(param) {
      this.set('analysisDetails.availabilityImpact', param.value);
      this.updateCVSSScore();
    },

    selectOwaspCategory(param) {
      this.set('analysisDetails.owasp', param);
    },

    selectPcidssCategory(param) {
      this.set('analysisDetails.pcidss', param);
    },

    selectOverriddenRisk(param) {
      this.set('analysisDetails.overriddenRisk', param);
    },

    addFinding() {
      const findingTitle = this.get("findingTitle");
      const findingDescription = this.get("findingDescription");
      if (isEmpty(findingDescription)) return this.get("notify").error("Please fill the description");
      let findingId = this.get("findingId");
      findingId = findingId + 1;
      const findings = this.get("analysisDetails.findings");
      const newFinding = {
        id: findingId,
        title: findingTitle,
        description: findingDescription
      };
      findings.addObject(newFinding);
      this.set("findingId", findingId);
      this.set("analysisDetails.findings", findings);
      this.get("notify").success("Finding Added");
      this.setProperties({
        findingTitle: "",
        findingDescription: ""
      });
    },

    openClearAllFindingConfirmBox() {
      this.set("showClearAllFindingsConfirmBox", true);
    },

    openRemoveFindingConfirmBox(param) {
      this.set("deletedFinding", param);
      this.set("showRemoveFindingConfirmBox", true);
    },

    openRemoveFileConfirmBox(param) {
      this.set("deletedFile", param);
      this.set("showRemoveFileConfirmBox", true);
    },

    openMarkPassedConfirmBox() {
      this.set("showMarkPassedConfirmBox", true);
    },

    downloadAttachment(id) {
      const url = [ENV.endpoints.uploadFile, id, ENV.endpoints.downloadAttachment].join('/');
      return this.get("ajax").request(url, {namespace: 'hudson-api'})
      .then((data) => {
        window.open(data.url, '_blank');
      }, (error) => {
        for (error of error.errors) {
          this.get("notify").error(error.detail.error);
        }
      })
    },

    resetOverriddenAnalysis() {
      this.set("analysisDetails.overriddenRisk", null);
    },

    saveAndContinue() {
      this.send("saveAnalysis");
    },

    saveAndGoBack() {
      this.send("saveAnalysis", 'back');
    },

    saveAnalysis(param) {
      const key = param;
      const risk = this.get("analysisDetails.risk");
      const owasp = this.get("analysisDetails.owasp");
      const pcidss = this.get("analysisDetails.pcidss");
      let status = this.get("analysisDetails.status");
      if(typeof status === "object") {
        status = status.value;
      }
      const analysisId= this.get("analysis.analysisId");
      const findings = this.get("analysisDetails.findings");
      let overriddenRisk = this.get("analysisDetails.overriddenRisk");
      if(typeof overriddenRisk === "object" && !Ember.isEmpty(overriddenRisk)) {
        overriddenRisk = overriddenRisk.value;
      }
      const overriddenRiskToProfile = this.get("analysisDetails.overriddenRiskToProfile");
      const attackVector = this.get("analysisDetails.attackVector");
      const attackComplexity = this.get("analysisDetails.attackComplexity");
      const privilegesRequired = this.get("analysisDetails.privilegesRequired");
      const userInteraction = this.get("analysisDetails.userInteraction");
      const scope = this.get("analysisDetails.scope");
      const confidentialityImpact = this.get("analysisDetails.confidentialityImpact");
      const integrityImpact = this.get("analysisDetails.integrityImpact");
      const availabilityImpact = this.get("analysisDetails.availabilityImpact");

      for (let inputValue of [attackVector, attackComplexity, privilegesRequired, userInteraction, scope, confidentialityImpact, integrityImpact, availabilityImpact]) {
        if (isEmpty(inputValue)) { return this.get("notify").error("Please select all the CVSS Metrics"); }
      }

      const cvssVector = this.get("analysisDetails.cvssVector");
      const data = {
        risk,
        status,
        owasp: owasp.map(a=>a.get('id')),
        pcidss: pcidss.map(a=>a.get('id')),
        findings,
        overridden_risk: overriddenRisk,
        overridden_risk_to_profile: overriddenRiskToProfile,
        cvss_vector: cvssVector,
        attack_vector: attackVector,
        attack_complexity: attackComplexity,
        privileges_required: privilegesRequired,
        user_interaction: userInteraction,
        scope,
        confidentiality_impact: confidentialityImpact,
        integrity_impact: integrityImpact,
        availability_impact: availabilityImpact
      };
      this.set("isSavingAnalyses", true);
      const url = [ENV.endpoints.analyses, analysisId].join('/');
      this.get("ajax").put(url,{ namespace: '/hudson-api', data: JSON.stringify(data), contentType: 'application/json' })
      .then(() => {
        this.set("isSavingAnalyses", false);
        this.get("notify").success("Analyses Updated");
        if(key) {
          Ember.getOwner(this).lookup('route:authenticated').transitionTo("authenticated.security.file", this.get("analysisDetails.file.id"));
        }
      }, () => {
        this.set("isSavingAnalyses", false);
        this.get("notify").error("Sorry something went wrong, please try again");
      })
    }
  }
});

/* jshint ignore:end */
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Header, Body, Sidebar, Content, Footer } from './entry';
import Keycloak from 'keycloak-js';
import axios from 'axios';
import md5 from 'js-md5';

class App extends Component {
	constructor() {
		super();
		this.state = ({
			keycloak: {},
			user: {
				image: './images/user.png',
				name: 'sam'
			},
			logo: 'logo'
		})
		this._getContent = this._getContent.bind(this);
	}
	componentWillMount() {
		const kc = Keycloak(process.env.REACT_APP_KEYCLOAK_JSON_FILE);

		kc.init({ onLoad: 'login-required' })
			.success((authenticated) => {
				if (authenticated) {
					this.setState({ keycloak: kc })
					this.state.keycloak.loadUserInfo()
						.success((user) => {
							// if ('adamcrow63+1@gmail.com'.includes("+")) {
							// 	var n = 'adamcrow63+1@gmail.com'.indexOf('+');
							// 	var at = 'adamcrow63+1@gmail.com'.indexOf('@');
							// 	var email = 'adamcrow63+1@gmail.com'.substr(0, n) + 'adamcrow63+1@gmail.com'.substr(at);
							// 	alert(email);
							// }
							md5(user.email);
							//md5('adamcrow63@gmail.com');
							const hash = md5.create();
							//hash.update('adamcrow63@gmail.com');
							hash.update(user.email);
							hash.hex();
							const imgUrl = 'https://www.gravatar.com/avatar/' + hash;
							//alert(imgUrl);
							const projectName = process.env.REACT_APP_PROJECT_NAME;
							if(projectName === undefined ) {
								projectName = kc.realm;
							}
							this.setState({ logo: projectName, user: { image: imgUrl, name: user.given_name } })
						});
				}
				else {
					console.log("user could not authenticated");
				}

			})
			.error(function (err) {
				console.log('failed to initialize');

			})
	}
	_getContent() {
		var { token } = this.state.keycloak;
		console.log(token);

		axios({
			url: 'qwanda/setup',
			method: 'get',
			// baseURL: 'https://qwanda-service.outcome-hub.com/',
			baseURL: process.env.REACT_APP_QWANDA_API_URL,
			data: {},
			headers: { 'Authorization': `Bearer ${token}` }
		}).then((success) => {
			alert('completed the authorization step with data ');
			console.log(success.data);
		}).catch(error => {
			alert(error);
		})
	}

	render() {
		var { keycloak, user, logo } = this.state;
		console.log('API', process.env.REACT_APP_QWANDA_API_URL);
		return (

					<Sidebar>

					</Sidebar>
					<Content>
						<button onClick={this._getContent}>Get Content </button>
					</Content>

					Version No:{process.env.REACT_APP_VERSION_NUMBER} ||| Build Date: {process.env.REACT_APP_BUILD_DATE}

		);
	}
}

export default App;

<commit_msg>fixed projectName error<commit_after>import React, { Component } from 'react';
import { Header, Body, Sidebar, Content, Footer } from './entry';
import Keycloak from 'keycloak-js';
import axios from 'axios';
import md5 from 'js-md5';

class App extends Component {
	constructor() {
		super();
		this.state = ({
			keycloak: {},
			user: {
				image: './images/user.png',
				name: 'sam'
			},
			logo: 'logo'
		})
		this._getContent = this._getContent.bind(this);
	}
	componentWillMount() {
		const kc = Keycloak(process.env.REACT_APP_KEYCLOAK_JSON_FILE);

		kc.init({ onLoad: 'login-required' })
			.success((authenticated) => {
				if (authenticated) {
					this.setState({ keycloak: kc })
					this.state.keycloak.loadUserInfo()
						.success((user) => {
							// if ('adamcrow63+1@gmail.com'.includes("+")) {
							// 	var n = 'adamcrow63+1@gmail.com'.indexOf('+');
							// 	var at = 'adamcrow63+1@gmail.com'.indexOf('@');
							// 	var email = 'adamcrow63+1@gmail.com'.substr(0, n) + 'adamcrow63+1@gmail.com'.substr(at);
							// 	alert(email);
							// }
							md5(user.email);
							//md5('adamcrow63@gmail.com');
							const hash = md5.create();
							//hash.update('adamcrow63@gmail.com');
							hash.update(user.email);
							hash.hex();
							const imgUrl = 'https://www.gravatar.com/avatar/' + hash;
							//alert(imgUrl);
							let projectName = process.env.REACT_APP_PROJECT_NAME;
							if(projectName === undefined ) {
								projectName = kc.realm;
							}
							this.setState({ logo: projectName, user: { image: imgUrl, name: user.given_name } })
						});
				}
				else {
					console.log("user could not authenticated");
				}

			})
			.error(function (err) {
				console.log('failed to initialize');

			})
	}
	_getContent() {
		var { token } = this.state.keycloak;
		console.log(token);

		axios({
			url: 'qwanda/setup',
			method: 'get',
			// baseURL: 'https://qwanda-service.outcome-hub.com/',
			baseURL: process.env.REACT_APP_QWANDA_API_URL,
			data: {},
			headers: { 'Authorization': `Bearer ${token}` }
		}).then((success) => {
			alert('completed the authorization step with data ');
			console.log(success.data);
		}).catch(error => {
			alert(error);
		})
	}

	render() {
		var { keycloak, user, logo } = this.state;
		console.log('API', process.env.REACT_APP_QWANDA_API_URL);
		return (

					<Sidebar>

					</Sidebar>
					<Content>
						<button onClick={this._getContent}>Get Content </button>
					</Content>

					Version No:{process.env.REACT_APP_VERSION_NUMBER} ||| Build Date: {process.env.REACT_APP_BUILD_DATE}

		);
	}
}

export default App;

<|endoftext|>


<commit_before>import React, { Component } from "react";
import Header from './Components/Header';

class App extends Component {
  render() {
    return (
      <Header />
      <p
    );
  }
}

export default App;
<commit_msg>typo fix<commit_after>import React, { Component } from "react";
import Header from './Components/Header';

class App extends Component {
  render() {
    return (
      <Header />
    );
  }
}

export default App;
<|endoftext|>


<commit_before>import React from 'react';
import { Link } from 'react-router'

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import keycode from 'keycode';
import {Tabs, Tab} from 'material-ui/Tabs';
import {Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle} from 'material-ui/Toolbar';
import Paper from 'material-ui/Paper';
import Snackbar from 'material-ui/Snackbar';

import Repo from './RepoPanel';
import RepoOps from './RepoOps';
import CommitTree from './CommitTreePanel';
import StagingArea from './StagingAreaPanel';

// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
import injectTapEventPlugin from 'react-tap-event-plugin';

import Git from 'nodegit';

const darkMuiTheme = getMuiTheme(darkBaseTheme);

class gitFunctions {
  static repoExists(path) {
    const pathToRepo = require('path').resolve(path);

    return Git.Repository.open(pathToRepo);
  }
}

class MainToolbar extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      toggle: false
    };
  }

  changeToolbar = (label) => {
    this.props.changeToolbar(label);
  }

  render = () => {
    const styles = {
      toolbar:{
        backgroundColor: 'blue',
        paddingLeft: '5%',
        border: '1px solid black',
        // boxShadow: '10px 10px 10px #888888',
        zIndex: 100,
      },
      button: {
        position: 'relative',
        marginRight: 5,
        marginLeft: 5,
        backgroundColor: '#CACACA',
      },
    };
    const repoButton = this.props.repoName?
                        <FlatButton style={styles.button}
                          label={this.props.repoName}
                          containerElement={<Link to='/repoOps' />}
                          linkButton={true} />
                          :
;

    return (
        <Toolbar style={styles.toolbar} noGutter={false} >
          <ToolbarGroup firstChild={true} >

            <FlatButton style={styles.button}
            containerElement={<Link to='/repo' />}
            label='Repos'
            linkButton={true} />

            {repoButton}
          </ToolbarGroup>
        </Toolbar>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currRepoIndex: -1,
      repos: [],
      openWrongDirSnackBar: false,
    };
  }

  handleKeyPressChange = (passedPath) => {
    //TODO: Check if passed path is valid or not
    //extracts the name of the repo from the path name
    const repoName = passedPath.slice(passedPath.lastIndexOf('/')+1);
    let flag = false;
    let pos;

    this.state.repos.forEach( (repo, index) => {

      //if repo already exists in the state
      if(repo.path === passedPath) {
        pos = index;
        flag = true;
      }
    });

    if( flag ) {
      this.setState({
        currRepoIndex: pos
      });
    }
    else
    {
      //checks if the folder contains a git repo
      let promise = gitFunctions.repoExists(passedPath);
      promise.then( () => {
        let repos = this.state.repos;
        repos.push({
          name: repoName,
          path: passedPath
        });
        let repoIndex = repos.length - 1;

        this.setState({
          currRepoIndex: repoIndex,
          repos: repos
        });
        this.changeToolbar(repoName);
      })
      .catch( (failure) => {
        console.log('Could not find a git repository in the folder',
          'Make sure you have selected the correct folder');
        console.log('failure',failure);
        this.setState({
          openWrongDirSnackBar: true
        });
      });
    }
  }

  handleRepoClick = (index) => {
    window.setTimeout( () => {
      this.setState({
        currRepoIndex: index
      });
      this.changeToolbar(this.state.repos[index].name);
    },0);
  }

  changeToolbar = (label) => {

  }

  handleRequestClose = () => {
    this.setState({
      openWrongDirSnackBar: false
    });
  }

  componentWillMount = () => {
    injectTapEventPlugin();
  }

  componentWillReceiveProps = (newprops) => {
  }

  //for dev prurposes only
  componentDidMount = () => {
    this.handleKeyPressChange('../dummy-repo');
  }

  render() {

    const styles = {
      mainPanel: {
        height:800
      },
      repos: {
      },
      tabs: {
        overflow: 'hidden',
        width: '50%',
      },
      font: {
        fontFamily: '"Roboto", sans-serif',
      },
    };

    const wrongDirError = 'Could not find a git repository in the folder. Make sure you have selected the correct folder';

    let renderRepo = this.state.repos[this.state.currRepoIndex]?this.state.repos[this.state.currRepoIndex]:null;

    let children = React.Children.map( this.props.children, child => {
      if(child.type === Repo) {

        return React.cloneElement(child, {
          repos: this.state.repos,
          pathToRepo: renderRepo? renderRepo.path: '',
          selectRepo: this.handleRepoClick,
          onKeyPress: this.handleKeyPressChange,
        });

      }
      else if(child.type === RepoOps) {

        return React.cloneElement(child, {
          repo: renderRepo,
        });

      }
    });

    return (
      <MuiThemeProvider muiTheme={getMuiTheme()}>

          <MainToolbar repoName={renderRepo? renderRepo.name: ''} />

          <Snackbar open={this.state.openWrongDirSnackBar} message={wrongDirError} autoHideDuration={4000}
          style={styles.font} onRequestClose={this.handleRequestClose}/>
          {children || <Repo style={styles.repos} repos={this.state.repos} pathToRepo={renderRepo? renderRepo.path: ''}
            selectRepo={this.handleRepoClick} onKeyPress={this.handleKeyPressChange}/>}

      </MuiThemeProvider>
    )
  }

}

export default App;<commit_msg>Misc: moved testing repo invoke command to componentWillMount<commit_after>import React from 'react';
import { Link } from 'react-router'

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import keycode from 'keycode';
import {Tabs, Tab} from 'material-ui/Tabs';
import {Toolbar, ToolbarGroup, ToolbarSeparator, ToolbarTitle} from 'material-ui/Toolbar';
import Paper from 'material-ui/Paper';
import Snackbar from 'material-ui/Snackbar';

import Repo from './RepoPanel';
import RepoOps from './RepoOps';
import CommitTree from './CommitTreePanel';
import StagingArea from './StagingAreaPanel';

// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
import injectTapEventPlugin from 'react-tap-event-plugin';

import Git from 'nodegit';

const darkMuiTheme = getMuiTheme(darkBaseTheme);

class gitFunctions {
  static repoExists(path) {
    const pathToRepo = require('path').resolve(path);

    return Git.Repository.open(pathToRepo);
  }
}

class MainToolbar extends React.Component {
  constructor(props) {
    super(props);
    this.state={
      toggle: false
    };
  }

  changeToolbar = (label) => {
    this.props.changeToolbar(label);
  }

  render = () => {
    const styles = {
      toolbar:{
        backgroundColor: 'blue',
        paddingLeft: '5%',
        border: '1px solid black',
        // boxShadow: '10px 10px 10px #888888',
        zIndex: 100,
      },
      button: {
        position: 'relative',
        marginRight: 5,
        marginLeft: 5,
        backgroundColor: '#CACACA',
      },
    };
    const repoButton = this.props.repoName?
                        <FlatButton style={styles.button}
                          label={this.props.repoName}
                          containerElement={<Link to='/repoOps' />}
                          linkButton={true} />
                          :
;

    return (
        <Toolbar style={styles.toolbar} noGutter={false} >
          <ToolbarGroup firstChild={true} >

            <FlatButton style={styles.button}
            containerElement={<Link to='/repo' />}
            label='Repos'
            linkButton={true} />

            {repoButton}
          </ToolbarGroup>
        </Toolbar>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currRepoIndex: -1,
      repos: [],
      openWrongDirSnackBar: false,
    };
  }

  handleKeyPressChange = (passedPath) => {
    //TODO: Check if passed path is valid or not
    //extracts the name of the repo from the path name
    const repoName = passedPath.slice(passedPath.lastIndexOf('/')+1);
    let flag = false;
    let pos;

    this.state.repos.forEach( (repo, index) => {

      //if repo already exists in the state
      if(repo.path === passedPath) {
        pos = index;
        flag = true;
      }
    });

    if( flag ) {
      this.setState({
        currRepoIndex: pos
      });
    }
    else
    {
      //checks if the folder contains a git repo
      let promise = gitFunctions.repoExists(passedPath);
      promise.then( () => {
        let repos = this.state.repos;
        repos.push({
          name: repoName,
          path: passedPath
        });
        let repoIndex = repos.length - 1;

        this.setState({
          currRepoIndex: repoIndex,
          repos: repos
        });
        this.changeToolbar(repoName);
      })
      .catch( (failure) => {
        console.log('Could not find a git repository in the folder',
          'Make sure you have selected the correct folder');
        console.log('failure',failure);
        this.setState({
          openWrongDirSnackBar: true
        });
      });
    }
  }

  handleRepoClick = (index) => {
    window.setTimeout( () => {
      this.setState({
        currRepoIndex: index
      });
      this.changeToolbar(this.state.repos[index].name);
    },0);
  }

  changeToolbar = (label) => {

  }

  handleRequestClose = () => {
    this.setState({
      openWrongDirSnackBar: false
    });
  }

  componentWillMount = () => {
    injectTapEventPlugin();
    this.handleKeyPressChange('../dummy-repo');
  }

  componentWillReceiveProps = (newprops) => {
  }

  //for dev prurposes only
  componentDidMount = () => {
  }

  render() {

    const styles = {
      mainPanel: {
        height:800
      },
      repos: {
      },
      tabs: {
        overflow: 'hidden',
        width: '50%',
      },
      font: {
        fontFamily: '"Roboto", sans-serif',
      },
    };

    const wrongDirError = 'Could not find a git repository in the folder. Make sure you have selected the correct folder';

    let renderRepo = this.state.repos[this.state.currRepoIndex]?this.state.repos[this.state.currRepoIndex]:null;

    let children = React.Children.map( this.props.children, child => {
      if(child.type === Repo) {

        return React.cloneElement(child, {
          repos: this.state.repos,
          pathToRepo: renderRepo? renderRepo.path: '',
          selectRepo: this.handleRepoClick,
          onKeyPress: this.handleKeyPressChange,
        });

      }
      else if(child.type === RepoOps) {

        return React.cloneElement(child, {
          repo: renderRepo,
        });

      }
    });

    return (
      <MuiThemeProvider muiTheme={getMuiTheme()}>

          <MainToolbar repoName={renderRepo? renderRepo.name: ''} />

          <Snackbar open={this.state.openWrongDirSnackBar} message={wrongDirError} autoHideDuration={4000}
          style={styles.font} onRequestClose={this.handleRequestClose}/>
          {children || <Repo style={styles.repos} repos={this.state.repos} pathToRepo={renderRepo? renderRepo.path: ''}
            selectRepo={this.handleRepoClick} onKeyPress={this.handleKeyPressChange}/>}

      </MuiThemeProvider>
    )
  }

}

export default App;<|endoftext|>


<commit_before>import './config';

import {
  CommandsManager,
  ExtensionManager,
  HotkeysManager,
  utils,
} from 'ohif-core';
import React, { Component } from 'react';
import {
  getUserManagerForOpenIdConnectClient,
  initWebWorkers,
} from './utils/index.js';

import { I18nextProvider } from 'react-i18next';
import OHIFCornerstoneExtension from '@ohif/extension-cornerstone';
import OHIFDicomHtmlExtension from '@ohif/extension-dicom-html';
import OHIFDicomMicroscopyExtension from '@ohif/extension-dicom-microscopy';
import OHIFDicomPDFExtension from '@ohif/extension-dicom-pdf';
import OHIFStandaloneViewer from './OHIFStandaloneViewer';
import OHIFVTKExtension from '@ohif/extension-vtk';
import { OidcProvider } from 'redux-oidc';
import PropTypes from 'prop-types';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import WhiteLabellingContext from './WhiteLabellingContext';
import appCommands from './appCommands';
import { getActiveContexts } from './store/layout/selectors.js';
import i18n from '@ohif/i18n';
import setupTools from './setupTools';
import store from './store';
// Imported flat feature since is not transpiled for old browser versions
import 'core-js/features/array/flat';

// ~~~~ APP SETUP
const commandsManagerConfig = {
  getAppState: () => store.getState(),
  getActiveContexts: () => getActiveContexts(store.getState()),
};

const commandsManager = new CommandsManager(commandsManagerConfig);
const hotkeysManager = new HotkeysManager(commandsManager);
const extensionManager = new ExtensionManager({ commandsManager });

// TODO: Should be done in extensions w/ commandsModule
// ~~ ADD COMMANDS
appCommands.init(commandsManager);
if (window.config.hotkeys) {
  hotkeysManager.setHotkeys(window.config.hotkeys, true);
}
// ~~~~ END APP SETUP

setupTools(store);

// const children = {
//   viewport: [<ConnectedToolContextMenu key="tool-context" />],
// };

/** TODO: extensions should be passed in as prop as soon as we have the extensions as separate packages and then registered by ExtensionsManager */
extensionManager.registerExtensions([
  OHIFCornerstoneExtension,
  OHIFVTKExtension,
  OHIFDicomPDFExtension,
  OHIFDicomHtmlExtension,
  OHIFDicomMicroscopyExtension,
]);

// TODO[react] Use a provider when the whole tree is React
window.store = store;

function handleServers(servers) {
  if (servers) {
    utils.addServers(servers, store);
  }
}

class App extends Component {
  static propTypes = {
    routerBasename: PropTypes.string.isRequired,
    relativeWebWorkerScriptsPath: PropTypes.string.isRequired,
    servers: PropTypes.object.isRequired,
    oidc: PropTypes.array,
    whiteLabelling: PropTypes.object,
  };

  static defaultProps = {
    whiteLabelling: {},
    oidc: [],
  };

  constructor(props) {
    super(props);

    if (this.props.oidc.length) {
      const firstOpenIdClient = this.props.oidc[0];

      this.userManager = getUserManagerForOpenIdConnectClient(
        store,
        firstOpenIdClient
      );
    }
    handleServers(this.props.servers);
    initWebWorkers(
      this.props.routerBasename,
      this.props.relativeWebWorkerScriptsPath
    );
  }

  render() {
    const userManager = this.userManager;

    if (userManager) {
      return (
        <Provider store={store}>
          <I18nextProvider i18n={i18n}>
            <OidcProvider store={store} userManager={userManager}>
              <Router basename={this.props.routerBasename}>
                <WhiteLabellingContext.Provider
                  value={this.props.whiteLabelling}
                >
                  <OHIFStandaloneViewer userManager={userManager} />
                </WhiteLabellingContext.Provider>
              </Router>
            </OidcProvider>
          </I18nextProvider>
        </Provider>
      );
    }

    return (
      <Provider store={store}>
        <I18nextProvider i18n={i18n}>
          <Router basename={this.props.routerBasename}>
            <WhiteLabellingContext.Provider value={this.props.whiteLabelling}>
              <OHIFStandaloneViewer />
            </WhiteLabellingContext.Provider>
          </Router>
        </I18nextProvider>
      </Provider>
    );
  }
}

export default App;

// Make our managers accessible
export { commandsManager, extensionManager, hotkeysManager };
<commit_msg>fix(polyfills): Adds core-js/stable and regenerator-runtime (#590)<commit_after>import './config';

import {
  CommandsManager,
  ExtensionManager,
  HotkeysManager,
  utils,
} from 'ohif-core';
import React, { Component } from 'react';
import {
  getUserManagerForOpenIdConnectClient,
  initWebWorkers,
} from './utils/index.js';

import { I18nextProvider } from 'react-i18next';
import OHIFCornerstoneExtension from '@ohif/extension-cornerstone';
import OHIFDicomHtmlExtension from '@ohif/extension-dicom-html';
import OHIFDicomMicroscopyExtension from '@ohif/extension-dicom-microscopy';
import OHIFDicomPDFExtension from '@ohif/extension-dicom-pdf';
import OHIFStandaloneViewer from './OHIFStandaloneViewer';
import OHIFVTKExtension from '@ohif/extension-vtk';
import { OidcProvider } from 'redux-oidc';
import PropTypes from 'prop-types';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import WhiteLabellingContext from './WhiteLabellingContext';
import appCommands from './appCommands';
import { getActiveContexts } from './store/layout/selectors.js';
import i18n from '@ohif/i18n';
import setupTools from './setupTools';
import store from './store';
// Imported flat feature since is not transpiled for old browser versions
import 'core-js/features/array/flat';
import 'core-js/stable';
import 'regenerator-runtime/runtime';

// ~~~~ APP SETUP
const commandsManagerConfig = {
  getAppState: () => store.getState(),
  getActiveContexts: () => getActiveContexts(store.getState()),
};

const commandsManager = new CommandsManager(commandsManagerConfig);
const hotkeysManager = new HotkeysManager(commandsManager);
const extensionManager = new ExtensionManager({ commandsManager });

// TODO: Should be done in extensions w/ commandsModule
// ~~ ADD COMMANDS
appCommands.init(commandsManager);
if (window.config.hotkeys) {
  hotkeysManager.setHotkeys(window.config.hotkeys, true);
}
// ~~~~ END APP SETUP

setupTools(store);

// const children = {
//   viewport: [<ConnectedToolContextMenu key="tool-context" />],
// };

/** TODO: extensions should be passed in as prop as soon as we have the extensions as separate packages and then registered by ExtensionsManager */
extensionManager.registerExtensions([
  OHIFCornerstoneExtension,
  OHIFVTKExtension,
  OHIFDicomPDFExtension,
  OHIFDicomHtmlExtension,
  OHIFDicomMicroscopyExtension,
]);

// TODO[react] Use a provider when the whole tree is React
window.store = store;

function handleServers(servers) {
  if (servers) {
    utils.addServers(servers, store);
  }
}

class App extends Component {
  static propTypes = {
    routerBasename: PropTypes.string.isRequired,
    relativeWebWorkerScriptsPath: PropTypes.string.isRequired,
    servers: PropTypes.object.isRequired,
    oidc: PropTypes.array,
    whiteLabelling: PropTypes.object,
  };

  static defaultProps = {
    whiteLabelling: {},
    oidc: [],
  };

  constructor(props) {
    super(props);

    if (this.props.oidc.length) {
      const firstOpenIdClient = this.props.oidc[0];

      this.userManager = getUserManagerForOpenIdConnectClient(
        store,
        firstOpenIdClient
      );
    }
    handleServers(this.props.servers);
    initWebWorkers(
      this.props.routerBasename,
      this.props.relativeWebWorkerScriptsPath
    );
  }

  render() {
    const userManager = this.userManager;

    if (userManager) {
      return (
        <Provider store={store}>
          <I18nextProvider i18n={i18n}>
            <OidcProvider store={store} userManager={userManager}>
              <Router basename={this.props.routerBasename}>
                <WhiteLabellingContext.Provider
                  value={this.props.whiteLabelling}
                >
                  <OHIFStandaloneViewer userManager={userManager} />
                </WhiteLabellingContext.Provider>
              </Router>
            </OidcProvider>
          </I18nextProvider>
        </Provider>
      );
    }

    return (
      <Provider store={store}>
        <I18nextProvider i18n={i18n}>
          <Router basename={this.props.routerBasename}>
            <WhiteLabellingContext.Provider value={this.props.whiteLabelling}>
              <OHIFStandaloneViewer />
            </WhiteLabellingContext.Provider>
          </Router>
        </I18nextProvider>
      </Provider>
    );
  }
}

export default App;

// Make our managers accessible
export { commandsManager, extensionManager, hotkeysManager };
<|endoftext|>


<commit_before>import React from 'react'
import * as BooksAPI from './BooksAPI'
import SearchBooks from './SearchBooks'
import BookshelfGrid from './BookshelfGrid'
import { Route } from 'react-router-dom'
import Notifications, { notify } from 'react-notify-toast'
import './App.css'

class BooksApp extends React.Component {
	// this way we can always go back to an initial state when reducing the getAll() result
	initialState = {
		searchResults: [],
		searchResultsMessage: 'Search for books to add to your shelves!',
		bookMap: {},
		currentlyReading: [],
		read: [],
		wantToRead: [],
	}

	// set the state to initial state on load
	state = this.initialState

	// when the component mounts for the first time, retrieve the book list and categorize them
	componentDidMount() {
		BooksAPI.getAll()
			.then(books => {
				// Organize the books into a map (id:object) to allow constant time lookups
				// store the shelf contents as ids, the detailed object can be retreived from the map if needed
				const myState = books.reduce((state, book) => {
					state.bookMap[book.id] = book
					switch (book.shelf) {
						case 'wantToRead':
							state.wantToRead.push(book.id)
							break
						case 'currentlyReading':
							state.currentlyReading.push(book.id)
							break
						case 'read':
							state.read.push(book.id)
							break
						default:
							break
					}
					return state
				}, this.initialState)
				this.setState(myState)
			})
			.catch(error => {
				// show a small toast message when the api call fails
				console.log('an error ocurred', error)
				notify.show(`Failed to communicate with Books API`, 'error', 2000)
			})
	}

	// Check if this id is in any of our shelves
	getCurrentShelf = id => {
		return this.state.read.includes(id)
			? 'read'
			: this.state.currentlyReading.includes(id)
				? 'currentlyReading'
				: this.state.wantToRead.includes(id) ? 'wantToRead' : 'none'
	}

	onSearch = term => {
		// Retrieve the search results from the BooksAPI,
		// filter them for unique entries and set the state
		BooksAPI.search(term)
			.then(books => {
				if (!books || books.error || books.length === 0) {
					if (books && books.error) {
						console.log(books)
						notify.show('Invalid search term', 'error', 2000)
					}
					this.setState({
						searchResults: [],
						searchResultsMessage: `No results found for ${term}`,
					})
					return
				}
				// there are duplicates in the results so we need to filter
				const uniqueIds = new Set()
				const uniqueBooks = books.filter(book => {
					if (uniqueIds.has(book.id)) {
						return false
					}
					uniqueIds.add(book.id)
					return true
				})
				this.setState({
					searchResults: uniqueBooks,
					searchResultsMessage: `${books.length} results found for ${term}`,
				})
			})
			.catch(error => {
				// show a small toast message when the api call fails
				console.log('an error ocurred', error)
				notify.show(`Failed to communicate with Books API`, 'error', 2000)
			})
	}

	// clear the search results, used when the user exist the search screen
	clearSearchResults = () => {
		this.setState({
			searchResults: this.initialState.searchResults,
			searchResultsMessage: this.initialState.searchResultsMessage,
		})
	}

	// When the shelf changes we can directly update the id list of books on each shelf
	// We also need to update the current shelf of the book in the book map
	// (this ensures the select box shows the correct default)
	onShelfChange = (book, shelf) => {
		BooksAPI.update(book, shelf)
			.then(results => {
				this.setState(state => {
					const bookMap = { ...state.bookMap }
					if (bookMap[book.id]) {
						bookMap[book.id].shelf = shelf
					} else {
						BooksAPI.get(book.id).then(book => {
							this.setState(state => {
								bookMap[book.id] = book
								return { bookMap }
							})
						})
					}
					// show a small toast message when the book as changed shelves
					// notify.show(`Succesfully moved book`, 'success', 2000)
					notify.show(`Failed to move book`, 'error', 2000)
					return { ...results, bookMap }
				})
			})
			.catch(error => {
				// show a small toast message when the book as changed shelves
				console.log('an error ocurred', error)
				notify.show(`Failed to move book`, 'error', 2000)
			})
	}

	render() {
		return (

				<Notifications />
				<Route
					path="/search"
					render={({ history }) =>
						<SearchBooks
							history={history}
							searchResults={this.state.searchResults}
							searchResultsMessage={this.state.searchResultsMessage}
							clearSearchResults={this.clearSearchResults}
							onSearch={this.onSearch}
							onShelfChange={this.onShelfChange}
							getCurrentShelf={this.getCurrentShelf}
						/>}
				/>
				<Route
					exact
					path="/"
					render={({ history }) =>

MyReads

							<BookshelfGrid
								bookMap={this.state.bookMap}
								onShelfChange={this.onShelfChange}
								currentlyReading={this.state.currentlyReading}
								read={this.state.read}
								wantToRead={this.state.wantToRead}
							/>

								 history.push('/search')}>Add a book

}
				/>

		)
	}
}

export default BooksApp
<commit_msg>Fixed an error Toast<commit_after>import React from 'react'
import * as BooksAPI from './BooksAPI'
import SearchBooks from './SearchBooks'
import BookshelfGrid from './BookshelfGrid'
import { Route } from 'react-router-dom'
import Notifications, { notify } from 'react-notify-toast'
import './App.css'

class BooksApp extends React.Component {
	// this way we can always go back to an initial state when reducing the getAll() result
	initialState = {
		searchResults: [],
		searchResultsMessage: 'Search for books to add to your shelves!',
		bookMap: {},
		currentlyReading: [],
		read: [],
		wantToRead: [],
	}

	// set the state to initial state on load
	state = this.initialState

	// when the component mounts for the first time, retrieve the book list and categorize them
	componentDidMount() {
		BooksAPI.getAll()
			.then(books => {
				// Organize the books into a map (id:object) to allow constant time lookups
				// store the shelf contents as ids, the detailed object can be retreived from the map if needed
				const myState = books.reduce((state, book) => {
					state.bookMap[book.id] = book
					switch (book.shelf) {
						case 'wantToRead':
							state.wantToRead.push(book.id)
							break
						case 'currentlyReading':
							state.currentlyReading.push(book.id)
							break
						case 'read':
							state.read.push(book.id)
							break
						default:
							break
					}
					return state
				}, this.initialState)
				this.setState(myState)
			})
			.catch(error => {
				// show a small toast message when the api call fails
				console.log('an error ocurred', error)
				notify.show(`Failed to communicate with Books API`, 'error', 2000)
			})
	}

	// Check if this id is in any of our shelves
	getCurrentShelf = id => {
		return this.state.read.includes(id)
			? 'read'
			: this.state.currentlyReading.includes(id)
				? 'currentlyReading'
				: this.state.wantToRead.includes(id) ? 'wantToRead' : 'none'
	}

	onSearch = term => {
		// Retrieve the search results from the BooksAPI,
		// filter them for unique entries and set the state
		BooksAPI.search(term)
			.then(books => {
				if (!books || books.error || books.length === 0) {
					if (books && books.error) {
						console.log(books)
						notify.show('Invalid search term', 'error', 2000)
					}
					this.setState({
						searchResults: [],
						searchResultsMessage: `No results found for ${term}`,
					})
					return
				}
				// there are duplicates in the results so we need to filter
				const uniqueIds = new Set()
				const uniqueBooks = books.filter(book => {
					if (uniqueIds.has(book.id)) {
						return false
					}
					uniqueIds.add(book.id)
					return true
				})
				this.setState({
					searchResults: uniqueBooks,
					searchResultsMessage: `${books.length} results found for ${term}`,
				})
			})
			.catch(error => {
				// show a small toast message when the api call fails
				console.log('an error ocurred', error)
				notify.show(`Failed to communicate with Books API`, 'error', 2000)
			})
	}

	// clear the search results, used when the user exist the search screen
	clearSearchResults = () => {
		this.setState({
			searchResults: this.initialState.searchResults,
			searchResultsMessage: this.initialState.searchResultsMessage,
		})
	}

	// When the shelf changes we can directly update the id list of books on each shelf
	// We also need to update the current shelf of the book in the book map
	// (this ensures the select box shows the correct default)
	onShelfChange = (book, shelf) => {
		BooksAPI.update(book, shelf)
			.then(results => {
				this.setState(state => {
					const bookMap = { ...state.bookMap }
					if (bookMap[book.id]) {
						bookMap[book.id].shelf = shelf
					} else {
						BooksAPI.get(book.id).then(book => {
							this.setState(state => {
								bookMap[book.id] = book
								return { bookMap }
							})
						})
					}
					// show a small toast message when the book as changed shelves
					notify.show(`Succesfully moved book`, 'success', 2000)
					return { ...results, bookMap }
				})
			})
			.catch(error => {
				// show a small toast message when the book as changed shelves
				console.log('an error ocurred', error)
				notify.show(`Failed to move book`, 'error', 2000)
			})
	}

	render() {
		return (

				<Notifications />
				<Route
					path="/search"
					render={({ history }) =>
						<SearchBooks
							history={history}
							searchResults={this.state.searchResults}
							searchResultsMessage={this.state.searchResultsMessage}
							clearSearchResults={this.clearSearchResults}
							onSearch={this.onSearch}
							onShelfChange={this.onShelfChange}
							getCurrentShelf={this.getCurrentShelf}
						/>}
				/>
				<Route
					exact
					path="/"
					render={({ history }) =>

MyReads

							<BookshelfGrid
								bookMap={this.state.bookMap}
								onShelfChange={this.onShelfChange}
								currentlyReading={this.state.currentlyReading}
								read={this.state.read}
								wantToRead={this.state.wantToRead}
							/>

								 history.push('/search')}>Add a book

}
				/>

		)
	}
}

export default BooksApp
<|endoftext|>