<commit_before>
import React, { Component } from 'react';
import {
	Text,
	View,
	InteractionManager,
	ActivityIndicator,
	TextInput,
	StyleSheet,
	Alert,
	TouchableWithoutFeedback,
	TouchableOpacity,
	KeyboardAvoidingView,
} from 'react-native';
import { connect } from 'react-redux';
import Device from 'react-native-device-info';

import Touchable from './common/Touchable';
import { hideKeyboard } from '../util/general';
import logger from '../util/logger';
import css from '../styles/css';
import AppSettings from '../AppSettings';
import {
	COLOR_WHITE,
	COLOR_PRIMARY
} from '../styles/ColorConstants';

class FeedbackView extends Component {

	constructor(props) {
		super(props);

		this.state = {
			commentsText: '',
			nameText: '',
			emailText: '',
			commentsHeight: 0,
			loaded: false,
			submit: false,
		};
	}

	componentDidMount() {
		logger.ga('View Loaded: Feedback');

		InteractionManager.runAfterInteractions(() => {
			this.setState({ loaded: true });
		});
	}

	componentWillReceiveProps(nextProps) {
		// Clear search results when navigating away
		if (nextProps.scene.key !== this.props.scene.key) {
			this.setState({
				commentsText: '',
				nameText: '',
				emailText: '',
			});
		}
	}

	/**
	 * Called after state change
	 * @return bool whether the component should re-render.
	**/
	shouldComponentUpdate(nextProps, nextState) {
		return true;
	}

	_postFeedback() {
		if (this.state.commentsText !== '') {
			this.setState({ loaded: false });

			const formData = new FormData();
			formData.append('element_1', this.state.commentsText);
			formData.append('element_2', this.state.nameText);
			formData.append('element_3', this.state.emailText);
			formData.append(
				'element_4',
				'Device Manufacturer: ' + Device.getManufacturer() + '\n' +
				'Device Brand: ' + Device.getBrand() + '\n' +
				'Device Model: ' + Device.getModel() + '\n' +
				'Device ID: ' + Device.getDeviceId() + '\n' +
				'System Name: ' + Device.getSystemName() + '\n' +
				'System Version: ' + Device.getSystemVersion() + '\n' +
				'Bundle ID: ' + Device.getBundleId() + '\n' +
				'App Version: ' + Device.getVersion() + '\n' +
				'Build Number: ' + Device.getBuildNumber() + '\n' +
				'Device Name: ' + Device.getDeviceName() + '\n' +
				'User Agent: ' + Device.getUserAgent() + '\n' +
				'Device Locale: ' + Device.getDeviceLocale() + '\n' +
				'Device Country: ' + Device.getDeviceCountry() + '\n' +
				'Timezone: ' + Device.getTimezone()
			);
			formData.append('form_id','175631');
			formData.append('submit_form','1');
			formData.append('page_number','1');
			formData.append('submit_form','Submit');

			fetch('https://eforms.ucsd.edu/view.php?id=175631', {
				method: 'POST',
				body: formData
			})
			.then((response) => {
				// Clear fields and alert user
				Alert.alert(
					'Thank you!',
					'We will take your feedback into consideration as we continue developing and improving the app.',
				);

				this.setState({
					submit: true,
					commentsText: '',
					nameText: '',
					emailText: '',
					commentsHeight: 0,
					loaded: true
				});
				return response.json();
			})
			.then((responseJson) => {
				// logger.log(responseJson);
			})
			.catch((error) => {
				logger.log('Error submitting Feedback: ' + error);
			});
		}
		else {
			return;
		}
	}

	_renderLoadingView() {
		return (
			<View style={css.main_container}>
				<ActivityIndicator
					animating={true}
					style={styles.loadingIcon}
					size="large"
				/>
			</View>
		);
	}

	_renderFormView() {
		return (
			<KeyboardAvoidingView
				style={css.main_container}
				behavior="padding"
			>
				<TouchableWithoutFeedback
					onPress={() => hideKeyboard()}
				>
					<View
						style={{ flex: 1 }}
					>
						<Text style={styles.feedbackText}>
							{this.state.labelText}
						</Text>
						<TextInput
							ref={(ref) => { this._feedback = ref; }}
							multiline={true}
							blurOnSubmit={true}
							value={this.state.commentsText}
							onFocus={() => this.setState({
								labelText: ''
							})}
							onChange={(event) => {
								this.setState({
									commentsText: event.nativeEvent.text,
								});
							}}
							placeholder="Tell us what you think*"
							underlineColorAndroid={'transparent'}
							style={[styles.feedbackInput]}
							returnKeyType={'done'}
							maxLength={500}
						/>
						<TextInput
							ref={(ref) => { this._email = ref; }}
							value={this.state.emailText}
							onChangeText={(text) => this.setState({ emailText: text })}
							placeholder="Email"
							underlineColorAndroid={'transparent'}
							style={styles.emailInput}
							returnKeyType={'done'}
							keyboardType={'email-address'}
							maxLength={100}
						/>
						<Touchable
							onPress={() => this._postFeedback()}
						>
							<View style={styles.submitContainer}>
								<Text style={styles.submitText}>Submit</Text>
							</View>
						</Touchable>
					</View>
				</TouchableWithoutFeedback>
			</KeyboardAvoidingView>
		);
	}

	render() {
		// return this._renderSubmitView();
		if (!this.state.loaded) {
			return this._renderLoadingView();
		} else {
			return this._renderFormView();
		}
	}
}

const styles = StyleSheet.create({
	loadingIcon: { flex: 1, alignItems: 'center', justifyContent: 'center' },
	feedbackText: { flexWrap: 'wrap', fontSize: 18, margin: 8, lineHeight: 24 },
	feedbackInput: { flex: 1, backgroundColor: COLOR_WHITE, fontSize: 18, alignItems: 'center', padding: 8, margin: 8, minHeight: 50 },
	emailInput: { backgroundColor: COLOR_WHITE, fontSize: 18, alignItems: 'center', padding: 8, margin: 8, minHeight: 50 },
	submitContainer: { justifyContent: 'center', alignItems: 'center', backgroundColor: COLOR_PRIMARY, borderRadius: 3, padding: 10, margin: 8 },
	submitText: { fontSize: 16, color: COLOR_WHITE },
});

const mapStateToProps = (state, props) => (
	{
		scene: state.routes.scene
	}
);

export default connect(mapStateToProps)(FeedbackView);
<commit_msg>Revert feedbackview to current live version<commit_after>
import React, { Component } from 'react';
import {
	Text,
	View,
	InteractionManager,
	ActivityIndicator,
	TextInput,
	StyleSheet,
	Alert,
	TouchableWithoutFeedback,
	TouchableOpacity
} from 'react-native';
import { connect } from 'react-redux';
import Icon from 'react-native-vector-icons/FontAwesome';
import Device from 'react-native-device-info';

import { hideKeyboard, getCampusPrimary } from '../util/general';
import logger from '../util/logger';
import css from '../styles/css';
import AppSettings from '../AppSettings';

class FeedbackView extends Component {

	constructor(props) {
		super(props);

		this.state = {
			commentsText: '',
			nameText: '',
			emailText: '',
			commentsHeight: 0,
			loaded: false,
			submit: false,
		};
	}

	componentDidMount() {
		logger.ga('View Loaded: Feedback');

		InteractionManager.runAfterInteractions(() => {
			this.setState({ loaded: true });
		});
	}

	componentWillReceiveProps(nextProps) {
		// Clear search results when navigating away
		if (nextProps.scene.key !== this.props.scene.key) {
			this.setState({
				commentsText: '',
				nameText: '',
				emailText: '',
			});
		}
	}

	/**
	 * Called after state change
	 * @return bool whether the component should re-render.
	**/
	shouldComponentUpdate(nextProps, nextState) {
		return true;
	}

	_postFeedback() {
		if (this.state.commentsText !== '') {
			this.setState({ loaded: false });

			const formData = new FormData();
			formData.append('element_1', this.state.commentsText);
			formData.append('element_2', this.state.nameText);
			formData.append('element_3', this.state.emailText);
			formData.append(
				'element_4',
				'Device Manufacturer: ' + Device.getManufacturer() + '\n' +
				'Device Brand: ' + Device.getBrand() + '\n' +
				'Device Model: ' + Device.getModel() + '\n' +
				'Device ID: ' + Device.getDeviceId() + '\n' +
				'System Name: ' + Device.getSystemName() + '\n' +
				'System Version: ' + Device.getSystemVersion() + '\n' +
				'Bundle ID: ' + Device.getBundleId() + '\n' +
				'App Version: ' + Device.getVersion() + '\n' +
				'Build Number: ' + Device.getBuildNumber() + '\n' +
				'Device Name: ' + Device.getDeviceName() + '\n' +
				'User Agent: ' + Device.getUserAgent() + '\n' +
				'Device Locale: ' + Device.getDeviceLocale() + '\n' +
				'Device Country: ' + Device.getDeviceCountry() + '\n' +
				'Timezone: ' + Device.getTimezone()
			);
			formData.append('form_id','175631');
			formData.append('submit_form','1');
			formData.append('page_number','1');
			formData.append('submit_form','Submit');

			fetch('https://eforms.ucsd.edu/view.php?id=175631', {
				method: 'POST',
				body: formData
			})
			.then((response) => {
				// Clear fields and alert user
				Alert.alert(
					'Thank you!',
					'We will take your feedback into consideration as we continue developing and improving the app.',
				);

				this.setState({
					submit: true,
					commentsText: '',
					nameText: '',
					emailText: '',
					commentsHeight: 0,
					loaded: true
				});
				return response.json();
			})
			.then((responseJson) => {
				// logger.log(responseJson);
			})
			.catch((error) => {
				logger.log('Error submitting Feedback: ' + error);
			});
		}
		else {
			return;
		}
	}

	_renderLoadingView() {
		return (
			<View style={css.main_container}>
				<ActivityIndicator
					animating={true}
					style={styles.loading_icon}
					size="large"
				/>
			</View>
		);
	}

	_renderFormView() {
		return (
			<TouchableWithoutFeedback
				onPress={() => hideKeyboard()}
			>
				<View style={css.main_container}>
					<View style={styles.feedback_container}>
						<Text style={styles.feedback_label}>
							Help us make the {AppSettings.APP_NAME} app better.{'\n'}
							Submit your thoughts and suggestions.
						</Text>

						<View style={styles.feedback_text_container}>
							<TextInput
								ref={(ref) => { this._feedback = ref; }}
								multiline={true}
								blurOnSubmit={true}
								value={this.state.commentsText}
								onChange={(event) => {
									this.setState({
										commentsText: event.nativeEvent.text,
										commentsHeight: event.nativeEvent.contentSize.height,
									});
								}}
								placeholder="Tell us what you think*"
								underlineColorAndroid={'transparent'}
								style={[styles.feedback_text, { height: Math.max(50, this.state.commentsHeight) }]}
								returnKeyType={'done'}
								maxLength={500}
							/>
						</View>

						<View style={styles.text_container}>
							<TextInput
								ref={(ref) => { this._email = ref; }}
								value={this.state.emailText}
								onChangeText={(text) => this.setState({ emailText: text })}
								placeholder="Email"
								underlineColorAndroid={'transparent'}
								style={styles.feedback_text}
								returnKeyType={'done'}
								keyboardType={'email-address'}
								maxLength={100}
							/>
						</View>

						<TouchableOpacity underlayColor={'rgba(200,200,200,.1)'} onPress={() => this._postFeedback()}>
							<View style={styles.submit_container}>
								<Text style={styles.submit_text}>Submit</Text>
							</View>
						</TouchableOpacity>

					</View>
				</View>
			</TouchableWithoutFeedback>
		);
	}

	render() {
		// return this._renderSubmitView();
		if (!this.state.loaded) {
			return this._renderLoadingView();
		} else {
			return this._renderFormView();
		}
	}
}

const styles = StyleSheet.create({
	loading_icon: { flex: 1, alignItems: 'center', justifyContent: 'center' },
	feedback_container: { flexDirection: 'column', marginHorizontal: 8, marginTop: 8 },
	feedback_label: { flexWrap: 'wrap', fontSize: 18, paddingBottom: 16, lineHeight: 24 },
	feedback_text: { backgroundColor: '#FFF', flex:1, fontSize: 18, alignItems: 'center', padding: 8 },

	submit_container: { justifyContent: 'center', alignItems: 'center', backgroundColor: getCampusPrimary(), borderRadius: 3, padding: 10 },
	submit_text: { fontSize: 16, color: '#FFF' },

	feedback_text_container: { flexDirection: 'row', borderColor: '#DADADA', borderBottomWidth: 1, marginBottom: 8, backgroundColor: 'white' },
	text_container: { height: 50, borderColor: '#DADADA', borderBottomWidth: 1, marginBottom: 8 },
});

const mapStateToProps = (state, props) => (
	{
		scene: state.routes.scene
	}
);

module.exports = connect(mapStateToProps)(FeedbackView);
<|endoftext|>


<commit_before>/**
 * newrelic agent
 */

require('newrelic');

/**
 * npm dependencies
 */

var _ = require('lodash');
var async = require('async');
var express = require('express');
var path = require('path');

var db = require('./db');
var loadMiddleware = require('./middleware');
var loadRoutes = require('../config/routes');

/**
 * Jobs
 */

var automessagePublisher = require('../workers/automessage-publisher');
var automessageConsumer = require('../workers/automessage-consumer');

/**
 * Helpers
 */

var logger = require('../helpers/logger');

/**
 * If NODE_ENV has not already been defined,
 * then set default environment as 'development'
 */

function setEnv() {
  if (!process.env.NODE_ENV) {
    process.env.NODE_ENV = 'development';
  }
}

/**
 * Start app server
 */

exports.start = function startServer(done) {

  var app = express();

  app.set('port', process.env.PORT || 8002);
  setEnv();

  // common middleware for all routes
  loadMiddleware.common(app);

  // track routes which do not need session
  loadRoutes.track(app);

  // session middleware required for dashboard routes
  loadMiddleware.session(app);

  // cors middlware to allow requests from app.dodatado.com and dodatado.com
  // to api routes
  loadMiddleware.cors(app);

  // dashboard routes
  loadRoutes.dashboard(app);

  // error handling routes
  loadRoutes.error(app);

  async.waterfall(

    [

      function connectDB(cb) {

        db.connect(function (err, db) {
          cb(err, db);
        });

      },

      function startServer(db, cb) {

        var server = app.listen(app.get('port'), function () {
          cb(null, db, server);
        });

      },

      function startCronJobs(db, server, cb) {

        // in the test / development environment, do not run the workers

        if (!_.contains(['test', 'development'], process.env.NODE_ENV)) {

          automessagePublisher();
          automessageConsumer();

        }

        cb(null, db, server);
      }

    ],

    function callback(err, db, server) {

      if (err) {

        logger.crit({
          at: 'load/index',
          err: err
        });

        return (done && done(err));
      };

      printMessage(db, app);
      done && done(null, db, app);

    });

}

/**
 * Stop app server
 */

// exports.stop = function stopServer(done) {

//   console.log('-------------------------------------------------');
//   console.log('   Shutting down server');
//   console.log('-------------------------------------------------');

//   process.exit(0);

// }

function printMessage(db, app) {

  console.log();
  console.log('-------------------------------------------------');
  console.log('   Express server listening');
  console.log();
  console.log('   Port              :     ', app.get('port'));
  console.log('   Environment       :     ', process.env.NODE_ENV);
  console.log('   Database          :     ', db.name);
  console.log('-------------------------------------------------');
  console.log();
  console.log();
  console.log();

}
<commit_msg>api: do not run newrelic agent in test environment<commit_after>/**
 * run newrelic agent (unless in test environment)
 */

if (process.env.NODE_ENV !== 'test') {
  require('newrelic');
}

/**
 * npm dependencies
 */

var _ = require('lodash');
var async = require('async');
var express = require('express');
var path = require('path');

var db = require('./db');
var loadMiddleware = require('./middleware');
var loadRoutes = require('../config/routes');

/**
 * Jobs
 */

var automessagePublisher = require('../workers/automessage-publisher');
var automessageConsumer = require('../workers/automessage-consumer');

/**
 * Helpers
 */

var logger = require('../helpers/logger');

/**
 * If NODE_ENV has not already been defined,
 * then set default environment as 'development'
 */

function setEnv() {
  if (!process.env.NODE_ENV) {
    process.env.NODE_ENV = 'development';
  }
}

/**
 * Start app server
 */

exports.start = function startServer(done) {

  var app = express();

  app.set('port', process.env.PORT || 8002);
  setEnv();

  // common middleware for all routes
  loadMiddleware.common(app);

  // track routes which do not need session
  loadRoutes.track(app);

  // session middleware required for dashboard routes
  loadMiddleware.session(app);

  // cors middlware to allow requests from app.dodatado.com and dodatado.com
  // to api routes
  loadMiddleware.cors(app);

  // dashboard routes
  loadRoutes.dashboard(app);

  // error handling routes
  loadRoutes.error(app);

  async.waterfall(

    [

      function connectDB(cb) {

        db.connect(function (err, db) {
          cb(err, db);
        });

      },

      function startServer(db, cb) {

        var server = app.listen(app.get('port'), function () {
          cb(null, db, server);
        });

      },

      function startCronJobs(db, server, cb) {

        // in the test / development environment, do not run the workers

        if (!_.contains(['test', 'development'], process.env.NODE_ENV)) {

          automessagePublisher();
          automessageConsumer();

        }

        cb(null, db, server);
      }

    ],

    function callback(err, db, server) {

      if (err) {

        logger.crit({
          at: 'load/index',
          err: err
        });

        return (done && done(err));
      };

      printMessage(db, app);
      done && done(null, db, app);

    });

}

/**
 * Stop app server
 */

// exports.stop = function stopServer(done) {

//   console.log('-------------------------------------------------');
//   console.log('   Shutting down server');
//   console.log('-------------------------------------------------');

//   process.exit(0);

// }

function printMessage(db, app) {

  console.log();
  console.log('-------------------------------------------------');
  console.log('   Express server listening');
  console.log();
  console.log('   Port              :     ', app.get('port'));
  console.log('   Environment       :     ', process.env.NODE_ENV);
  console.log('   Database          :     ', db.name);
  console.log('-------------------------------------------------');
  console.log();
  console.log();
  console.log();

}
<|endoftext|>


<commit_before>import React              from 'react';
import ShortId            from 'shortid';
import { attackAnalysis } from 'one-piece';
import Boat               from './Boat';
import CharacterList      from './CharacterList';
import Enemy              from './Enemy';
import './OnePiece.less'

export default class OnePiece extends React.Component {

    constructor (props) {
        super(props);

        this.updateBoat = this.updateBoat.bind(this);
        this.updateEnemy = this.updateEnemy.bind(this);
        this.updateCharacters = this.updateCharacters.bind(this);

        this.state = {
            enemy: { type: '心', defense: 100 }, // 卡普
            boat: 1.5,
            characters: [
                { no: 8,   attack: 1250, bead: 1, timing: 'perfect' },                       // 索隆 Lv.87
                { no: 227, attack: 1285, bead: 1, timing: 'perfect', captainEffect: true },  // 鷹眼 Lv.99
                { no: 227, attack: 1285, bead: 1, timing: 'perfect', captainEffect: true },  // 鷹眼 Lv.99
                { no: 39,  attack: 702,  bead: 1, timing: 'perfect' },                       // 巴其 Lv.61
                { no: 66,  attack: 1491, bead: 1, timing: 'perfect' },                       // 惡龍 Lv.99
                { no: 255, attack: 1155, bead: 1, timing: 'perfect' },                       // 花劍 Lv.71
            ]
        };

        // get the data from local storage
        const data = window.localStorage.getItem('data');
        if (data !== null) {
            this.state = JSON.parse(data);
        }

        // generate unique id for each character
        this.state.characters.forEach(character => { character.id = ShortId.generate() });
    }

    updateBoat(boat) {
        this.setState({ boat });
    }

    updateEnemy (enemy) {
        this.setState({ enemy });
    }

    updateCharacters (characters) {
        this.setState({ characters });
    }

    componentWillUpdate(nextProps, nextState) {
        const { enemy, boat, characters } = nextState;
        const team = characters.map(character => {
            return {
                no: character.no,
                attack: character.attack,
                bead: character.bead,
                timing: character.timing,
                captain: character.captainEffect
            };
        });

        // save the data to local storage
        window.localStorage.setItem('data', JSON.stringify(nextState));

        attackAnalysis({ enemy, boat, team });
    }

    render () {
        return (

梅莉號

                <Boat boat={this.state.boat}
                    onChange={this.updateBoat}
                />

敵人

                <Enemy enemy={this.state.enemy}
                    onChange={this.updateEnemy}
                />

隊員

                <CharacterList
                    characters={this.state.characters}
                    onChange={this.updateCharacters}
                />

        );
    }
}
<commit_msg>[UI] show analysis in UI level<commit_after>import React              from 'react';
import ShortId            from 'shortid';
import { attackAnalysis } from 'one-piece';
import Boat               from './Boat';
import CharacterList      from './CharacterList';
import Enemy              from './Enemy';
import './OnePiece.less'

export default class OnePiece extends React.Component {

    constructor (props) {
        super(props);

        this.updateBoat = this.updateBoat.bind(this);
        this.updateEnemy = this.updateEnemy.bind(this);
        this.updateCharacters = this.updateCharacters.bind(this);

        this.state = {
            enemy: { type: '心', defense: 100 }, // 卡普
            boat: 1.5,
            characters: [
                { no: 8,   attack: 1250, bead: 1, timing: 'perfect' },                       // 索隆 Lv.87
                { no: 227, attack: 1285, bead: 1, timing: 'perfect', captainEffect: true },  // 鷹眼 Lv.99
                { no: 227, attack: 1285, bead: 1, timing: 'perfect', captainEffect: true },  // 鷹眼 Lv.99
                { no: 39,  attack: 702,  bead: 1, timing: 'perfect' },                       // 巴其 Lv.61
                { no: 66,  attack: 1491, bead: 1, timing: 'perfect' },                       // 惡龍 Lv.99
                { no: 255, attack: 1155, bead: 1, timing: 'perfect' },                       // 花劍 Lv.71
            ]
        };

        // get the data from local storage
        const data = window.localStorage.getItem('data');
        if (data !== null) {
            this.state = JSON.parse(data);
        }

        // generate unique id for each character
        this.state.characters.forEach(character => { character.id = ShortId.generate() });
    }

    updateBoat(boat) {
        this.setState({ boat });
    }

    updateEnemy (enemy) {
        this.setState({ enemy });
    }

    updateCharacters (characters) {
        this.setState({ characters });
    }

    componentWillUpdate(nextProps, nextState) {
        const data = nextState;
        console.log(analysisToString(attackAnalysis(data)));

        // save the data to local storage
        window.localStorage.setItem('data', JSON.stringify(data));
    }

    render () {
        return (

梅莉號

                <Boat boat={this.state.boat}
                    onChange={this.updateBoat}
                />

敵人

                <Enemy enemy={this.state.enemy}
                    onChange={this.updateEnemy}
                />

隊員

                <CharacterList
                    characters={this.state.characters}
                    onChange={this.updateCharacters}
                />

        );
    }
}

function analysisToString(data) {
  const { captains, analysis } = data;

  // Captain Effect
  const captainEffectContent = captains.reduce((text, character, index) => {
    const name = character.name.tw ? character.name.tw : character.name.jp;
    const content = character.captainEffect.tw.content ? character.captainEffect.tw.content : character.captainEffect.jp.content;
    return text + `\n${index + 1}. ${name} No.${character.no}\n   ${content}\n`;
  }, '');

  // Analysis
  const analysisContent = analysis.reduce((text, { character, magnification: magni, attack, damage, total }, index) => {
    return text +
`\n第 ${index + 1} 位：${character.name.tw || character.name.jp}

原攻擊力 = ${attack.original}, 連擊 = ${character.combo}
梅莉號：${magni.boat}, 船長：${magni.captain}, 屬珠：${magni.bead}, 剋屬：${magni.type}, Chain：${magni.chain}
加成後攻擊力 = ${attack.basic}
單擊攻擊力   = ${attack.singal}

前 ${attack.combo - 1} 擊傷害  = ${damage.singal}
最後一擊傷害 = ${damage.final} (${attack.timing.toUpperCase()})

累計傷害：
${damage.history.join('\n')} => ${damage.total}

Combo = ${total.combo}
Total = ${total.attack}

--------------------------------------------------------\n`
  }, '');

  return '船長效果：\n'
    + captainEffectContent
    + '\n--------------------------------------------------------\n'
    + analysisContent;
}
<|endoftext|>


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

/**
 * External dependencies
 */
import fetchMock from 'fetch-mock';

export function bootstrapFetchMocks() {
	// Reset first to prevent errors when hot reloading.
	fetchMock.reset();
	fetchMockSaveSettings();
	fetchMockCatchAll();
}

export function fetchMockSaveSettings() {
	fetchMock.post(
		/\/google-site-kit\/v1\/modules\/[\w-]+\/data\/settings/,
		( url, opts ) => {
			const { data } = JSON.parse( opts.body );
			return {
				status: 200,
				body: JSON.stringify( data ),
			};
		}
	);
}

// Catch-all mock to log any other requests.
export function fetchMockCatchAll() {
	fetchMock.mock( '*', ( url, opts ) => {
		global.console.warn( 'fetch', opts.method, url, opts );

		return {
			status: 200,
			body: '{}',
		};
	} );
}

<commit_msg>Use fetchMock.catch instead of wildcard mock.<commit_after>/**
 * Fetch Mocks for use in Storybook.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import fetchMock from 'fetch-mock';

export function bootstrapFetchMocks() {
	// Reset first to prevent errors when hot reloading.
	fetchMock.reset();
	fetchMockSaveSettings();
	fetchMockCatchAll();
}

export function fetchMockSaveSettings() {
	fetchMock.post(
		/\/google-site-kit\/v1\/modules\/[\w-]+\/data\/settings/,
		( url, opts ) => {
			const { data } = JSON.parse( opts.body );
			return {
				status: 200,
				body: JSON.stringify( data ),
			};
		}
	);
}

// Catch-all mock to log any other requests.
export function fetchMockCatchAll() {
	fetchMock.catch( ( url, opts ) => {
		global.console.warn( 'fetch', opts.method, url, opts );

		return {
			status: 200,
			body: '{}',
		};
	} );
}

<|endoftext|>


<commit_before>var clientFileName,
    xhttp = new XMLHttpRequest(),

    publishRelatory = function(){
        $('#date-range-slider-wrapper').addClass('hidden');
        $('#publish-report-button').addClass('hidden');
        $('#interval-wrapper').removeClass('hidden');
        console.log($('#interval-wrapper').attr("class"));

        var createObjectURL = (window.URL || window.webkitURL || {}).createObjectURL || function(){};
        var blob = null;
        var content = document.documentElement.outerHTML;
        var mimeString = "application/octet-stream";
        window.BlobBuilder = window.BlobBuilder ||
                             window.WebKitBlobBuilder ||
                             window.MozBlobBuilder ||
                             window.MSBlobBuilder;

        if(window.BlobBuilder){
           var bb = new BlobBuilder();
           bb.append(content);
           blob = bb.getBlob(mimeString);
        }else{
           blob = new Blob([content], {type : mimeString});
        }

        var url = createObjectURL(blob);
        var now = new Date();
        var a = $("#publish-report-button");
        a.attr("href", url);
        a.attr("download", "js-dump-report-"+diff.apiKey+"-"+now.getDate()+"/"+now.getMonth()+"/"+now.getFullYear()+".html");

        $('#interval-wrapper').addClass("hidden");
        $('#publish-report-button').removeClass('hidden');
        $('#date-range-slider-wrapper').removeClass('hidden');
    },

    prepareReport = function() {
        $('#publish-report-button').addClass('hidden');
        $('#date-range-slider-wrapper').addClass('hidden');
    },

    showResponse = function() {
        $('#publish-report-button').removeClass('hidden');
        $('#date-range-slider-wrapper').removeClass('hidden');
    }

    utf8_to_b64 = function(str) {
        return window.btoa(unescape(encodeURIComponent( str )));
    },

    confirmApiKey = function() {
        var apiKey = $("#api-key-input").val();
        var activationDate = $("#activation-date-input").val();

        if (apiKey) {
            diff.apiKey = apiKey;
            diff.activationDate = activationDate;
            $("#api-key-input-wrapper").addClass("hidden");

            $("#client-title").text("Report of "+diff.apiKey);
            $(".the-client-file-input-label").text(diff.apiKey+" Dump");
            $(".the-platform-file-input-label").text(diff.platformName+" Dump");

            $("#client-file-chooser-wrapper").removeClass("hidden");
        } else {
            $("#api-key-input-group").addClass("has-error");
        }
    },

    editApiKey = function() {
        $("#api-key-input-wrapper").removeClass("hidden");
        $("#client-title-wrapper").addClass("hidden");
    }

    showInfo = function() {
        $("#platform-file-chooser-wrapper").addClass("hidden");
        $("#client-file-chooser-wrapper").addClass("hidden");
        $("#client-title-wrapper").removeClass("hidden");

        if($("#showBlackboard").val() === "Show info") $("#showBlackboard").val("Update")

        resetFilters();

        var platformDateInterval = filterByDateInterval(diff.platformDump.data, diff.clientDump.extentDays[0], diff.clientDump.extentDays[1]),
            clientDateInterval = filterByDateInterval(diff.clientDump.data, diff.clientDump.extentDays[0], diff.clientDump.extentDays[1]),
            groupedClientInterval = groupByOrders(clientDateInterval),
            groupedPlatformInterval = groupByOrders(platformDateInterval);

        diff.inconsistentOrders = 0;

        teste.results = []
        teste.errorOrders = 0;
        teste.warningOrders = 0;
        teste.successOrders = 0;

        showCharts(clientDateInterval, platformDateInterval);

        getOrdersDifference(groupedClientInterval, groupedPlatformInterval);

        for(orderId of getOrdersIntersection(groupedClientInterval, groupedPlatformInterval)){

            var clientOrder = getOrderById(orderId, groupedClientInterval);
            var platformOrder = getOrderById(orderId, groupedPlatformInterval);

            result = testOrder(clientOrder, platformOrder);
            // console.log(result);
            orderResult = newIsOrderOk(result);

            if(orderResult < 0) teste.errorOrders++;
            if(orderResult == 0) teste.warningOrders++;
            if(orderResult > 0) teste.successOrders++;

            teste.results.push(result);
        }
        console.log(teste);

        diff.inconsistentOrders = teste.errorOrders;

        showReport(diff.clientDump, diff.platformDump);

        createClientOnlyOrdersReport(getAllOrdersById(diff.clientDump.onlyOrders, groupedClientInterval));
        createPlatformOnlyOrdersReport(getAllOrdersById(diff.platformDump.onlyOrders, groupedPlatformInterval));
        createTestedOrdersResultReport(teste);

        $("#order-only-on-client").removeClass("hidden");
        $("#report-progress").attr('aria-valuenow','100');
        $("#report-progress").css('width','100%');
        $("#report-progress-bar").addClass("hidden");
        $("#publish-report-button").removeClass("hidden");
        $("#interval").text(moment(diff.clientDump.extentDays[0]).format('YYYY/MM/DD')+" to "+moment(diff.clientDump.extentDays[1]).format('YYYY/MM/DD'));

    },

    setupPlatform = function(data) {
        for (row of data) {
            row.timestamp = moment(row.timestamp, ["YYYY-MM-DD HH:mm:ss"]);
        }

        diff.platformDump = makeDump(data);
    },

    setupClient = function(data) {
        data.forEach(function(row) {
            row.timestamp = moment(row.timestamp, ["YYYY-MM-DD HH:mm:ss"]);
        });

        diff.clientDump = makeDump(data);
        diff.clientDump.extentDays = d3.extent(data, function(row) { return row.timestamp });
    },

    makeDump = function(csvData) {
        var object = {
            data: csvData,
            numberOfRows: csvData.length
        }
        return object;
    }

    calculateAmountTotals = function(clientData, platformData) {
        var clientTotal = 0,
            platformTotal = 0,
            innerData = diffAmountsByDay(clientData, platformData);

        for (summary of innerData) {
            clientTotal += summary[diff.apiKey];
            platformTotal += summary[diff.platformName];
        }

        diff.clientDump.amountTotal = clientTotal;
        diff.platformDump.amountTotal = platformTotal;
    },

    calculateDumpNumberOfTransactions = function(dump, groupedData) {
        dump.numberOfOrders = groupedData.length;
    },

    createDateSlider = function(minDate, maxDate) {
        var beginDate = new Date(minDate.year(), minDate.month(), minDate.date()),
            endDate = new Date(maxDate.year(), maxDate.month(), maxDate.date()),
            formattedBeginDate = beginDate.getDate()+"/"+(beginDate.getMonth()+1)+"/"+beginDate.getFullYear(),
            formattedEndDate = endDate.getDate()+"/"+(endDate.getMonth()+1)+"/"+endDate.getFullYear();

        $("#beginDate").text(formattedBeginDate);
        $("#endDate").text(formattedEndDate);

        $("#slider").dateRangeSlider({
            arrows: false,
            bounds:{
                min: beginDate,
                max: endDate
            },
            defaultValues:{
                min: beginDate,
                max: endDate
            },
            formatter:function(val){
                var days = val.getDate(),
                    month = val.getMonth() + 1,
                    year = val.getFullYear();
                return days + "/" + month + "/" + year;
                // "+ hour + ":" + minute + ":" + second;
            },
            range:{
                min: {days: 2}
            },
            step: {days: 1}
        });

        $("#slider").bind("valuesChanged", function(e, data){
            diff.clientDump.extentDays[0] = data.values.min;
            diff.clientDump.extentDays[1] = data.values.max;
            console.log("Values just changed. min: " + diff.clientDump.extentDays[0] + " max: " + diff.clientDump.extentDays[1]);
        });
    };

$("#the-client-csv-file-input").change(function() {
    clientFileName = this.files[0].name;
    Papa.parse(this.files[0], {
        header: true,
        dynamicTyping: true,
        skipEmptyLines: true,
        // fastMode: true,
        // chunk: function(chunk){
        //   diff.clientData = diff.clientData.concat(chunk.data);
        // },
        error: function(err, reason) {
            console.log(err, reason);
        },
        complete: function(result) {
            console.log(result);
            if (result.errors){
                for (var i = 0; i < result.errors.length; i++) {
                    console.log(result.errors[i]);
                }
            }
            var filteredResult = result.data;
            if(diff.activationDate){
                filteredResult = filterResultByActivationDate(result.data, diff.activationDate);
            }
            setupClient(filteredResult);
            $("#platform-file-chooser-wrapper").removeClass("hidden");
            $("#client-csv-warning-tip").addClass("hidden");
            $("#client-csv-success-tip").removeClass("hidden");
            $("#client-csv-progress-bar").addClass("hidden");
            $("#client-json-tab").addClass("hidden");
        }
 });

  $("#client-csv-progress").attr('aria-valuenow','100');
  $("#client-csv-progress").css('width','100%');

});

$("#the-client-json-file-input").change(function() {
    var URL = window.URL || window.webkitURL ;
    var url = URL.createObjectURL(this.files[0]);
    var size = 0;

    diff.clientData = [];

    oboe(url)
    .done(function(things){
        var teste="";
        for(item of things.items) {
           diff.clientData.push({oid: things.id,
                uid: things.userId,
                timestamp: things.date,
                pid: item.product.id,
                sku: item.product.sku,
                price: +item.product.price,
                quantity: +item.quantity
            });
        }
        teste += JSON.stringify(things)+"\n";
        size += teste.length;

        if(size >= this.header('Content-Length') | size >= (this.header('Content-Length')-1)){
            var filteredResult = diff.clientData;
            if(diff.activationDate){
                filteredResult = filterResultByActivationDate(diff.clientData, diff.activationDate);
            }
            setupClient(filteredResult);
            $("#platform-file-chooser-wrapper").removeClass("hidden");
            $("#client-json-warning-tip").addClass("hidden");
            $("#client-json-success-tip").removeClass("hidden");
            $("#client-json-progress-bar").addClass("hidden");
            $("#client-csv-tab").addClass("hidden");
        }
    });

    $("#client-json-progress").attr('aria-valuenow','100');
    $("#client-json-progress").css('width','100%');
});

$("#the-platform-csv-file-input").change(function() {
  Papa.parse(this.files[0], {
    header: true,
    dynamicTyping: true,
    skipEmptyLines: true,
    // fastMode: true,
    // chunk: function(chunk){
    //   diff.platformData = diff.platformData.concat(chunk.data);
    // },
    error: function(err, reason) {
      console.log(err, reason);
    },
    complete: function(result) {
      console.log(result);
      if (result.errors){
        for (var i = 0; i < result.errors.length; i++) {
          console.log(result.errors[i]);
        }
      }
      var filteredResult = result.data;
      if(diff.activationDate){
          filteredResult = filterResultByActivationDate(result.data, diff.activationDate);
      }
      setupPlatform(filteredResult);
      $("#date-range-slider-wrapper").removeClass("hidden");
      $("#platform-csv-warning-tip").addClass("hidden");
      $("#platform-csv-success-tip").removeClass("hidden");
      $("#platform-csv-progress-bar").addClass("hidden");
      $("#platform-json-tab").addClass("hidden");
      createDateSlider(diff.clientDump.extentDays[0], diff.clientDump.extentDays[1]);
    }
  });

  $("#platform-csv-progress").attr('aria-valuenow','100');
  $("#platform-csv-progress").css('width','100%');
});

$("#the-platform-json-file-input").change(function() {
    var URL = window.URL || window.webkitURL ;
    var url = URL.createObjectURL(this.files[0]);
    var size = 0;

    diff.clientData = [];

    oboe(url)
    .done(function(things){
        var teste="";
        for(item of things.items) {
           diff.clientData.push({oid: things.id,
                uid: things.userId,
                timestamp: things.date,
                pid: item.product.id,
                sku: item.product.sku,
                price: +item.product.price,
                quantity: +item.quantity
            });
            if(item.quantity) teste += ".0";
        }
        teste += JSON.stringify(things)+"\n";
        size += teste.length;

        if(size >= this.header('Content-Length') | size >= (this.header('Content-Length')-6)){
            var filteredResult = diff.clientData;
            if(diff.activationDate){
                filteredResult = filterResultByActivationDate(diff.clientData, diff.activationDate);
            }
            setupPlatform(filteredResult);
            $("#date-range-slider-wrapper").removeClass("hidden");
            $("#platform-json-warning-tip").addClass("hidden");
            $("#platform-json-success-tip").removeClass("hidden");
            $("#platform-json-progress-bar").addClass("hidden");
            $("#platform-csv-tab").addClass("hidden");
            createDateSlider(diff.clientDump.extentDays[0], diff.clientDump.extentDays[1]);
        }
    });
    $("#platform-json-progress").attr('aria-valuenow','100');
    $("#platform-json-progress").css('width','100%');
});

$('#activation-date-input').datetimepicker({
    format: 'YYYY-MM-DD',
    extraFormats: [ 'YYYY-MM-DD HH:mm:SS', moment.ISO_8601 ]
});
<commit_msg>removed app/analysis.js<commit_after><|endoftext|>


<commit_before>angular.module('starter.controllers', [])

.controller('SyncCtrl', function($scope, $ionicHistory) {
	$scope.$on('$ionicView.enter', function(e) {
		sync()
		$ionicHistory.goBack(-1);
	});
})

.controller('SubmitCtrl', function($scope) {})

.controller('DataCtrl', function($scope, Chats) {
	// With the new view caching in Ionic, Controllers are only called
	// when they are recreated or on app start, instead of every page change.
	// To listen for when this page is active (for example, to refresh data),
	// listen for the $ionicView.enter event:
	//
	$scope.$on('$ionicView.enter', function(e) {
		sync()
		// fill in and stuff
	});

});
<commit_msg>Dont sync on entrance to database and sync tab<commit_after>angular.module('starter.controllers', [])

.controller('SyncCtrl', function($scope, $ionicHistory) {

})

.controller('SubmitCtrl', function($scope) {})

.controller('DataCtrl', function($scope, Chats) {

});
<|endoftext|>


<commit_before>'use strict';
(function(_htmlTag) {
  _htmlTag.className = _htmlTag.className.replace(/\bno-js\b/, '');
})(document.documentElement);
<commit_msg>修正 init js<commit_after>'use strict';
(function(_htmlTag) {
  _htmlTag.className = _htmlTag.className.replace(/\bno-js\b/, ' js ');
})(document.documentElement);
<|endoftext|>


<commit_before>const config = require('config');
const mysql = require('promise-mysql');

const logger = require('~/logger');

const pool = mysql.createPool(config.get('mysql'));

function dbMiddleware() {
  return async (ctx, next) => {
    const db = await pool.getConnection();
    ctx.state.db = db;
    try {
      await next();
    } finally {
      pool.releaseConnection(db);
    }
  };
}

async function initDatabase() {
  const scripts = [
    `CREATE TABLE IF NOT EXISTS user (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      osmId INT UNSIGNED NULL UNIQUE,
      facebookUserId VARCHAR(32) CHARSET latin1 COLLATE latin1_bin NULL UNIQUE,
      googleUserId VARCHAR(32) CHARSET latin1 COLLATE latin1_bin NULL UNIQUE,
      name VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NOT NULL,
      email VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      isAdmin BOOL NOT NULL DEFAULT 0,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      lat FLOAT(8, 6) NULL,
      lon FLOAT(9, 6) NULL,
      settings VARCHAR(4096) CHARSET utf8 COLLATE utf8_bin NOT NULL DEFAULT '{}',
      preventTips BOOL NOT NULL DEFAULT 0
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS auth (
      authToken VARCHAR(255) CHARSET utf8 COLLATE utf8_bin PRIMARY KEY,
      userId INT UNSIGNED NOT NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      osmAuthToken VARCHAR(255) CHARSET latin1 COLLATE latin1_bin NULL UNIQUE,
      osmAuthTokenSecret VARCHAR(255) CHARSET latin1 COLLATE latin1_bin NULL,
      facebookAccessToken VARCHAR(255) CHARSET latin1 COLLATE latin1_bin NULL,
      googleIdToken VARCHAR(4095) CHARSET latin1 COLLATE latin1_bin NULL,
      FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS picture (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      pathname VARCHAR(255) CHARSET utf8 COLLATE utf8_bin NOT NULL UNIQUE,
      userId INT UNSIGNED NOT NULL,
      title VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      description VARCHAR(4096) CHARSET utf8 COLLATE utf8_general_ci NULL,
      takenAt TIMESTAMP NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      lat FLOAT(8, 6) NULL,
      lon FLOAT(9, 6) NULL,
      FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE,
      INDEX USING BTREE (lat),
      INDEX USING BTREE (lon)
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS pictureTag (
      pictureId INT UNSIGNED NOT NULL,
      name VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci,
      PRIMARY KEY (pictureId, name),
      FOREIGN KEY (pictureId) REFERENCES picture (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS pictureComment (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      pictureId INT UNSIGNED NOT NULL,
      userId INT UNSIGNED NOT NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      comment VARCHAR(4096) CHARSET utf8 COLLATE utf8_general_ci,
      FOREIGN KEY (pictureId) REFERENCES picture (id) ON DELETE CASCADE,
      FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS pictureRating (
      userId INT UNSIGNED NOT NULL,
      pictureId INT UNSIGNED NOT NULL,
      stars TINYINT UNSIGNED NOT NULL,
      ratedAt TIMESTAMP NOT NULL,
      PRIMARY KEY (pictureId, userId),
      FOREIGN KEY (pictureId) REFERENCES picture (id) ON DELETE CASCADE,
      FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS trackingDevice (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      userId INT UNSIGNED NOT NULL,
      name VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NOT NULL,
      token VARCHAR(255) CHARSET ascii NOT NULL UNIQUE,
      maxCount INT UNSIGNED NULL,
      maxAge INT UNSIGNED NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      CONSTRAINT tdUserFk FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS trackingPoint (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      deviceId INT UNSIGNED NOT NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      lat FLOAT(8, 6) NOT NULL,
      lon FLOAT(9, 6) NOT NULL,
      altitude FLOAT(4, 1) NULL,
      speed FLOAT(4, 1) NULL,
      accuracy FLOAT(4, 1) NULL,
      bearing FLOAT NULL,
      battery FLOAT(3) NULL,
      gsmSignal FLOAT(3) NULL,
      message VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      CONSTRAINT tpDeviceIdFk FOREIGN KEY (deviceId) REFERENCES trackingDevice (id) ON DELETE CASCADE,
      INDEX tpCreatedAtIdx (createdAt)
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS trackingAccessToken (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      deviceId INT UNSIGNED NOT NULL,
      token VARCHAR(255) CHARSET ascii NOT NULL UNIQUE,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      timeFrom TIMESTAMP NULL,
      timeTo TIMESTAMP NULL,
      listingLabel VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      note VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      CONSTRAINT tatDeviceIdFk FOREIGN KEY (deviceId) REFERENCES trackingDevice (id) ON DELETE CASCADE,
      INDEX tatCreatedAtIdx (createdAt)
    ) ENGINE=InnoDB`,
  ];

  const updates = [
  ];

  const db = await pool.getConnection();
  try {
    /* eslint-disable no-await-in-loop, no-restricted-syntax */
    for (const script of scripts) {
      await db.query(script);
    }

    for (const script of updates) {
      try {
        await db.query(script);
      } catch (err) {
        logger.info(`Unsuccessful SQL ${script}: ${err.message}`);
      }
    }
  } finally {
    pool.releaseConnection(db);
  }
}

module.exports = { pool, dbMiddleware, initDatabase };
<commit_msg>fixed db<commit_after>const config = require('config');
const mysql = require('promise-mysql');

const logger = require('~/logger');

const pool = mysql.createPool(config.get('mysql'));

function dbMiddleware() {
  return async (ctx, next) => {
    const db = await pool.getConnection();
    ctx.state.db = db;
    try {
      await next();
    } finally {
      pool.releaseConnection(db);
    }
  };
}

async function initDatabase() {
  const scripts = [
    `CREATE TABLE IF NOT EXISTS user (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      osmId INT UNSIGNED NULL UNIQUE,
      facebookUserId VARCHAR(32) CHARSET latin1 COLLATE latin1_bin NULL UNIQUE,
      googleUserId VARCHAR(32) CHARSET latin1 COLLATE latin1_bin NULL UNIQUE,
      name VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NOT NULL,
      email VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      isAdmin BOOL NOT NULL DEFAULT 0,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      lat FLOAT(8, 6) NULL,
      lon FLOAT(9, 6) NULL,
      settings VARCHAR(4096) CHARSET utf8 COLLATE utf8_bin NOT NULL DEFAULT '{}',
      preventTips BOOL NOT NULL DEFAULT 0
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS auth (
      authToken VARCHAR(255) CHARSET utf8 COLLATE utf8_bin PRIMARY KEY,
      userId INT UNSIGNED NOT NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      osmAuthToken VARCHAR(255) CHARSET latin1 COLLATE latin1_bin NULL UNIQUE,
      osmAuthTokenSecret VARCHAR(255) CHARSET latin1 COLLATE latin1_bin NULL,
      facebookAccessToken VARCHAR(255) CHARSET latin1 COLLATE latin1_bin NULL,
      googleIdToken VARCHAR(4095) CHARSET latin1 COLLATE latin1_bin NULL,
      FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS picture (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      pathname VARCHAR(255) CHARSET utf8 COLLATE utf8_bin NOT NULL UNIQUE,
      userId INT UNSIGNED NOT NULL,
      title VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      description VARCHAR(4096) CHARSET utf8 COLLATE utf8_general_ci NULL,
      takenAt TIMESTAMP NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      lat FLOAT(8, 6) NOT NULL,
      lon FLOAT(9, 6) NOT NULL,
      FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE,
      INDEX USING BTREE (lat),
      INDEX USING BTREE (lon)
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS pictureTag (
      pictureId INT UNSIGNED NOT NULL,
      name VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci,
      PRIMARY KEY (pictureId, name),
      FOREIGN KEY (pictureId) REFERENCES picture (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS pictureComment (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      pictureId INT UNSIGNED NOT NULL,
      userId INT UNSIGNED NOT NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      comment VARCHAR(4096) CHARSET utf8 COLLATE utf8_general_ci,
      FOREIGN KEY (pictureId) REFERENCES picture (id) ON DELETE CASCADE,
      FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS pictureRating (
      userId INT UNSIGNED NOT NULL,
      pictureId INT UNSIGNED NOT NULL,
      stars TINYINT UNSIGNED NOT NULL,
      ratedAt TIMESTAMP NOT NULL,
      PRIMARY KEY (pictureId, userId),
      FOREIGN KEY (pictureId) REFERENCES picture (id) ON DELETE CASCADE,
      FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS trackingDevice (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      userId INT UNSIGNED NOT NULL,
      name VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NOT NULL,
      token VARCHAR(255) CHARSET ascii NOT NULL UNIQUE,
      maxCount INT UNSIGNED NULL,
      maxAge INT UNSIGNED NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      CONSTRAINT tdUserFk FOREIGN KEY (userId) REFERENCES user (id) ON DELETE CASCADE
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS trackingPoint (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      deviceId INT UNSIGNED NOT NULL,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      lat FLOAT(8, 6) NOT NULL,
      lon FLOAT(9, 6) NOT NULL,
      altitude FLOAT NULL,
      speed FLOAT NULL,
      accuracy FLOAT NULL,
      bearing FLOAT NULL,
      battery FLOAT NULL,
      gsmSignal FLOAT NULL,
      message VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      CONSTRAINT tpDeviceIdFk FOREIGN KEY (deviceId) REFERENCES trackingDevice (id) ON DELETE CASCADE,
      INDEX tpCreatedAtIdx (createdAt)
    ) ENGINE=InnoDB`,

    `CREATE TABLE IF NOT EXISTS trackingAccessToken (
      id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
      deviceId INT UNSIGNED NOT NULL,
      token VARCHAR(255) CHARSET ascii NOT NULL UNIQUE,
      createdAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
      timeFrom TIMESTAMP NULL,
      timeTo TIMESTAMP NULL,
      listingLabel VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      note VARCHAR(255) CHARSET utf8 COLLATE utf8_general_ci NULL,
      CONSTRAINT tatDeviceIdFk FOREIGN KEY (deviceId) REFERENCES trackingDevice (id) ON DELETE CASCADE,
      INDEX tatCreatedAtIdx (createdAt)
    ) ENGINE=InnoDB`,
  ];

  const updates = [
  ];

  const db = await pool.getConnection();
  try {
    /* eslint-disable no-await-in-loop, no-restricted-syntax */
    for (const script of scripts) {
      await db.query(script);
    }

    for (const script of updates) {
      try {
        await db.query(script);
      } catch (err) {
        logger.info(`Unsuccessful SQL ${script}: ${err.message}`);
      }
    }
  } finally {
    pool.releaseConnection(db);
  }
}

module.exports = { pool, dbMiddleware, initDatabase };
<|endoftext|>


<commit_before>'use strict';

// Use Webpack's require.context to manage dynamic requires for templates
// The templates will be cached when the application is booted
// https://webpack.js.org/guides/dependency-management/#require-context
var template = require.context('../views', true, /(partials|content-pages)\/.*\.html$/);

var app = angular.module('ddsRecapSituation', ['ui.router', 'ngSanitize', 'ddsCommon']);

app.config(function($locationProvider, $stateProvider) {
    moment.locale('fr');
    $locationProvider.html5Mode(true);
    $stateProvider.state('home', {
        url: '/:situationId',
        controller: '',
        resolve: {
            situation: function($stateParams, SituationService) {
                return SituationService.restoreRemote($stateParams.situationId);
            }
        },
        views: {
            '': {
                controller: 'EmbedCtrl',
                template: '

',
            },
            'recap_situation@home': {
                controller: 'RecapSituationCtrl',
                templateUrl: '/partials/foyer/recap-situation.html'
            }
        },
    });
}).controller('EmbedCtrl', function($scope, situation) {
    $scope.situation = situation;
});

app.run(function($templateCache) {
    // Preload templates in cache
    // We use the keys() function of the context module API
    // to iterate over the templates, and we store them in Angular's template cache.
    // This means Angular won't try to load the template via AJAX
    _.forEach(template.keys(), function(path) {
        var cacheKey = path.replace('./', '/');
        $templateCache.put(cacheKey, template(path));
    });
});
<commit_msg>Répare la vue recadrée<commit_after>'use strict';

// Use Webpack's require.context to manage dynamic requires for templates
// The templates will be cached when the application is booted
// https://webpack.js.org/guides/dependency-management/#require-context
var template = require.context('../views', true, /(partials|content-pages)\/.*\.html$/);

var app = angular.module('ddsRecapSituation', ['ui.router', 'ngSanitize', 'ddsCommon']);

app.config(function($locationProvider, $stateProvider) {
    moment.locale('fr');
    $locationProvider.html5Mode(true);
    $stateProvider.state('home', {
        url: '/:situationId',
        resolve: {
            situation: function($stateParams, SituationService) {
                return SituationService.restoreRemote($stateParams.situationId);
            }
        },
        views: {
            '': {
                controller: 'EmbedCtrl',
                template: '

',
            },
            'recap_situation@home': {
                controller: 'RecapSituationCtrl',
                templateUrl: '/partials/foyer/recap-situation.html'
            }
        },
    });
}).controller('EmbedCtrl', function($scope, situation) {
    $scope.situation = situation;
});

app.run(function($templateCache) {
    // Preload templates in cache
    // We use the keys() function of the context module API
    // to iterate over the templates, and we store them in Angular's template cache.
    // This means Angular won't try to load the template via AJAX
    _.forEach(template.keys(), function(path) {
        var cacheKey = path.replace('./', '/');
        $templateCache.put(cacheKey, template(path));
    });
});
<|endoftext|>


<commit_before>// Global variables
var csvFields;
var map;
var zoom;
var layer;
var percent;
var fieldSelect;
var stat;
var body;
/*
 * Main program instructions
 */
$(document).ready(function()
{
  init();
});
/*
 * End of main program instructions
 */

function init()
{
  csvFields = getCSVFields(initCartogram);
          var features = carto.features(topology, geometries),
            path = d3.geo.path()
              .projection(proj);

        states = states.data(features)
          .enter()
          .append("path")
            .attr("class", "state")
            .attr("id", function(d) {
              return d.properties.NAME;
            })
            .attr("fill", "#fafafa")
            .attr("d", path);

        states.append("title");

        parseHash();

}

function initCartogram(csvFields)
{
  fields = csvFields;
  // Data info for the cartogram
  percent = (function() {
          var fmt = d3.format(".2f");
          return function(n) { return fmt(n) + "%"; };
      })(),
      fields = csvFields,
      // TODO: Make this customizable
      // NOTE: Might just have this detect if there are digits at the end of the column or beginning, and if there are then use those as a year
      years = [2010, 2011],
      fieldsById = d3.nest()
          .key(function(d) { return d.id; })
          .rollup(function(d) { return d[0]; })
          .map(fields),
      field = fields[0],
      year = years[0],
      colors = colorbrewer.RdYlBu[3]
          .reverse()
          .map(function(rgb) { return d3.hsl(rgb); });

          body = d3.select("body");
          stat = d3.select("#status");

          fieldSelect = d3.select("#field")
              .on("change", function(e) {
                  field = fields[this.selectedIndex];
                  location.hash = "#" + [field.id, year].join("/");
              });

          fieldSelect.selectAll("option")
              .data(fields)
              .enter()
              .append("option")
              .attr("value", function(d) { return d.id; })
              .text(function(d) { return d.name; });

          /* TODO: Reincorporate year
          var yearSelect = d3.select("#year")
              .on("change", function(e) {
                  year = years[this.selectedIndex];
                  location.hash = "#" + [field.id, year].join("/");
              });

          yearSelect.selectAll("option")
              .data(years)
              .enter()
              .append("option")
              .attr("value", function(y) { return y; })
              .text(function(y) { return y; })
          */

          map = d3.select("#map");
          zoom = d3.behavior.zoom()
              .translate([-38, 32])
              .scale(.94)
              .scaleExtent([0.5, 10.0])
              .on("zoom", updateZoom);
          layer = map.append("g")
              .attr("id", "layer"),
          states = layer.append("g")
              .attr("id", "states")
              .selectAll("path");

          updateZoom();
}

var proj = d3.geo.albersUsa(),
    topology,
    geometries,
    rawData,
    dataById = {},
    carto = d3.cartogram()
        .projection(proj)
        .properties(function(d) {
            return dataById[d.id];
        })
        .value(function(d) {
            return +d.properties[field];
        });

window.onhashchange = function() {
    parseHash();
};

var segmentized = location.search === "?segmentized",
    url = ["data",
        segmentized ? "us-states-segmentized.topojson" : "us-states.topojson"
    ].join("/");
d3.json(url, function(topo) {
    topology = topo;
    geometries = topology.objects.states.geometries;
    d3.csv(DATA_DIRECTORY + DATASHEET, function(data) {
        rawData = data;
        dataById = d3.nest()
            .key(function(d) { return d.NAME; })
            .rollup(function(d) { return d[0]; })
            .map(data);
        init();
    });
});

var deferredUpdate = (function() {
    var timeout;
    return function() {
        var args = arguments;
        clearTimeout(timeout);
        stat.text("calculating...");
        return timeout = setTimeout(function() {
            update.apply(null, arguments);
        }, 10);
    };
})();

var hashish = d3.selectAll("a.hashish")
    .datum(function() {
        return this.href;
    });
<commit_msg>Addressed uncaught reference type error<commit_after>// Global variables
var csvFields;
var map;
var zoom;
var layer;
var percent;
var fieldSelect;
var stat;
var body;
/*
 * Main program instructions
 */
$(document).ready(function()
{
  init();
});
/*
 * End of main program instructions
 */

function init()
{
  csvFields = getCSVFields(initCartogram);
          }

function initCartogram(csvFields)
{
  fields = csvFields;
  // Data info for the cartogram
  percent = (function() {
          var fmt = d3.format(".2f");
          return function(n) { return fmt(n) + "%"; };
      })(),
      fields = csvFields,
      // TODO: Make this customizable
      // NOTE: Might just have this detect if there are digits at the end of the column or beginning, and if there are then use those as a year
      years = [2010, 2011],
      fieldsById = d3.nest()
          .key(function(d) { return d.id; })
          .rollup(function(d) { return d[0]; })
          .map(fields),
      field = fields[0],
      year = years[0],
      colors = colorbrewer.RdYlBu[3]
          .reverse()
          .map(function(rgb) { return d3.hsl(rgb); });

          body = d3.select("body");
          stat = d3.select("#status");

          fieldSelect = d3.select("#field")
              .on("change", function(e) {
                  field = fields[this.selectedIndex];
                  location.hash = "#" + [field.id, year].join("/");
              });

          fieldSelect.selectAll("option")
              .data(fields)
              .enter()
              .append("option")
              .attr("value", function(d) { return d.id; })
              .text(function(d) { return d.name; });

          /* TODO: Reincorporate year
          var yearSelect = d3.select("#year")
              .on("change", function(e) {
                  year = years[this.selectedIndex];
                  location.hash = "#" + [field.id, year].join("/");
              });

          yearSelect.selectAll("option")
              .data(years)
              .enter()
              .append("option")
              .attr("value", function(y) { return y; })
              .text(function(y) { return y; })
          */

          map = d3.select("#map");
          zoom = d3.behavior.zoom()
              .translate([-38, 32])
              .scale(.94)
              .scaleExtent([0.5, 10.0])
              .on("zoom", updateZoom);
          layer = map.append("g")
              .attr("id", "layer"),
          states = layer.append("g")
              .attr("id", "states")
              .selectAll("path");

          updateZoom();
}

var proj = d3.geo.albersUsa(),
    topology,
    geometries,
    rawData,
    dataById = {},
    carto = d3.cartogram()
        .projection(proj)
        .properties(function(d) {
            return dataById[d.id];
        })
        .value(function(d) {
            return +d.properties[field];
        });

window.onhashchange = function() {
    parseHash();
};

var segmentized = location.search === "?segmentized",
    url = ["data",
        segmentized ? "us-states-segmentized.topojson" : "us-states.topojson"
    ].join("/");
d3.json(url, function(topo) {
    topology = topo;
    geometries = topology.objects.states.geometries;
    d3.csv(DATA_DIRECTORY + DATASHEET, function(data) {
        rawData = data;
        dataById = d3.nest()
            .key(function(d) { return d.NAME; })
            .rollup(function(d) { return d[0]; })
            .map(data);
     var features = carto.features(topology, geometries),
            path = d3.geo.path()
              .projection(proj);

        states = states.data(features)
          .enter()
          .append("path")
            .attr("class", "state")
            .attr("id", function(d) {
              return d.properties.NAME;
            })
            .attr("fill", "#fafafa")
            .attr("d", path);

        states.append("title");

        parseHash();

        init();
    });
});

var deferredUpdate = (function() {
    var timeout;
    return function() {
        var args = arguments;
        clearTimeout(timeout);
        stat.text("calculating...");
        return timeout = setTimeout(function() {
            update.apply(null, arguments);
        }, 10);
    };
})();

var hashish = d3.selectAll("a.hashish")
    .datum(function() {
        return this.href;
    });
<|endoftext|>


<commit_before>var Marionette = require('marionette');
var _ = require('underscore');

module.exports = Marionette.Behavior.extend({
	initialize: function() {
		// Inject the necessary methods to perform validation in the view.
		this.view.triggerValidation = function(e) {
			this.validate(e);
			this.scrollToFirstError();
		}.bind(this);

		this.view.triggerRevalidation = this.revalidate.bind(this);
	},

	onRender: function() {
		this._rules = this.options.rules;
		this._handleErrors = true;

		if(this.options.handleErrors === false) {
			this._handleErrors = false;
		}

		// rules can be passed as a function.
		if(_.isFunction(this._rules)) {
			this._rules = this._rules.apply(this.view);
		}
	},

	/*
	*	Function to trigger the first validation.
	*/
	validate: function(e) {
		if(e) {	e.preventDefault(); }

		this._errors = [];
		this.hideErrors();

		_(this._rules).each(function(fns, field) {
			this.prepareRuleFns(fns, this.view.$(field));
		}.bind(this));

		this.broadcastErrors();
		this.triggered = true;
	},

	/*
	*	Function to trigger the subsequent validations.
	*/
	revalidate: function(e) {
		if(this.triggered) {
			this.validate(null);
		}
	},

	/*
	*	Prepare the functions. Verify and normalize the format of the rules passed.
	*/
	prepareRuleFns: function(fns, field) {
		if(!_.some(fns, _.isArray)) {
			fns = [fns];
		}

		_(fns).each(function(fn) {
			if(!_.isFunction(fn) && !_.isFunction(fn[0])) {
				fn = require('./rules/' + fn[0]).apply(fn, _.rest(fn) );
			}
			this.executeRuleFn(fn, field);
		}, this);
	},

	/*
	*	Execute the function associated with the rule.
	*/
	executeRuleFn: function(fn, field) {
		// only visible fields trigger validation.
		if(field.is(':visible') || field.attr('type') === 'hidden') {
			var errorMessage = fn.call(this, field);

			if(errorMessage) {
				field.addClass('validated-field');
				this.showError(field, errorMessage);
				this._errors.push({field: field, message: errorMessage});
			}
		}
	},

	/*
	*	Send the errors collection to view on event onValidate.
	*/
	broadcastErrors: function() {
		this.view.triggerMethod('validation', this._errors);
	},

	/*
	*	Show the error messages.
	*/
	showError: function(field, errorMessage) {
		if(this._handleErrors) {
			if(!field.parents('.form-group').hasClass('has-error')) {
				field
					.parents('.form-group')
					.addClass('has-error')
					.append('
' + errorMessage + '
');
			}
		}
	},

	/*
	*	Hide the error messages.
	*/
	hideErrors: function() {
		if(this._handleErrors) {
			this.view.$('.form-group')
				.removeClass('has-error')
				.find('div.text-danger')
				.remove();
		}
	},

	/*
	*	Scroll to the first error
	*/
	scrollToFirstError: function() {
		try {
			if(this.view.$('.has-error').length > 0) {
				var top = this.view.$('.has-error').position().top;
				if(top) {
					$('body').scrollTop(top);
				}
			}
		} catch(err) {}
	}
});
<commit_msg>scroll to the first error<commit_after>var Marionette = require('marionette');
var _ = require('underscore');

module.exports = Marionette.Behavior.extend({
	initialize: function() {
		// Inject the necessary methods to perform validation in the view.
		this.view.triggerValidation = function(e) {
			this.validate(e);

			if(this._handleErrors && this._scrollToFirstError) {
				this.scrollToFirstError();
			}
		}.bind(this);

		this.view.triggerRevalidation = this.revalidate.bind(this);
	},

	onRender: function() {
		this._rules = this.options.rules;
		this._handleErrors = true;
		this._scrollToFirstError = true;

		if(this.options.handleErrors === false) {
			this._handleErrors = false;
		}

		if(this.options.scrollToFirstError === false) {
			this._scrollToFirstError = false;
		}

		// rules can be passed as a function.
		if(_.isFunction(this._rules)) {
			this._rules = this._rules.apply(this.view);
		}
	},

	/*
	*	Function to trigger the first validation.
	*/
	validate: function(e) {
		if(e) {	e.preventDefault(); }

		this._errors = [];
		this.hideErrors();

		_(this._rules).each(function(fns, field) {
			this.prepareRuleFns(fns, this.view.$(field));
		}.bind(this));

		this.broadcastErrors();
		this.triggered = true;
	},

	/*
	*	Function to trigger the subsequent validations.
	*/
	revalidate: function(e) {
		if(this.triggered) {
			this.validate(null);
		}
	},

	/*
	*	Prepare the functions. Verify and normalize the format of the rules passed.
	*/
	prepareRuleFns: function(fns, field) {
		if(!_.some(fns, _.isArray)) {
			fns = [fns];
		}

		_(fns).each(function(fn) {
			if(!_.isFunction(fn) && !_.isFunction(fn[0])) {
				fn = require('./rules/' + fn[0]).apply(fn, _.rest(fn) );
			}
			this.executeRuleFn(fn, field);
		}, this);
	},

	/*
	*	Execute the function associated with the rule.
	*/
	executeRuleFn: function(fn, field) {
		// only visible fields trigger validation.
		if(field.is(':visible') || field.attr('type') === 'hidden') {
			var errorMessage = fn.call(this, field);

			if(errorMessage) {
				field.addClass('validated-field');
				this.showError(field, errorMessage);
				this._errors.push({field: field, message: errorMessage});
			}
		}
	},

	/*
	*	Send the errors collection to view on event onValidate.
	*/
	broadcastErrors: function() {
		this.view.triggerMethod('validation', this._errors);
	},

	/*
	*	Show the error messages.
	*/
	showError: function(field, errorMessage) {
		if(this._handleErrors) {
			if(!field.parents('.form-group').hasClass('has-error')) {
				field
					.parents('.form-group')
					.addClass('has-error')
					.append('
' + errorMessage + '
');
			}
		}
	},

	/*
	*	Hide the error messages.
	*/
	hideErrors: function() {
		if(this._handleErrors) {
			this.view.$('.form-group')
				.removeClass('has-error')
				.find('div.text-danger')
				.remove();
		}
	},

	/*
	*	Scroll to the first error
	*/
	scrollToFirstError: function() {
		if($('.has-error').length > 0) {
			$('body').scrollTop($('.has-error:first').position().top);
		}
	}
});
<|endoftext|>


<commit_before>// Global variables
var csvFields;
var map;
var zoom;
var scale = .94;
var layer;
var percent;
var fieldSelect;
var fieldsById;
var stat;
var body;
var topology;
var carto;
var geometries;
var userSessionCookie;
var userData;

/*
 * Main program instructions
 */
console.log("Running Cartograms 4 All Web App");

$(document).ready(function() {
  // if not already set, set new cookie.
  var session_id = generateSessionID(16);
  if(readCookie('userSessionCookie') === null) {
    createCookie('userSessionCookie', session_id, 10, '/');
  }
  init();
  //set default data file and topoJSON
  /*map
    .call(updateZoom)
    .call(zoom.event);
  */
});
/*
 * End of main program instructions
 */

/*
I'm noticing that Chrome is complaining a lot about undefined functions in index.js. This leads me to believe that
we don't have any way of including scripts within each other - unless I'm an idiot and something is being used that
I don't see, we need to set jQuery or ajax or something to load scripts within other script files, if we want the files
to exist separately. Since Tim's index.html just had the main logic that depends upon the script files, we need to either
include functions.js and cartogram.js in index.js, or they won't work together (I think!)
Or we could just put the main logic back in index.html, even though that's not as pretty or satisfying. -JSL

*/

//initialization of the entire map

function init() {
  // Start with default data and topo for user
  // Switch to user data when given
  if (userSessionCookie == null) {
    userSessionCookie = readCookie('userSessionCookie');
  }

  if (document.getElementById('input_csv').files[0] == null) {
    userData = DEFAULT_DATA;
  } else {
      //File object is immutable, so it does not rename to make it unique per user in js
      var csv = document.getElementById('input_csv').files[0];
     //Save user input if it is given and override the default
      if (csv != null) {
        saveCSV(csv);
        //userData = USER_DIRECTORY + csv.name;
      } else {
        //Avoid null user file
        userData = DEFAULT_DATA;
      }
      //Add local file usage to avoid async js calls that breaks map
      userData = URL.createObjectURL(csv);
  }

  console.log("Cartograms 4 All: Start init()");
  map = d3.select("#map");
  zoom = d3.behavior.zoom()
    .translate([-38, 32])
    .scale(scale)
    .scaleExtent([0.1, 20.0])
    .on("zoom", updateZoom);
  layer = map.append("g")
    .attr("id", "layer")
    .call(zoom),
    states = layer.append("g")
    .attr("id", "states")
    .selectAll("path")
    .call(zoom);

  csvFields = getCSVFields(initCartogram, userData);

  var proj = d3.geo.albersUsa(),
    rawData,
    dataById = {};

  /**
  var proj = d3.geo.conicConformal()
      .center(center)
      .clip(Angle(180))
      .scale(pScale)
      .translate(width / 2, height / 2)
      .precision(.1),
      rawData,
      dataById = {};
 **/

  carto = d3.cartogram()
    .projection(proj)
    .properties(function(d) {
      return dataById[d.id];
    })
    .value(function(d) {
      return +d.properties[field];
    });

  d3.json(DEFAULT_TOPO, function(topology) {
    this.topology = topology;
    geometries = topology.objects.states.geometries;
    d3.csv(userData, function(rawData) {
      dataById = d3.nest()
        .key(function(d) {
          return d.NAME;
        })
        .rollup(function(d) {
          return d[0];
        })
        .map(rawData);
      var features = carto.features(topology, geometries),
        path = d3.geo.path().projection(proj);

      states = states.data(features)
        .enter()
        .append("path")
        .attr("class", "state")
        .attr("id", function(d) {
          return d.properties.NAME;
        })
        .attr("fill", "#fff")
        .attr("d", path);
      states.append("title");

      // Waits until fields has been defined
      function waitForFields() {
        if (typeof someVariable !== "undefined") {
          parseHash(fieldsById);
        } else {
          setTimeout(waitForFields, 250);
        }
      }

      // Waits until fields has been defined
      function waitForTopology() {
        if (typeof someVariable !== "undefined") {
          initTopo();
        } else {
          setTimeout(topology, 250);
        }
      }
    });
  });

  console.log("Cartograms 4 All: Finished init()");
}

//initialization of the new cartogram,
//based on the csv fields passed in.
function initCartogram(csvFields) {
  fields = csvFields;
  // Data info for the cartogram
  percent = (function() {
      var fmt = d3.format(".2f");
      return function(n) {
        return fmt(n) + "%";
      };
    })(),
    fields = csvFields,
    // TODO: Make this customizable
    // NOTE: Might just have this detect if there are digits at the end of the column or beginning,
    // and if there are then use those as a year
    // TODO: Make a custom function getTimeInField() which will clear
    fieldsById = d3.nest()
    .key(function(d) {
      return d.id;
    })
    .rollup(function(d) {
      return d[0];
    })
    .map(fields),
    // TODO: Set default field to something that looks like data
    field = fields[0],
    // TODO: Allow for customization of map color
    colors = colorbrewer.RdYlBu[3]
    .reverse()
    .map(function(rgb) {
      return d3.hsl(rgb);
    });

  body = d3.select("body");
  stat = d3.select("#status");

  fieldSelect = d3.select("#field")
    .on("change", function(e) {
      field = fields[this.selectedIndex];
      location.hash = "#" + field.id;
    });

  fieldSelect.selectAll("option")
    .data(fields)
    .enter()
    .append("option")
    .attr("value", function(d) {
      return d.id;
    })
    .text(function(d) {
      return d.name;
    });

  /* TODO: Reincorporate year
  var yearSelect = d3.select("#year")
      .on("change", function(e) {
          year = years[this.selectedIndex];
          location.hash = "#" + [field.id, year].join("/");
      });

  yearSelect.selectAll("option")
      .data(years)
      .enter()
      .append("option")
      .attr("value", function(y) { return y; })
      .text(function(y) { return y; })
  */

  updateZoom();
}

window.onhashchange = function() {
  parseHash(fieldsById);
};

var deferredUpdate = (function() {
  var timeout;
  return function() {
    var args = arguments;
    clearTimeout(timeout);
    stat.text("calculating...");
    return timeout = setTimeout(function() {
      update.apply(null, arguments);
    }, 10);
  };
})();

var hashish = d3.selectAll("a.hashish")
  .datum(function() {
    return this.href;
  });
<commit_msg>Change default render view<commit_after>// Global variables
var csvFields;
var map;
var zoom;
var scale = .94;
var layer;
var percent;
var fieldSelect;
var fieldsById;
var stat;
var body;
var topology;
var carto;
var geometries;
var userSessionCookie;
var userData;

/*
 * Main program instructions
 */
console.log("Running Cartograms 4 All Web App");

$(document).ready(function() {
  // if not already set, set new cookie.
  var session_id = generateSessionID(16);
  if(readCookie('userSessionCookie') === null) {
    createCookie('userSessionCookie', session_id, 10, '/');
  }
  init();
  //set default data file and topoJSON
  /*map
    .call(updateZoom)
    .call(zoom.event);
  */
});
/*
 * End of main program instructions
 */

/*
I'm noticing that Chrome is complaining a lot about undefined functions in index.js. This leads me to believe that
we don't have any way of including scripts within each other - unless I'm an idiot and something is being used that
I don't see, we need to set jQuery or ajax or something to load scripts within other script files, if we want the files
to exist separately. Since Tim's index.html just had the main logic that depends upon the script files, we need to either
include functions.js and cartogram.js in index.js, or they won't work together (I think!)
Or we could just put the main logic back in index.html, even though that's not as pretty or satisfying. -JSL

*/

//initialization of the entire map

function init() {
  // Start with default data and topo for user
  // Switch to user data when given
  if (userSessionCookie == null) {
    userSessionCookie = readCookie('userSessionCookie');
  }

  if (document.getElementById('input_csv').files[0] == null) {
    userData = DEFAULT_DATA;
  } else {
      //File object is immutable, so it does not rename to make it unique per user in js
      var csv = document.getElementById('input_csv').files[0];
     //Save user input if it is given and override the default
      if (csv != null) {
        saveCSV(csv);
        //userData = USER_DIRECTORY + csv.name;
      } else {
        //Avoid null user file
        userData = DEFAULT_DATA;
      }
      //Add local file usage to avoid async js calls that breaks map
      userData = URL.createObjectURL(csv);
  }

  console.log("Cartograms 4 All: Start init()");
  map = d3.select("#map");
  zoom = d3.behavior.zoom()
    .translate([-38, 32])
    .scale(scale)
    .scaleExtent([0.1, 20.0])
    .on("zoom", updateZoom);
  layer = map.append("g")
    .attr("id", "layer")
    .call(zoom),
    states = layer.append("g")
    .attr("id", "states")
    .selectAll("path")
    .call(zoom);

  csvFields = getCSVFields(initCartogram, userData);

  var proj = d3.geo.albersUsa(),
    rawData,
    dataById = {};

  /**
  var proj = d3.geo.conicConformal()
      .center(center)
      .clip(Angle(180))
      .scale(pScale)
      .translate(width / 2, height / 2)
      .precision(.1),
      rawData,
      dataById = {};
 **/

  carto = d3.cartogram()
    .projection(proj)
    .properties(function(d) {
      return dataById[d.id];
    })
    .value(function(d) {
      return +d.properties[field];
    });

  d3.json(DEFAULT_TOPO, function(topology) {
    this.topology = topology;
    geometries = topology.objects.states.geometries;
    d3.csv(userData, function(rawData) {
      dataById = d3.nest()
        .key(function(d) {
          return d.NAME;
        })
        .rollup(function(d) {
          return d[0];
        })
        .map(rawData);
      var features = carto.features(topology, geometries),
        path = d3.geo.path().projection(proj);

      states = states.data(features)
        .enter()
        .append("path")
        .attr("class", "state")
        .attr("id", function(d) {
          return d.properties.NAME;
        })
        .attr("fill", "#fff")
        .attr("d", path);
      states.append("title");

      // Waits until fields has been defined
      function waitForFields() {
        if (typeof someVariable !== "undefined") {
          parseHash(fieldsById);
        } else {
          setTimeout(waitForFields, 250);
        }
      }

      // Waits until fields has been defined
      function waitForTopology() {
        if (typeof someVariable !== "undefined") {
          initTopo();
        } else {
          setTimeout(topology, 250);
        }
      }
    });
  });

  console.log("Cartograms 4 All: Finished init()");
}

//initialization of the new cartogram,
//based on the csv fields passed in.
function initCartogram(csvFields) {
  fields = csvFields;
  // Data info for the cartogram
  percent = (function() {
      var fmt = d3.format(".2f");
      return function(n) {
        return fmt(n) + "%";
      };
    })(),
    fields = csvFields,
    // TODO: Make this customizable
    // NOTE: Might just have this detect if there are digits at the end of the column or beginning,
    // and if there are then use those as a year
    // TODO: Make a custom function getTimeInField() which will clear
    fieldsById = d3.nest()
    .key(function(d) {
      return d.id;
    })
    .rollup(function(d) {
      return d[0];
    })
    .map(fields),
    // TODO: Set default field to something that looks like data
    field = fields[9],
    // TODO: Allow for customization of map color
    colors = colorbrewer.RdYlBu[3]
    .reverse()
    .map(function(rgb) {
      return d3.hsl(rgb);
    });

  body = d3.select("body");
  stat = d3.select("#status");

  fieldSelect = d3.select("#field")
    .on("change", function(e) {
      field = fields[this.selectedIndex];
      location.hash = "#" + field.id;
    });

  fieldSelect.selectAll("option")
    .data(fields)
    .enter()
    .append("option")
    .attr("value", function(d) {
      return d.id;
    })
    .text(function(d) {
      return d.name;
    });

  /* TODO: Reincorporate year
  var yearSelect = d3.select("#year")
      .on("change", function(e) {
          year = years[this.selectedIndex];
          location.hash = "#" + [field.id, year].join("/");
      });

  yearSelect.selectAll("option")
      .data(years)
      .enter()
      .append("option")
      .attr("value", function(y) { return y; })
      .text(function(y) { return y; })
  */

  updateZoom();
}

window.onhashchange = function() {
  parseHash(fieldsById);
};

var deferredUpdate = (function() {
  var timeout;
  return function() {
    var args = arguments;
    clearTimeout(timeout);
    stat.text("calculating...");
    return timeout = setTimeout(function() {
      update.apply(null, arguments);
    }, 10);
  };
})();

var hashish = d3.selectAll("a.hashish")
  .datum(function() {
    return this.href;
  });
<|endoftext|>


<commit_before>requirejs.config({
    shim: {
        // because bootstrap doesn't use AMD to declare its dependency on jquery
        "bootstrap" : { "deps" :['jquery'] }
    },
    baseUrl: '/js/lib',
    paths: {
        app: '/js/app',
    },
});

require(
    [
        'backbone',
        'app/routes',
    ],
    function(Backbone, Routes) {
        Backbone.sync = function(method, model, options) {
            if (this.urlPinned) {
                var url = this.urlPinned;
            } else {
                var url = this.urlRoot + method;  // Example: '/wsgi_service.captain_' + 'create'
            }
            console.log('Backbone sync ' + method + ' url: ' + url + ' model: ');
            console.log(model);
            // Template for a ROOMS API settings.
            var settings = {
                url: url,

                // Protorpc always sends a POST and expects JSON, it's not RESTful.
                // https://github.com/google/protorpc/blob/9c0854e147e774e574327dc12f1042167a5ace6e/protorpc/wsgi/service.py#L91
                method: "POST",
                dataType: 'json',
                contentType: "application/json",

                success: function(data, status, xhr) {
                    console.log('Backbone sync ' + method
                                + ' success: ' + JSON.stringify(data));
                    xhr.statusText = method;
                    options.success(data, method, xhr);
                }
            };

            var error = options.error;
            settings.error = function(xhr, textStatus, errorThrown) {
                console.log('Backbone sync ' + method + ' error: ' + JSON.stringify('response: ' + xhr.responseText));
                options.textStatus = textStatus;
                options.errorThrown = errorThrown;
                if (error) error.call(options.context, xhr, textStatus, errorThrown);
            };

            switch (method) {
            case 'read':
                var inputs = {"id": model.id};
                if (model.getApiInputs) {
                    inputs = model.getApiInputs();
                }
                var xhr = options.xhr = Backbone.$.ajax(_.extend(settings, {
                    data: JSON.stringify(inputs)
                }))
                break;
            case 'create':
            case 'update':
                var xhr = options.xhr = Backbone.$.ajax(_.extend(settings, {
                    data: JSON.stringify(model.attributes),
                }))
                break;
            }
            model.trigger('request', model, xhr, options);
            return xhr;
        }
        var Rooms = function() {
            var self = this;
            this.routes = new Routes(this);
            this.go();
        };
        Rooms.prototype = {
            views: {},
            models: {},
            go: function() {
                Backbone.history.start({pushState: true});
            }
        };
        window.rooms = new Rooms();
    }
);
<commit_msg>added delete<commit_after>requirejs.config({
    shim: {
        // because bootstrap doesn't use AMD to declare its dependency on jquery
        "bootstrap" : { "deps" :['jquery'] }
    },
    baseUrl: '/js/lib',
    paths: {
        app: '/js/app',
    },
});

require(
    [
        'backbone',
        'app/routes',
    ],
    function(Backbone, Routes) {
        Backbone.sync = function(method, model, options) {
            if (this.urlPinned) {
                var url = this.urlPinned;
            } else {
                var url = this.urlRoot + method;  // Example: '/wsgi_service.captain_' + 'create'
            }
            console.log('Backbone sync ' + method + ' url: ' + url + ' model: ');
            console.log(model);
            // Template for a ROOMS API settings.
            var settings = {
                url: url,

                // Protorpc always sends a POST and expects JSON, it's not RESTful.
                // https://github.com/google/protorpc/blob/9c0854e147e774e574327dc12f1042167a5ace6e/protorpc/wsgi/service.py#L91
                method: "POST",
                dataType: 'json',
                contentType: "application/json",

                success: function(data, status, xhr) {
                    console.log('Backbone sync ' + method
                                + ' success: ' + JSON.stringify(data));
                    xhr.statusText = method;
                    options.success(data, method, xhr);
                }
            };

            var error = options.error;
            settings.error = function(xhr, textStatus, errorThrown) {
                console.log('Backbone sync ' + method + ' error: ' + JSON.stringify('response: ' + xhr.responseText));
                options.textStatus = textStatus;
                options.errorThrown = errorThrown;
                if (error) error.call(options.context, xhr, textStatus, errorThrown);
            };

            switch (method) {
            case 'read':
            case 'delete':
                var inputs = {"id": model.id};
                if (model.getApiInputs) {
                    inputs = model.getApiInputs();
                }
                var xhr = options.xhr = Backbone.$.ajax(_.extend(settings, {
                    data: JSON.stringify(inputs)
                }))
                break;
            case 'create':
            case 'update':
                var xhr = options.xhr = Backbone.$.ajax(_.extend(settings, {
                    data: JSON.stringify(model.attributes),
                }))
                break;
            }
            model.trigger('request', model, xhr, options);
            return xhr;
        }
        var Rooms = function() {
            var self = this;
            this.routes = new Routes(this);
            this.go();
        };
        Rooms.prototype = {
            views: {},
            models: {},
            go: function() {
                Backbone.history.start({pushState: true});
            }
        };
        window.rooms = new Rooms();
    }
);
<|endoftext|>