<commit_before>/**
 * ErrorHandler component.
 *
 * Site Kit by Google, Copyright 2021 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 copyToClipboard from 'clipboard-copy';
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { Component, Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Icon, check, stack } from '@wordpress/icons';

/**
 * Internal dependencies
 */
import Notification from '../legacy-notifications/notification';
import Link from '../Link';
import Button from '../Button';

class ErrorHandler extends Component {
	constructor( props ) {
		super( props );

		this.state = {
			error: null,
			info: null,
			copied: false,
		};

		this.onErrorClick = this.onErrorClick.bind( this );
	}

	componentDidCatch( error, info ) {
		global.console.error( 'Caught an error:', error, info );

		this.setState( { error, info } );
	}

	onErrorClick() {
		const { error, info } = this.state;

		// Copy message with wrapping backticks for code block formatting on wp.org.
		copyToClipboard( `\`${ error?.message }\n${ info?.componentStack }\`` );

		this.setState( { copied: true } );
	}

	render() {
		const { children } = this.props;
		const { error, info, copied } = this.state;

		// If there is no caught error, render the children components normally.
		if ( ! error ) {
			return children;
		}

		const icon = <Icon
			className="mdc-button__icon"
			icon={ copied ? check : stack }
		/>;

		return (
			<Notification
				id="googlesitekit-error"
				title={ __( 'Site Kit encountered an error', 'google-site-kit' ) }
				description={ (
					<Fragment>
						<Button trailingIcon={ icon } onClick={ this.onErrorClick }>
							{ __( 'Copy error to clipboard', 'google-site-kit' ) }
						</Button>
						<Link href="https://wordpress.org/support/plugin/google-site-kit/" external>
							{ __( 'Report this problem', 'google-site-kit' ) }
						</Link>
					</Fragment>
				) }
				isDismissable={ false }
				format="small"
				type="win-error"
			>

					{ error.message }
					{ info.componentStack }

			</Notification>
		);
	}
}

ErrorHandler.propTypes = {
	/** @ignore */
	children: PropTypes.node.isRequired,
};

export default ErrorHandler;
<commit_msg>Add event tracking to ErrorHandler.<commit_after>/**
 * ErrorHandler component.
 *
 * Site Kit by Google, Copyright 2021 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 copyToClipboard from 'clipboard-copy';
import PropTypes from 'prop-types';

/**
 * WordPress dependencies
 */
import { Component, Fragment } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { Icon, check, stack } from '@wordpress/icons';

/**
 * Internal dependencies
 */
import Notification from '../legacy-notifications/notification';
import Link from '../Link';
import Button from '../Button';
import { trackEvent } from '../../util';

class ErrorHandler extends Component {
	constructor( props ) {
		super( props );

		this.state = {
			error: null,
			info: null,
			copied: false,
		};

		this.onErrorClick = this.onErrorClick.bind( this );
	}

	componentDidCatch( error, info ) {
		const { viewContext = 'unknown' } = this.props;
		global.console.error( 'Caught an error:', error, info );

		this.setState( { error, info } );

		trackEvent(
			'react_error',
			`handle_${ viewContext }_error`,
			`${ error?.message }\n${ info?.componentStack }`
		);
	}

	onErrorClick() {
		const { error, info } = this.state;

		// Copy message with wrapping backticks for code block formatting on wp.org.
		copyToClipboard( `\`${ error?.message }\n${ info?.componentStack }\`` );

		this.setState( { copied: true } );
	}

	render() {
		const { children } = this.props;
		const { error, info, copied } = this.state;

		// If there is no caught error, render the children components normally.
		if ( ! error ) {
			return children;
		}

		const icon = <Icon
			className="mdc-button__icon"
			icon={ copied ? check : stack }
		/>;

		return (
			<Notification
				id="googlesitekit-error"
				title={ __( 'Site Kit encountered an error', 'google-site-kit' ) }
				description={ (
					<Fragment>
						<Button trailingIcon={ icon } onClick={ this.onErrorClick }>
							{ __( 'Copy error to clipboard', 'google-site-kit' ) }
						</Button>
						<Link href="https://wordpress.org/support/plugin/google-site-kit/" external>
							{ __( 'Report this problem', 'google-site-kit' ) }
						</Link>
					</Fragment>
				) }
				isDismissable={ false }
				format="small"
				type="win-error"
			>

					{ error.message }
					{ info.componentStack }

			</Notification>
		);
	}
}

ErrorHandler.propTypes = {
	/** @ignore */
	children: PropTypes.node.isRequired,
};

export default ErrorHandler;
<|endoftext|>


<commit_before>angular.module('PantsParty')
    .controller('LoginCtrl', function($scope, $auth) {
        $scope.login = function() {
            $auth.login({ username: $scope.username, password: $scope.password })
                .then(function() {
                    console.log("Successful login");
                })
                .catch(function(response) {
                    console.log(response.data.message);
                });
        }

        $scope.authenticate = function(provider) {
            $auth.authenticate(provider)
                .then(function() {
                    $scope.$broadcast("loginout", "on!");
                })
                .catch(function(response) {
                    console.log(response.data ? response.data.message : response);
                });
        };
    })

    .controller('HelloCtrl', ['$scope', '$state', '$http', '$rootScope', function($scope, $state, $http, $rootScope) {
        $http.get("/api/users/me/")
            .success(function(data) {
                $scope.userData = data;
                localStorage.setItem("avatar", data.avatar);
                localStorage.setItem("username", data.display_name);
                $rootScope.$broadcast("avatarChanged");
            })

        $scope.helloForm = function(form) {
            $http.post("/api/users/me/", $scope.userData)
                .success(function(data) {
                    $scope.userData = data;
                    swal("Hooray!", "You saved your thing.  That's cool.", "success");
                    console.log(data);
                })
                .error(function(data) {
                    console.log(data);
                    alert("Hi!");
                })
            console.log($scope.userData);
        };

        $scope.available = true;
        $scope.usernameAvailable = function() {
            if(typeof($scope.userData.username) === "undefined") {
                $scope.available = false;
            } else {
                if($scope.userData.username.length <= 2)
                    $scope.available = false;
                else {
                    $http.get("/api/username/available/" + $scope.userData.username)
                        .success(function(data) {
                            $scope.available = data.available;
                        })
                }
            };
        };

        var unmet_condition = false;
        if(unmet_condition)
            $state.go("home");
    }])

    .controller('ProfileCtrl', function($scope, $auth, $http, $stateParams) {
        if($stateParams.profileId) {
            console.log($stateParams.profileId);
            $scope.isAuthenticated = function() {
                return $auth.isAuthenticated();
            }

            $http.get("/api/users/" + $stateParams.profileId)
                .success(function(data) {
                    $scope.profile = data;
                })
                .error(function(data) {
                    swal("404", "This user does not exist.", "error");
                })
        } else {
            swal("404", "This user does not exist.", "error");
        }
    })
<commit_msg>Now sets anonymous avatar to localStorage if user does not have one specified.<commit_after>angular.module('PantsParty')
    .controller('LoginCtrl', function($scope, $auth) {
        $scope.login = function() {
            $auth.login({ username: $scope.username, password: $scope.password })
                .then(function() {
                    console.log("Successful login");
                })
                .catch(function(response) {
                    console.log(response.data.message);
                });
        }

        $scope.authenticate = function(provider) {
            $auth.authenticate(provider)
                .then(function() {
                    $scope.$broadcast("loginout", "on!");
                })
                .catch(function(response) {
                    console.log(response.data ? response.data.message : response);
                });
        };
    })

    .controller('HelloCtrl', ['$scope', '$state', '$http', '$rootScope', function($scope, $state, $http, $rootScope) {
        $http.get("/api/users/me/")
            .success(function(data) {
                $scope.userData = data;
                console.log($scope.userData.avatar);
                if($scope.userData.avatar !== "")
                    localStorage.setItem("avatar", data.avatar);
                else
                    localStorage.setItem("avatar", "/static/images/anonymous.png");
                localStorage.setItem("username", data.display_name);
                $rootScope.$broadcast("avatarChanged");
            })

        $scope.helloForm = function(form) {
            $http.post("/api/users/me/", $scope.userData)
                .success(function(data) {
                    $scope.userData = data;
                    swal("Hooray!", "You saved your thing.  That's cool.", "success");
                    console.log(data);
                })
                .error(function(data) {
                    console.log(data);
                    alert("Hi!");
                })
            console.log($scope.userData);
        };

        $scope.available = true;
        $scope.usernameAvailable = function() {
            if(typeof($scope.userData.username) === "undefined") {
                $scope.available = false;
            } else {
                if($scope.userData.username.length <= 2)
                    $scope.available = false;
                else {
                    $http.get("/api/username/available/" + $scope.userData.username)
                        .success(function(data) {
                            $scope.available = data.available;
                        })
                }
            };
        };

        var unmet_condition = false;
        if(unmet_condition)
            $state.go("home");
    }])

    .controller('ProfileCtrl', function($scope, $auth, $http, $stateParams) {
        if($stateParams.profileId) {
            console.log($stateParams.profileId);
            $scope.isAuthenticated = function() {
                return $auth.isAuthenticated();
            }

            $http.get("/api/users/" + $stateParams.profileId)
                .success(function(data) {
                    $scope.profile = data;
                })
                .error(function(data) {
                    swal("404", "This user does not exist.", "error");
                })
        } else {
            swal("404", "This user does not exist.", "error");
        }
    })
<|endoftext|>


<commit_before>// include core Park class
var Park = require("../park");

var Moment = require("moment-timezone");

// load ride name data
var rawRideData = require(__dirname + "/AsterixData.js");
var rideData = {};
for (var i = 0, ride; ride = rawRideData[i++];) {
    rideData[ride.code] = ride;
}

var s_apiBase = Symbol();
var s_apiVersion = Symbol();
var s_appVersion = Symbol();

var reTime = /(\d+)h - (\d+|Minuit)(?:h?)/ig;
var reClosingTime = /(\d+)h(\d+)/;

/**
 * Implements the Asterix Park API
 * @class
 * @extends Park
 */
class AsterixPark extends Park {
    constructor(options = {}) {
        options.name = options.name || "Parc-Asterix";
        options.timezone = options.timezone || "Europe/Paris";
        options.latitude = options.latitude || 49.136041;
        options.longitude = options.longitude || 2.572768;

        // inherit from base class
        super(options);

        // API Options
        this[s_apiBase] = options.api_base || "https://www.parcasterix.fr/webservices/";
        this[s_apiVersion] = options.api_version || "1";
        this[s_appVersion] = options.app_version || "320";
    }

    // this park supports ride schedules
    get SupportsRideSchedules() {
        return true;
    }

    FetchWaitTimes() {
        return new Promise(function (resolve, reject) {
            this.HTTP({
                url: `${this[s_apiBase]}api/attentix.json`,
                data: {
                    "device": "android",
                    "version": this[s_appVersion],
                    "lang": "fr",
                    "apiversion": this[s_apiVersion]
                }
            }).then(function (waittimes) {
                // get opening hours and mark every ride as closed if the park is just actually closed
                this.GetOpeningTimes().then(function (parkTimes) {
                    var allRidesClosed = true;
                    var todaysOpeningHour;

                    var now = Moment();
                    for (var i = 0, parkTime; parkTime = parkTimes[i++];) {
                        if (parkTime.type == "Operating" && now.isBetween(parkTime.openingTime, parkTime.closingTime)) {
                            allRidesClosed = false;
                            // remember the park's opening hour so we can fill in ride opening times later
                            todaysOpeningHour = parkTime.openingTime;
                        }
                    }

                    if (!waittimes.latency || !waittimes.latency.latency) return reject("API didn't return expected format");

                    var ridetime;
                    for (i = 0, ridetime; ridetime = waittimes.latency.latency[i++];) {
                        var rideObject = this.GetRideObject({
                            id: ridetime.attractionid,
                            // ride name comes from hard-coded AsterixData.json file
                            name: (rideData[ridetime.attractionid] && rideData[ridetime.attractionid].title) ? rideData[ridetime.attractionid].title : "??",
                        });

                        // if park is closed, just mark all rides as closed
                        if (allRidesClosed) {
                            rideObject = -1;
                        } else {
                            //FYI, latency = "A L'ARRET" / "INDISPONIBLE" / "FERME" / "X" (mn)
                            if (ridetime.latency === "A L'ARRET" || ridetime.latency === "INDISPONIBLE") {
                                rideObject.WaitTime = -2;
                            } else if (ridetime.latency === "FERME") {
                                rideObject.WaitTime = -1;
                            } else {
                                rideObject.WaitTime = parseInt(ridetime.latency, 10);

                                if (ridetime.closing_time) {
                                    var resultRe = reClosingTime.exec(ridetime.closing_time);
                                    if (resultRe) {
                                        var closingMoment = Moment.tz(this.Timezone).hours(parseInt(resultRe[1])).minutes(parseInt(resultRe[2])).seconds(0);
                                        rideObject.Schedule.SetDate({
                                            openingTime: todaysOpeningHour,
                                            closingTime: closingMoment,
                                            type: "Operating"
                                        });
                                    }
                                }
                            }
                        }
                    }

                    resolve();
                }.bind(this), reject);
            }.bind(this), reject);
        }.bind(this));
    }

    FetchOpeningTimes() {
        return new Promise(function (resolve, reject) {
            this.HTTP({
                url: `${this[s_apiBase]}03/fr`,
                data: {
                    "device": "android",
                    "version": this[s_appVersion],
                    "lang": "fr",
                    "apiversion": this[s_apiVersion]
                }
            }).then(function (openingHours) {
                if (!openingHours.agenda) return reject("API didn't return expected opening hours data");

                for (var i = 0, agenda; agenda = openingHours.agenda[i++];) {
                    var date = Moment.tz(agenda.jour, "DD-MM-YYYY", this.Timezone);

                    if (agenda.type === "D") {
                        // park is closed
                        this.Schedule.SetDate({
                            date: date,
                            type: "Closed"
                        });
                    } else if (agenda.type === "A") {
                        var resultRe;
                        var firstResult = true;

                        while ((resultRe = reTime.exec(agenda.horaire)) !== null) {
                            // - Normal time
                            this.Schedule.SetDate({
                                date: date,
                                openingTime: date.clone().hours(parseInt(resultRe[1])).minutes(0).seconds(0),
                                closingTime: (resultRe[2] === "Minuit") ? date.endOf("day") : date.clone().hours(parseInt(resultRe[2])).minutes(0).seconds(0),
                                // can't send type for "special hours"
                                type: !firstResult ? null : "Operating",
                                // first result is normal hours, any further dates are special hours
                                specialHours: !firstResult
                            });

                            // mark that we've parsed one set of opening hours, assume any others are special
                            firstResult = false;
                        }
                    } else {
                        this.Log(`Unknown agenda type: ${agenda.type}`);
                        continue;
                    }
                }

                resolve();
            }.bind(this), reject);
        }.bind(this));
    }
}

// export the class
module.exports = AsterixPark;<commit_msg>[!] Fix unknown agendas not being parsed into calendar * These agendas are fine and expected<commit_after>// include core Park class
var Park = require("../park");

var Moment = require("moment-timezone");

// load ride name data
var rawRideData = require(__dirname + "/AsterixData.js");
var rideData = {};
for (var i = 0, ride; ride = rawRideData[i++];) {
    rideData[ride.code] = ride;
}

var s_apiBase = Symbol();
var s_apiVersion = Symbol();
var s_appVersion = Symbol();

var reTime = /(\d+)h - (\d+|Minuit)(?:h?)/ig;
var reClosingTime = /(\d+)h(\d+)/;

/**
 * Implements the Asterix Park API
 * @class
 * @extends Park
 */
class AsterixPark extends Park {
    constructor(options = {}) {
        options.name = options.name || "Parc-Asterix";
        options.timezone = options.timezone || "Europe/Paris";
        options.latitude = options.latitude || 49.136041;
        options.longitude = options.longitude || 2.572768;

        // inherit from base class
        super(options);

        // API Options
        this[s_apiBase] = options.api_base || "https://www.parcasterix.fr/webservices/";
        this[s_apiVersion] = options.api_version || "1";
        this[s_appVersion] = options.app_version || "320";
    }

    // this park supports ride schedules
    get SupportsRideSchedules() {
        return true;
    }

    FetchWaitTimes() {
        return new Promise(function(resolve, reject) {
            this.HTTP({
                url: `${this[s_apiBase]}api/attentix.json`,
                data: {
                    "device": "android",
                    "version": this[s_appVersion],
                    "lang": "fr",
                    "apiversion": this[s_apiVersion]
                }
            }).then(function(waittimes) {
                // get opening hours and mark every ride as closed if the park is just actually closed
                this.GetOpeningTimes().then(function(parkTimes) {
                    var allRidesClosed = true;
                    var todaysOpeningHour;

                    var now = Moment();
                    for (var i = 0, parkTime; parkTime = parkTimes[i++];) {
                        if (parkTime.type == "Operating" && now.isBetween(parkTime.openingTime, parkTime.closingTime)) {
                            allRidesClosed = false;
                            // remember the park's opening hour so we can fill in ride opening times later
                            todaysOpeningHour = parkTime.openingTime;
                        }
                    }

                    if (!waittimes.latency || !waittimes.latency.latency) return reject("API didn't return expected format");

                    var ridetime;
                    for (i = 0, ridetime; ridetime = waittimes.latency.latency[i++];) {
                        var rideObject = this.GetRideObject({
                            id: ridetime.attractionid,
                            // ride name comes from hard-coded AsterixData.json file
                            name: (rideData[ridetime.attractionid] && rideData[ridetime.attractionid].title) ? rideData[ridetime.attractionid].title : "??",
                        });

                        // if park is closed, just mark all rides as closed
                        if (allRidesClosed) {
                            rideObject = -1;
                        } else {
                            //FYI, latency = "A L'ARRET" / "INDISPONIBLE" / "FERME" / "X" (mn)
                            if (ridetime.latency === "A L'ARRET" || ridetime.latency === "INDISPONIBLE") {
                                rideObject.WaitTime = -2;
                            } else if (ridetime.latency === "FERME") {
                                rideObject.WaitTime = -1;
                            } else {
                                rideObject.WaitTime = parseInt(ridetime.latency, 10);

                                if (ridetime.closing_time) {
                                    var resultRe = reClosingTime.exec(ridetime.closing_time);
                                    if (resultRe) {
                                        var closingMoment = Moment.tz(this.Timezone).hours(parseInt(resultRe[1])).minutes(parseInt(resultRe[2])).seconds(0);
                                        rideObject.Schedule.SetDate({
                                            openingTime: todaysOpeningHour,
                                            closingTime: closingMoment,
                                            type: "Operating"
                                        });
                                    }
                                }
                            }
                        }
                    }

                    resolve();
                }.bind(this), reject);
            }.bind(this), reject);
        }.bind(this));
    }

    FetchOpeningTimes() {
        return new Promise(function(resolve, reject) {
            this.HTTP({
                url: `${this[s_apiBase]}03/fr`,
                data: {
                    "device": "android",
                    "version": this[s_appVersion],
                    "lang": "fr",
                    "apiversion": this[s_apiVersion]
                }
            }).then(function(openingHours) {
                if (!openingHours.agenda) return reject("API didn't return expected opening hours data");

                for (var i = 0, agenda; agenda = openingHours.agenda[i++];) {
                    var date = Moment.tz(agenda.jour, "DD-MM-YYYY", this.Timezone);

                    if (agenda.type === "D") {
                        // park is closed
                        this.Schedule.SetDate({
                            date: date,
                            type: "Closed"
                        });
                    } else {
                        var resultRe;
                        var firstResult = true;

                        while ((resultRe = reTime.exec(agenda.horaire)) !== null) {
                            // - Normal time
                            this.Schedule.SetDate({
                                date: date,
                                openingTime: date.clone().hours(parseInt(resultRe[1])).minutes(0).seconds(0),
                                closingTime: (resultRe[2] === "Minuit") ? date.endOf("day") : date.clone().hours(parseInt(resultRe[2])).minutes(0).seconds(0),
                                // can't send type for "special hours"
                                type: !firstResult ? null : "Operating",
                                // first result is normal hours, any further dates are special hours
                                specialHours: !firstResult
                            });

                            // mark that we've parsed one set of opening hours, assume any others are special
                            firstResult = false;
                        }
                    }
                }

                resolve();
            }.bind(this), reject);
        }.bind(this));
    }
}

// export the class
module.exports = AsterixPark;<|endoftext|>


<commit_before>const express = require('express');
const path = require('path');
const favicon = require('serve-favicon');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const debug = require('debug')('app-ui:server');
const http = require('http');
const config = require('./config');
const logger = require('./logger');
const stream = require('stream');
const fs = require('fs');
const checkTables = require('./database/createTables');

const app = express();
const server = http.createServer(app);
const io = require('socket.io')(server);

app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json());

// view engine setup
app.set('views', path.join(__dirname, '../', 'views'));

app.engine('html', function (filePath, options, callback) {
  fs.readFile(filePath, function (err, content) {
    if (err) { return callback(err);}

    return callback(null, content.toString());
  });
});
app.set('view engine', 'html');

app.use(favicon(path.join(__dirname, '../..', 'public', 'icon.png')));
app.use(morgan('dev', {
  stream: new stream.Writable({
    write(chunk, encoding, next) {
      logger.info(chunk.toString('utf8').trim());

      next();
    }
  })
}));

app.use(cookieParser());
app.use(express.static(path.join(__dirname, '../..', 'public')));

app.use(function (req, res, next) {
  // Website you wish to allow to connect
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
  // Request methods you wish to allow
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
  // Request headers you wish to allow
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
  // Set to true if you need the website to include cookies in the requests sent
  // to the API (e.g. in case you use sessions)
  res.setHeader('Access-Control-Allow-Credentials', true);
  // Pass to next layer of middleware
  next();
});

app.use('/', require('./routes/databaseRoutes/sockets')(io));
app.use('/layout', require('./routes/databaseRoutes/REST'));
app.use('/', require('./routes/'));

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  let err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function (err, req, res, next) {
    res.status(err.status || 500);
    res.render('error');
  });
}

// production error handler
// no stacktraces leaked to user
// error page handler
app.use(function (err, req, res, next) {
  res.status(err.status || 500);
  res.render('error');
});

let port = normalizePort(config.PORT);

app.set('port', port);

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

function normalizePort(val) {
  let port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  let bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      logger.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      logger.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

function onListening() {
  let addr = server.address();
  let bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

// Create database instance if one does not already exist.
checkTables.checkDatabase();

module.exports = app;
<commit_msg>fixed reference to rest.js in server/index.js from REST<commit_after>const express = require('express');
const path = require('path');
const favicon = require('serve-favicon');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const debug = require('debug')('app-ui:server');
const http = require('http');
const config = require('./config');
const logger = require('./logger');
const stream = require('stream');
const fs = require('fs');
const checkTables = require('./database/createTables');

const app = express();
const server = http.createServer(app);
const io = require('socket.io')(server);

app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json());

// view engine setup
app.set('views', path.join(__dirname, '../', 'views'));

app.engine('html', function (filePath, options, callback) {
  fs.readFile(filePath, function (err, content) {
    if (err) { return callback(err);}

    return callback(null, content.toString());
  });
});
app.set('view engine', 'html');

app.use(favicon(path.join(__dirname, '../..', 'public', 'icon.png')));
app.use(morgan('dev', {
  stream: new stream.Writable({
    write(chunk, encoding, next) {
      logger.info(chunk.toString('utf8').trim());

      next();
    }
  })
}));

app.use(cookieParser());
app.use(express.static(path.join(__dirname, '../..', 'public')));

app.use(function (req, res, next) {
  // Website you wish to allow to connect
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
  // Request methods you wish to allow
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
  // Request headers you wish to allow
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
  // Set to true if you need the website to include cookies in the requests sent
  // to the API (e.g. in case you use sessions)
  res.setHeader('Access-Control-Allow-Credentials', true);
  // Pass to next layer of middleware
  next();
});

app.use('/', require('./routes/databaseRoutes/sockets')(io));
app.use('/layout', require('./routes/databaseRoutes/rest'));
app.use('/', require('./routes/'));

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  let err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function (err, req, res, next) {
    res.status(err.status || 500);
    res.render('error');
  });
}

// production error handler
// no stacktraces leaked to user
// error page handler
app.use(function (err, req, res, next) {
  res.status(err.status || 500);
  res.render('error');
});

let port = normalizePort(config.PORT);

app.set('port', port);

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

function normalizePort(val) {
  let port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  let bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      logger.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      logger.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

function onListening() {
  let addr = server.address();
  let bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

// Create database instance if one does not already exist.
checkTables.checkDatabase();

module.exports = app;
<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

 /**
  * @name Component
  * @class
  */
var Component = Base.extend(Callback, /** @lends Component# */{
    _class: 'Component',
    _events: [ 'onChange', 'onClick' ],

    // DOCS: All!

    // Meta-information, by type. This is stored in _meta on the components.
    _types: {
        'boolean': {
            type: 'checkbox',
            value: 'checked'
        },

        string: {
            type: 'text'
        },

        number: {
            type: 'number',
            number: true
        },

        button: {
            type: 'button',
            tag: 'button',
            value: 'text'
        },

        text: {
            tag: 'span',
            // This will return the native textContent through DomElement.get():
            value: 'text'
        },

        slider: {
            type: 'range',
            number: true
        },

        list: {
            tag: 'select',

            setOptions: function() {
                DomElement.removeChildren(this._element);
                DomElement.create(Base.each(this._options, function(option) {
                    this.push('option', { value: option, text: option });
                }, []), this._element);
            }
        },

        color: {
            type: 'color',

            getValue: function(value) {
                // Always convert internal string representation back to a
                // paper.js color object.
                return new Color(value);
            },

            setValue: function(value) {
                // Only enfore hex values if the input field is indeed of
                // color type. This allows sketch.paperjs.org to plug in
                // the Spectrum.js library with alpha support.
                return new Color(value).toCSS(
                        DomElement.get(this._element, 'type') === 'color');
            }
        }
    },

    // Default values for internals
    _visible: true,
    _enabled: true,

    initialize: function Component(palette, parent, name, props, values, row) {
        if (!name)
            name = 'component-' + this._id;
        var value = Base.pick(values[name], props.value);
        this._id = Component._id = (Component._id || 0) + 1;
        this._palette = palette;
        this._parent = parent;
        this._name = name;
        // The row within which this component is contained. This can be a
        // shared row, e.g. when the parent component has a columns layout.
        this._row = row;
        var type = this._type = props.type in this._types
                ? props.type
                : 'options' in props
                    ? 'list'
                    : 'onClick' in props
                        ? 'button'
                        : value !== undefined
                            ? typeof value
                            : undefined,
            meta = this._meta = this._types[type] || { type: type },
            create = DomElement.create,
            element,
            className;
        if (!type) {
            // No type defined, so we're dealing with a layout component that
            // contains nested child components. See if they are to be aligned
            // as columns or rows, and lay things out accordingly.
            var columns = props.columns,
                // On the root element, we need to create the table and row even
                // if it's a columns layout.
                table = this._table = !(columns && row) && DomElement.create(
                    'table', { class: 'palettejs-pane' }, [ 'tbody' ]),
                tbody = this._tbody = table && table.firstChild,
                components = this._components = {},
                currentRow = row,
                numCells = 0;
            element = row && table;
            className = 'layout-' + (columns ? 'columns' : 'rows');
            this._numCells = 0;
            for (var key in props) {
                var component = props[key];
                if (Base.isPlainObject(component)) {
                    // Create the rows for vertical elements, as well as
                    // columns root elements.
                    if (table && !(columns && currentRow)) {
                        currentRow = DomElement.addChildren(tbody, ['tr', {
                            class: 'palettejs-row',
                            id: 'palettejs-row-' + key
                        }])[0];
                        // Set _row for the columns root element.
                        if (columns)
                            this._row = currentRow;
                    }
                    components[key] = new Component(palette, this, key,
                            component, values, currentRow);
                    // Keep track of the maximum amount of cells per row, so we
                    // can adjust colspan after.
                    numCells = Math.max(numCells, this._numCells);
                    // Do not reset cell counter if all components go to the
                    // same parent row.
                    if (!columns)
                        this._numCells = 0;
                    // Remove the entry now from the object that was provided to
                    // create the component since the leftovers will be injected
                    // into the created component through #_set() below.
                    delete props[key];
                }
            }
            this._numCells = numCells;
            // If aligning things horizontally, we need to tell the parent how
            // many cells there are all together.
            if (columns && parent)
                parent._numCells = numCells;
            Base.each(components, function(component, key) {
                // NOTE: Components with columns layout won't have their _cell
                // set.
                if (numCells > 2 && component._cell && !columns)
                    DomElement.set(component._cell, 'colspan', numCells - 1);
                // Replace each entry in values with getters/setters so we can
                // directly link the value to the component and observe change.
                if (key in values) {
                    Base.define(values, key, {
                        enumerable: true,
                        configurable: true,
                        get: function() {
                            return component.getValue();
                        },
                        set: function(val) {
                            component.setValue(val);
                        }
                    });
                }
            });
            // Add child components directly to this component, so we can access
            // it through the same path as in the components object literal that
            // was passed.
            Base.set(this, components);
        } else {
            var that = this;
            element = this._element = create(meta.tag || 'input', {
                class: 'palettejs-input',
                id: 'palettejs-input-' + name,
                type: meta.type,
                events: {
                    change: function() {
                        that.setValue(DomElement.get(this,
                                meta.value || 'value'));
                    },
                    click: function() {
                        that.fire('click');
                    }
                }
            });
            className = 'type-' + type;
        }
        if (element) {
            DomElement.addChildren(row, [
                this._labelCell = create('td', {
                    class: 'palettejs-label',
                    id: 'palettejs-label-' + name
                }),
                this._cell = create('td', {
                    class: 'palettejs-component palettejs-' + className,
                    id: 'palettejs-component-' + name
                }, [ element ])
            ]);
            // We just added two cells to the row:
            if (parent)
                parent._numCells += 2;
        }
        this._className = className;

        // Attach default 'change' even that delegates to the palette.
        this.attach('change', function(value) {
            if (!this._dontFire)
                palette.fire('change', this, this._name, value);
        });
        this._dontFire = true;
        // Now that everything is set up, copy over values fro, props.
        // NOTE: This triggers setters, which is why we set _dontFire = true,
        // and why we can only call this after everything else is set up (e.g.
        // setLabel() requires this._labelCell).
        // Exclude name because it's already set, and value since we want to set
        // it after range.
        this._set(props, { name: true, value: true });
        this.setValue(value);
        // Start firing change events after we have initialized.
        this._dontFire = false;
        this._defaultValue = this._value;
    },

    getType: function() {
        return this._type;
    },

    getName: function() {
        return this._name;
    },

    getElement: function() {
        return this._element;
    },

    getTitle: function() {
        return this._title;
    },

    setTitle: function(title) {
        this._title = title;
        if (this._tbody) {
            var node = this._titleNode;
            if (!node && title) {
                // Create a caption tag, and nest the title in a span inside,
                // so we can offer some more flexibility with CSS on it.
                node = this._titleNode = DomElement.insertBefore(this._tbody, [
                        'caption', [ 'span' ],
                    ]).firstChild;
            } else if (node && !title) {
                DomElement.remove(node);
            }
            DomElement.set(node, 'text', title);
        }
    },

    getPalette: function() {
        return this._palette;
    },

    getParent: function() {
        return this._parent;
    },

    getValue: function() {
        var value = this._value,
            getValue = this._meta.getValue;
        return getValue ? getValue.call(this, value) : value;
    },

    setValue: function(value) {
        if (this._components)
            return;
        var meta = this._meta,
            key = meta.value || 'value',
            setValue = meta.setValue;
        if (setValue)
            value = setValue.call(this, value);
        // If setValue doesn't return a value, then we assume it took care of
        // the setting by itself.
        if (value !== undefined) {
            DomElement.set(this._element, key, value);
            // Read back and convert from input again to make sure we're in sync
            value = DomElement.get(this._element, key);
        }
        if (meta.number)
            value = parseFloat(value, 10);
        if (this._value !== value) {
            this._value = value;
            if (!this._dontFire)
                this.fire('change', this.getValue());
        }
    },

    // Setup #text as an alias to #value, for better semantics when creating
    // buttons.
    getText: '#getValue',
    setText: '#setValue',

    _setLabel: function(label, nodeName, parent) {
        if (parent) {
            this[nodeName] = DomElement.set(
                    this[nodeName] || DomElement.addChild(parent,
                        ['label', { 'for': 'palettejs-input-' + this._name }]),
                    'text', label);
        }
    },

    getLabel: function() {
        return this._label;
    },

    setLabel: function(label) {
        this._label = label;
        this._setLabel(label, '_labelNode', this._labelCell);
    },

    getSuffix: function() {
        return this._suffix;
    },

    setSuffix: function(suffix) {
        this._suffix = suffix;
        this._setLabel(suffix, '_suffixNode', this._cell);
    },

    getOptions: function() {
        return this._options;
    },

    setOptions: function(options) {
        this._options = options;
        var setOptions = this._meta.setOptions;
        if (setOptions)
            setOptions.call(this);
    },

    isVisible: function() {
        return this._visible;
    },

    setVisible: function(visible) {
        // NOTE: Only set the visibility of the whole row if this is a row item,
        // in which case this._cell is not defined.
        DomElement.toggleClass(this._cell || this._row, 'hidden', !visible);
        DomElement.toggleClass(this._labelCell, 'hidden', !visible);
        this._visible = !!visible;
    },

    isEnabled: function() {
        return this._enabled;
    },

    setEnabled: function(enabled, _fromParent) {
        if (_fromParent) {
            // When called from the parent component, we have to remember the
            // component's previous enabled state when disabling the palette,
            // so we can restore it when enabling the palette again.
            var prev = Base.pick(this._previousEnabled, this._enabled);
            this._previousEnabled = enabled ? undefined : prev; // clear
            enabled = enabled && prev;
        }
        DomElement.toggleClass(this._cell || this._row, 'disabled', !enabled);
        if (this._components) {
            for (var i in this._components)
                this._components[i].setEnabled(enabled, true);
        } else {
            DomElement.set(this._element, 'disabled', !enabled);
        }
        this._enabled = !!enabled;
    },

    getRange: function() {
        return [parseFloat(DomElement.get(this._element, 'min')),
                parseFloat(DomElement.get(this._element, 'max'))];
    },

    setRange: function(min, max) {
        var range = Array.isArray(min) ? min : [min, max];
        DomElement.set(this._element, { min: range[0], max: range[1] });
    },

    getMin: function() {
        return this.getRange()[0];
    },

    setMin: function(min) {
        this.setRange(min, this.getMax());
    },

    getMax: function() {
        return this.getRange()[1];
    },

    setMax: function(max) {
        this.setRange(this.getMin(), max);
    },

    getStep: function() {
        return parseFloat(DomElement.get(this._element, 'step'));
    },

    setStep: function(step) {
        DomElement.set(this._element, 'step', step);
    },

    reset: function() {
        if (this._components) {
            for (var i in this._components)
                this._components[i].reset();
        } else {
            this.setValue(this._defaultValue);
        }
    }
});
<commit_msg>Implement ruler component, and only use palettejs-input id for actual inputs that can have labels.<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

 /**
  * @name Component
  * @class
  */
var Component = Base.extend(Callback, /** @lends Component# */{
    _class: 'Component',
    _events: [ 'onChange', 'onClick' ],

    // DOCS: All!

    // Meta-information, by type. This is stored in _meta on the components.
    _types: {
        'boolean': {
            type: 'checkbox',
            value: 'checked'
        },

        string: {
            type: 'text'
        },

        number: {
            type: 'number',
            number: true
        },

        button: {
            type: 'button',
            tag: 'button',
            value: 'text'
        },

        text: {
            tag: 'span',
            // This will return the native textContent through DomElement.get():
            value: 'text'
        },

        slider: {
            type: 'range',
            number: true
        },

        ruler: {
            tag: 'hr'
        },

        list: {
            tag: 'select',

            setOptions: function() {
                DomElement.removeChildren(this._element);
                DomElement.create(Base.each(this._options, function(option) {
                    this.push('option', { value: option, text: option });
                }, []), this._element);
            }
        },

        color: {
            type: 'color',

            getValue: function(value) {
                // Always convert internal string representation back to a
                // paper.js color object.
                return new Color(value);
            },

            setValue: function(value) {
                // Only enfore hex values if the input field is indeed of
                // color type. This allows sketch.paperjs.org to plug in
                // the Spectrum.js library with alpha support.
                return new Color(value).toCSS(
                        DomElement.get(this._element, 'type') === 'color');
            }
        }
    },

    // Default values for internals
    _visible: true,
    _enabled: true,

    initialize: function Component(palette, parent, name, props, values, row) {
        if (!name)
            name = 'component-' + this._id;
        var value = Base.pick(values[name], props.value);
        this._id = Component._id = (Component._id || 0) + 1;
        this._palette = palette;
        this._parent = parent;
        this._name = name;
        // The row within which this component is contained. This can be a
        // shared row, e.g. when the parent component has a columns layout.
        this._row = row;
        var type = this._type = props.type in this._types
                ? props.type
                : 'options' in props
                    ? 'list'
                    : 'onClick' in props
                        ? 'button'
                        : value !== undefined
                            ? typeof value
                            : undefined,
            meta = this._meta = this._types[type] || { type: type },
            create = DomElement.create,
            element,
            className;
        if (!type) {
            // No type defined, so we're dealing with a layout component that
            // contains nested child components. See if they are to be aligned
            // as columns or rows, and lay things out accordingly.
            var columns = props.columns,
                // On the root element, we need to create the table and row even
                // if it's a columns layout.
                table = this._table = !(columns && row) && DomElement.create(
                    'table', { class: 'palettejs-pane' }, [ 'tbody' ]),
                tbody = this._tbody = table && table.firstChild,
                components = this._components = {},
                currentRow = row,
                numCells = 0;
            element = row && table;
            className = 'layout-' + (columns ? 'columns' : 'rows');
            this._numCells = 0;
            for (var key in props) {
                var component = props[key];
                if (Base.isPlainObject(component)) {
                    // Create the rows for vertical elements, as well as
                    // columns root elements.
                    if (table && !(columns && currentRow)) {
                        currentRow = DomElement.addChildren(tbody, ['tr', {
                            class: 'palettejs-row',
                            id: 'palettejs-row-' + key
                        }])[0];
                        // Set _row for the columns root element.
                        if (columns)
                            this._row = currentRow;
                    }
                    components[key] = new Component(palette, this, key,
                            component, values, currentRow);
                    // Keep track of the maximum amount of cells per row, so we
                    // can adjust colspan after.
                    numCells = Math.max(numCells, this._numCells);
                    // Do not reset cell counter if all components go to the
                    // same parent row.
                    if (!columns)
                        this._numCells = 0;
                    // Remove the entry now from the object that was provided to
                    // create the component since the leftovers will be injected
                    // into the created component through #_set() below.
                    delete props[key];
                }
            }
            this._numCells = numCells;
            // If aligning things horizontally, we need to tell the parent how
            // many cells there are all together.
            if (columns && parent)
                parent._numCells = numCells;
            Base.each(components, function(component, key) {
                // NOTE: Components with columns layout won't have their _cell
                // set.
                if (numCells > 2 && component._cell && !columns)
                    DomElement.set(component._cell, 'colspan', numCells - 1);
                // Replace each entry in values with getters/setters so we can
                // directly link the value to the component and observe change.
                if (key in values) {
                    Base.define(values, key, {
                        enumerable: true,
                        configurable: true,
                        get: function() {
                            return component.getValue();
                        },
                        set: function(val) {
                            component.setValue(val);
                        }
                    });
                }
            });
            // Add child components directly to this component, so we can access
            // it through the same path as in the components object literal that
            // was passed.
            Base.set(this, components);
        } else {
            var that = this;
            element = this._element = create(meta.tag || 'input', {
                id: !meta.tag ? 'palettejs-input-' + name : null,
                type: meta.type,
                events: {
                    change: function() {
                        that.setValue(DomElement.get(this,
                                meta.value || 'value'));
                    },
                    click: function() {
                        that.fire('click');
                    }
                }
            });
            className = 'type-' + type;
        }
        if (element) {
            DomElement.addChildren(row, [
                this._labelCell = create('td', {
                    class: 'palettejs-label',
                    id: 'palettejs-label-' + name
                }),
                this._cell = create('td', {
                    class: 'palettejs-component palettejs-' + className,
                    id: 'palettejs-component-' + name
                }, [ element ])
            ]);
            // We just added two cells to the row:
            if (parent)
                parent._numCells += 2;
        }
        this._className = className;

        // Attach default 'change' even that delegates to the palette.
        this.attach('change', function(value) {
            if (!this._dontFire)
                palette.fire('change', this, this._name, value);
        });
        this._dontFire = true;
        // Now that everything is set up, copy over values fro, props.
        // NOTE: This triggers setters, which is why we set _dontFire = true,
        // and why we can only call this after everything else is set up (e.g.
        // setLabel() requires this._labelCell).
        // Exclude name because it's already set, and value since we want to set
        // it after range.
        this._set(props, { name: true, value: true });
        this.setValue(value);
        // Start firing change events after we have initialized.
        this._dontFire = false;
        this._defaultValue = this._value;
    },

    getType: function() {
        return this._type;
    },

    getName: function() {
        return this._name;
    },

    getElement: function() {
        return this._element;
    },

    getTitle: function() {
        return this._title;
    },

    setTitle: function(title) {
        this._title = title;
        if (this._tbody) {
            var node = this._titleNode;
            if (!node && title) {
                // Create a caption tag, and nest the title in a span inside,
                // so we can offer some more flexibility with CSS on it.
                node = this._titleNode = DomElement.insertBefore(this._tbody, [
                        'caption', [ 'span' ],
                    ]).firstChild;
            } else if (node && !title) {
                DomElement.remove(node);
            }
            DomElement.set(node, 'text', title);
        }
    },

    getPalette: function() {
        return this._palette;
    },

    getParent: function() {
        return this._parent;
    },

    getValue: function() {
        var value = this._value,
            getValue = this._meta.getValue;
        return getValue ? getValue.call(this, value) : value;
    },

    setValue: function(value) {
        if (this._components)
            return;
        var meta = this._meta,
            key = meta.value || 'value',
            setValue = meta.setValue;
        if (setValue)
            value = setValue.call(this, value);
        // If setValue doesn't return a value, then we assume it took care of
        // the setting by itself.
        if (value !== undefined) {
            DomElement.set(this._element, key, value);
            // Read back and convert from input again to make sure we're in sync
            value = DomElement.get(this._element, key);
        }
        if (meta.number)
            value = parseFloat(value, 10);
        if (this._value !== value) {
            this._value = value;
            if (!this._dontFire)
                this.fire('change', this.getValue());
        }
    },

    // Setup #text as an alias to #value, for better semantics when creating
    // buttons.
    getText: '#getValue',
    setText: '#setValue',

    _setLabel: function(label, nodeName, parent) {
        if (parent) {
            this[nodeName] = DomElement.set(
                    this[nodeName] || DomElement.addChild(parent, ['label', {
                        'for': !this._meta.tag
                            ? 'palettejs-input-' + this._name
                            : null
                    }]), 'text', label);
        }
    },

    getLabel: function() {
        return this._label;
    },

    setLabel: function(label) {
        this._label = label;
        this._setLabel(label, '_labelNode', this._labelCell);
    },

    getSuffix: function() {
        return this._suffix;
    },

    setSuffix: function(suffix) {
        this._suffix = suffix;
        this._setLabel(suffix, '_suffixNode', this._cell);
    },

    getOptions: function() {
        return this._options;
    },

    setOptions: function(options) {
        this._options = options;
        var setOptions = this._meta.setOptions;
        if (setOptions)
            setOptions.call(this);
    },

    isVisible: function() {
        return this._visible;
    },

    setVisible: function(visible) {
        // NOTE: Only set the visibility of the whole row if this is a row item,
        // in which case this._cell is not defined.
        DomElement.toggleClass(this._cell || this._row, 'hidden', !visible);
        DomElement.toggleClass(this._labelCell, 'hidden', !visible);
        this._visible = !!visible;
    },

    isEnabled: function() {
        return this._enabled;
    },

    setEnabled: function(enabled, _fromParent) {
        if (_fromParent) {
            // When called from the parent component, we have to remember the
            // component's previous enabled state when disabling the palette,
            // so we can restore it when enabling the palette again.
            var prev = Base.pick(this._previousEnabled, this._enabled);
            this._previousEnabled = enabled ? undefined : prev; // clear
            enabled = enabled && prev;
        }
        DomElement.toggleClass(this._cell || this._row, 'disabled', !enabled);
        if (this._components) {
            for (var i in this._components)
                this._components[i].setEnabled(enabled, true);
        } else {
            DomElement.set(this._element, 'disabled', !enabled);
        }
        this._enabled = !!enabled;
    },

    getRange: function() {
        return [parseFloat(DomElement.get(this._element, 'min')),
                parseFloat(DomElement.get(this._element, 'max'))];
    },

    setRange: function(min, max) {
        var range = Array.isArray(min) ? min : [min, max];
        DomElement.set(this._element, { min: range[0], max: range[1] });
    },

    getMin: function() {
        return this.getRange()[0];
    },

    setMin: function(min) {
        this.setRange(min, this.getMax());
    },

    getMax: function() {
        return this.getRange()[1];
    },

    setMax: function(max) {
        this.setRange(this.getMin(), max);
    },

    getStep: function() {
        return parseFloat(DomElement.get(this._element, 'step'));
    },

    setStep: function(step) {
        DomElement.set(this._element, 'step', step);
    },

    reset: function() {
        if (this._components) {
            for (var i in this._components)
                this._components[i].reset();
        } else {
            this.setValue(this._defaultValue);
        }
    }
});
<|endoftext|>


<commit_before>/* eslint-disable no-console */
/* eslint-disable func-names */
/* eslint-disable arrow-parens */
import Koa from 'koa';
import IO from 'koa-socket';
import send from 'koa-send';
import path from 'path';
import chalk from 'chalk'
import moment from 'moment'

const app = Koa();
const io = new IO();

const g = chalk.green.bind(chalk);
const b = chalk.blue.bind(chalk);
const gr = chalk.grey.bind(chalk);
const r = chalk.red.bind(chalk);
const y = chalk.yellow.bind(chalk);

const port = process.env.PORT || 3000

const d = () => y(`[${moment().format('HH:mm:ss')}]`)

app.use(function* () {
  yield send(this, this.path,
    { root: path.join(__dirname, '../../dist/index.html') });
})
io.attach(app);

io.on('connection', ctx => {
  const ip = ctx.socket.handshake.headers['x-forwarded-for'] || ctx.socket.handshake.address.address;
  console.log(d() + b(' Connection: ') + r('New user connected'), gr(ctx.socket.id), gr(ip));
});

let usernames = [];
io.on('disconnect', ctx => {
  const { username } = ctx.socket;
  if (username) {
    console.log(`[server] disconnected: ${username}`);
    usernames = usernames.filter(u => u !== username)
  }
});

io.on('login', (ctx, { username }) => {
  console.log(`[server] login: ${username}`);
  usernames.push(username);
  console.log('this is usernames array: ', usernames);
  ctx.socket.username = username;
  ctx.socket.usernames = usernames;

  io.broadcast('users.login', { username, usernames });
  console.log('users.login', username, usernames);
});

io.on('logout', ctx => {
  const { username } = ctx.socket;
  if (username) {
    console.log(`[server] logout: ${username}`);
    usernames = usernames.filter(u => u !== username)
    delete ctx.socket['username'];

    io.broadcast('users.logout', { username });
  }
});

let messages = [];
io.on('message', (ctx, { text }) => {
  console.log(`[server] message: ${text}`);
  const message = {
    id: messages.length,
    text,
    username: ctx.socket.username,
  };
  messages.push(message);

  io.broadcast('messages.new', { message });
});

const env = process.env.NODE_ENV || 'dev'

app.listen(port, () => {
  console.log(`Server started on port ${r(port)}, environement: ${b(env)}`);
});
<commit_msg>feat(server/index.js): modify logging<commit_after>/* eslint-disable no-console */
/* eslint-disable func-names */
/* eslint-disable arrow-parens */
import Koa from 'koa';
import IO from 'koa-socket';
import send from 'koa-send';
import path from 'path';
import chalk from 'chalk'
import moment from 'moment'

const app = Koa();
const io = new IO();

const log = console.log;
const g = chalk.green.bind(chalk);
const b = chalk.blue.bind(chalk);
const gr = chalk.grey.bind(chalk);
const r = chalk.red.bind(chalk);
const y = chalk.yellow.bind(chalk);

const port = process.env.PORT || 3000

const d = () => y(`[${moment().format('HH:mm:ss')}]`)

app.use(function* () {
  yield send(this, this.path,
    { root: path.join(__dirname, '../../dist/index.html') });
})
io.attach(app);

io.on('connection', ctx => {
  const ip = ctx.socket.handshake.headers['x-forwarded-for'] || ctx.socket.handshake.address.address;
  log(d() + b(' Connection: ') + r('New user connected'), gr(ctx.socket.id), gr(ip));
});

let usernames = [];
io.on('disconnect', ctx => {
  const { username } = ctx.socket;
  if (username) {
    log(`[server] disconnected: ${username}`);
    usernames = usernames.filter(u => u !== username)
  }
});

io.on('login', (ctx, { username }) => {
  log(`[server] login: ${username}`);
  usernames.push(username);
  log('this is usernames array: ', usernames);
  ctx.socket.username = username;
  ctx.socket.usernames = usernames;

  io.broadcast('users.login', { username, usernames });
  log('users.login', username, usernames);
});

io.on('logout', ctx => {
  const { username } = ctx.socket;
  if (username) {
    log(`[server] logout: ${username}`);
    usernames = usernames.filter(u => u !== username)
    delete ctx.socket['username'];

    io.broadcast('users.logout', { username });
  }
});

let messages = [];
io.on('message', (ctx, { text }) => {
  log(`[server] message: ${text}`);
  const message = {
    id: messages.length,
    text,
    username: ctx.socket.username,
  };
  messages.push(message);

  io.broadcast('messages.new', { message });
});

const env = process.env.NODE_ENV || 'dev'

app.listen(port, () => {
  log(`Server started on port ${r(port)}, environement: ${b(env)}`);
});
<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

 /**
  * @name Component
  * @class
  */
var Component = Base.extend(Callback, /** @lends Component# */{
    _class: 'Component',
    _events: [ 'onChange', 'onClick' ],

    // DOCS: All!

    // Meta-information, by type. This is stored in _meta on the components.
    _types: {
        'boolean': {
            type: 'checkbox',
            value: 'checked'
        },

        string: {
            type: 'text'
        },

        number: {
            type: 'number',
            number: true
        },

        button: {
            type: 'button'
        },

        text: {
            tag: 'div',
            // This will return the native textContent through DomElement.get():
            value: 'text'
        },

        slider: {
            type: 'range',
            number: true
        },

        list: {
            tag: 'select',

            setOptions: function() {
                DomElement.removeChildren(this._input);
                DomElement.create(Base.each(this._options, function(option) {
                    this.push('option', { value: option, text: option });
                }, []), this._input);
            }
        },

        color: {
            type: 'color',

            getValue: function(value) {
                // Always convert internal string representation back to a
                // paper.js color object.
                return new Color(value);
            },

            setValue: function(value) {
                // Only enfore hex values if the input field is indeed of
                // color type. This allows sketch.paperjs.org to plug in
                // the Spectrum.js library with alpha support.
                return new Color(value).toCSS(
                        DomElement.get(this._input, 'type') === 'color');
            }
        },

        row: {},
        pane: {}
    },

    // Default values for internals
    _visible: true,
    _enabled: true,

    initialize: function Component(pane, name, props, values, row, parent) {
        if (!name)
            name = 'component-' + this._id;
        var value = Base.pick(values[name], props.value);
        this._id = Component._id = (Component._id || 0) + 1;
        this._pane = pane;
        this._name = name;
        this._row = row;
        this._parent = parent; // The parent component, if any.
        this._nested = !!parent;
        if (!parent || parent._type !== 'row')
            DomElement.set(row, 'id', 'palettejs-row-' + name);
        var type = this._type = props.type in this._types
                ? props.type
                : 'options' in props
                    ? 'list'
                    : 'onClick' in props
                        ? 'button'
                        : typeof value,
            meta = this._meta = this._types[type] || { type: type },
            that = this,
            create = DomElement.create,
            element = null,
            isRow = type === 'row',
            isPane = type === 'pane';
        if (isRow || isPane) {
            var childPane = this._childPane = new Pane(props, values, this,
                    isRow && row);
            if (isRow) {
                pane._numCells = childPane._numCells;
            } else { // isPane
                element = childPane._table;
            }
        } else {
            element = this._input = create(meta.tag || 'input', {
                class: 'palettejs-input',
                id: 'palettejs-input-' + name,
                type: meta.type,
                events: {
                    change: function() {
                        that.setValue(DomElement.get(this,
                                meta.value || 'value'));
                    },
                    click: function() {
                        that.fire('click');
                    }
                }
            });
        }
        if (element) {
            DomElement.addChildren(row, [
                this._labelCell = create('td', {
                    class: 'palettejs-label',
                    id: 'palettejs-label-' + name
                }),
                this._cell = create('td', {
                    class: 'palettejs-component palettejs-type-' + type,
                    id: 'palettejs-component-' + name
                }, [ element ])
            ]);
            // We just added two cells to the row:
            pane._numCells += 2;
        }

        // Attach default 'change' even that delegates to palette
        this.attach('change', function(value) {
            if (!this._dontFire)
                pane.fire('change', this, this._name, value);
        });
        this._dontFire = true;
        // Now that everything is set up, copy over values fro, props.
        // NOTE: This triggers setters, which is why we set _dontFire = true,
        // and why we can only call this after everything else is set up (e.g.
        // setLabel() requires this._labelCell).
        // Exclude name because it's already set, and value since we want to set
        // it after range.
        this._set(props, { name: true, value: true });
        this.setValue(value);
        // Start firing change events after we have initialized.
        this._dontFire = false;
        //  Store link to component in the pane's components object.
        pane._components[name] = this;
        values[name] = this._defaultValue = this._value;
    },

    getType: function() {
        return this._type;
    },

    getName: function() {
        return this._name;
    },

    _setLabel: function(label, nodeName, parent) {
        if (parent) {
            this[nodeName] = DomElement.set(this[nodeName]
                    || parent.appendChild(DomElement.create('label',
                        { 'for': 'palettejs-input-' + this._name })),
                    'text', label);
        }
    },

    getLabel: function() {
        return this._label;
    },

    setLabel: function(label) {
        this._label = label;
        this._setLabel(label, '_labelNode', this._labelCell);
    },

    getSuffix: function() {
        return this._suffix;
    },

    setSuffix: function(suffix) {
        this._suffix = suffix;
        this._setLabel(suffix, '_suffixNode', this._cell);
    },

    getOptions: function() {
        return this._options;
    },

    setOptions: function(options) {
        this._options = options;
        var setOptions = this._meta.setOptions;
        if (setOptions)
            setOptions.call(this);
    },

    getValue: function() {
        var value = this._value,
            getValue = this._meta.getValue;
        return getValue ? getValue.call(this, value) : value;
    },

    setValue: function(value) {
        if (this._childPane)
            return;
        var meta = this._meta,
            key = meta.value || 'value',
            setValue = meta.setValue;
        if (setValue)
            value = setValue.call(this, value);
        DomElement.set(this._input, key, value);
        // Read back and convert from input again, to make sure we're in sync
        value = DomElement.get(this._input, key);
        if (meta.number)
            value = parseFloat(value, 10);
        if (this._value !== value) {
            this._value = value;
            if (!this._dontFire)
                this.fire('change', this.getValue());
        }
    },

    getVisible: function() {
        return this._visible;
    },

    setVisible: function(visible) {
        // NOTE: Only set the visibility of the whole row if this is a row item,
        // in which case this._input is not defined.
        DomElement.toggleClass(this._cell || this._row, 'hidden', !visible);
        DomElement.toggleClass(this._labelCell, 'hidden', !visible);
        this._visible = !!visible;
    },

    getEnabled: function() {
        return this._enabled;
    },

    setEnabled: function(enabled, _fromPalette) {
        if (_fromPalette) {
            // When called from Palette#setEnabled, we have to remember the
            // component's previous enabled state when disabling the palette,
            // so we can restore it when enabling the palette again.
            var prev = Base.pick(this._previousEnabled, this._enabled);
            this._previousEnabled = enabled ? undefined : prev; // clear
            enabled = enabled && prev;
        }
        if (this._input) {
            DomElement.set(this._input, 'disabled', !enabled);
        } else if (this._childPane) {
            this._childPane.setEnabled(enabled);
        }
        this._enabled = !!enabled;
    },

    getRange: function() {
        return [parseFloat(DomElement.get(this._input, 'min')),
                parseFloat(DomElement.get(this._input, 'max'))];
    },

    setRange: function(min, max) {
        var range = Array.isArray(min) ? min : [min, max];
        DomElement.set(this._input, { min: range[0], max: range[1] });
    },

    getMin: function() {
        return this.getRange()[0];
    },

    setMin: function(min) {
        this.setRange(min, this.getMax());
    },

    getMax: function() {
        return this.getRange()[1];
    },

    setMax: function(max) {
        this.setRange(this.getMin(), max);
    },

    getStep: function() {
        return parseFloat(DomElement.get(this._input, 'step'));
    },

    setStep: function(step) {
        DomElement.set(this._input, 'step', step);
    },

    reset: function() {
        if (this._childPane) {
            this._childPane.reset();
        } else {
            this.setValue(this._defaultValue);
        }
    }
});
<commit_msg>Expose child components.<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

 /**
  * @name Component
  * @class
  */
var Component = Base.extend(Callback, /** @lends Component# */{
    _class: 'Component',
    _events: [ 'onChange', 'onClick' ],

    // DOCS: All!

    // Meta-information, by type. This is stored in _meta on the components.
    _types: {
        'boolean': {
            type: 'checkbox',
            value: 'checked'
        },

        string: {
            type: 'text'
        },

        number: {
            type: 'number',
            number: true
        },

        button: {
            type: 'button'
        },

        text: {
            tag: 'div',
            // This will return the native textContent through DomElement.get():
            value: 'text'
        },

        slider: {
            type: 'range',
            number: true
        },

        list: {
            tag: 'select',

            setOptions: function() {
                DomElement.removeChildren(this._input);
                DomElement.create(Base.each(this._options, function(option) {
                    this.push('option', { value: option, text: option });
                }, []), this._input);
            }
        },

        color: {
            type: 'color',

            getValue: function(value) {
                // Always convert internal string representation back to a
                // paper.js color object.
                return new Color(value);
            },

            setValue: function(value) {
                // Only enfore hex values if the input field is indeed of
                // color type. This allows sketch.paperjs.org to plug in
                // the Spectrum.js library with alpha support.
                return new Color(value).toCSS(
                        DomElement.get(this._input, 'type') === 'color');
            }
        },

        row: {},
        pane: {}
    },

    // Default values for internals
    _visible: true,
    _enabled: true,

    initialize: function Component(pane, name, props, values, row, parent) {
        if (!name)
            name = 'component-' + this._id;
        var value = Base.pick(values[name], props.value);
        this._id = Component._id = (Component._id || 0) + 1;
        this._pane = pane;
        this._name = name;
        this._row = row;
        this._parent = parent; // The parent component, if any.
        this._nested = !!parent;
        if (!parent || parent._type !== 'row')
            DomElement.set(row, 'id', 'palettejs-row-' + name);
        var type = this._type = props.type in this._types
                ? props.type
                : 'options' in props
                    ? 'list'
                    : 'onClick' in props
                        ? 'button'
                        : typeof value,
            meta = this._meta = this._types[type] || { type: type },
            that = this,
            create = DomElement.create,
            element = null,
            isRow = type === 'row',
            isPane = type === 'pane';
        if (isRow || isPane) {
            var childPane = this._childPane = new Pane(props, values, this,
                    isRow && row);
            if (isRow) {
                pane._numCells = childPane._numCells;
            } else { // isPane
                element = childPane._table;
            }
            // Add child components directly to this component, so we can access
            // it through the same path as in the components object literal that
            // was passed.
            Base.set(this, childPane._components);
        } else {
            element = this._input = create(meta.tag || 'input', {
                class: 'palettejs-input',
                id: 'palettejs-input-' + name,
                type: meta.type,
                events: {
                    change: function() {
                        that.setValue(DomElement.get(this,
                                meta.value || 'value'));
                    },
                    click: function() {
                        that.fire('click');
                    }
                }
            });
        }
        if (element) {
            DomElement.addChildren(row, [
                this._labelCell = create('td', {
                    class: 'palettejs-label',
                    id: 'palettejs-label-' + name
                }),
                this._cell = create('td', {
                    class: 'palettejs-component palettejs-type-' + type,
                    id: 'palettejs-component-' + name
                }, [ element ])
            ]);
            // We just added two cells to the row:
            pane._numCells += 2;
        }

        // Attach default 'change' even that delegates to palette
        this.attach('change', function(value) {
            if (!this._dontFire)
                pane.fire('change', this, this._name, value);
        });
        this._dontFire = true;
        // Now that everything is set up, copy over values fro, props.
        // NOTE: This triggers setters, which is why we set _dontFire = true,
        // and why we can only call this after everything else is set up (e.g.
        // setLabel() requires this._labelCell).
        // Exclude name because it's already set, and value since we want to set
        // it after range.
        this._set(props, { name: true, value: true });
        this.setValue(value);
        // Start firing change events after we have initialized.
        this._dontFire = false;
        //  Store link to component in the pane's components object.
        pane._components[name] = this;
        values[name] = this._defaultValue = this._value;
    },

    getType: function() {
        return this._type;
    },

    getName: function() {
        return this._name;
    },

    _setLabel: function(label, nodeName, parent) {
        if (parent) {
            this[nodeName] = DomElement.set(this[nodeName]
                    || parent.appendChild(DomElement.create('label',
                        { 'for': 'palettejs-input-' + this._name })),
                    'text', label);
        }
    },

    getLabel: function() {
        return this._label;
    },

    setLabel: function(label) {
        this._label = label;
        this._setLabel(label, '_labelNode', this._labelCell);
    },

    getSuffix: function() {
        return this._suffix;
    },

    setSuffix: function(suffix) {
        this._suffix = suffix;
        this._setLabel(suffix, '_suffixNode', this._cell);
    },

    getOptions: function() {
        return this._options;
    },

    setOptions: function(options) {
        this._options = options;
        var setOptions = this._meta.setOptions;
        if (setOptions)
            setOptions.call(this);
    },

    getValue: function() {
        var value = this._value,
            getValue = this._meta.getValue;
        return getValue ? getValue.call(this, value) : value;
    },

    setValue: function(value) {
        if (this._childPane)
            return;
        var meta = this._meta,
            key = meta.value || 'value',
            setValue = meta.setValue;
        if (setValue)
            value = setValue.call(this, value);
        DomElement.set(this._input, key, value);
        // Read back and convert from input again, to make sure we're in sync
        value = DomElement.get(this._input, key);
        if (meta.number)
            value = parseFloat(value, 10);
        if (this._value !== value) {
            this._value = value;
            if (!this._dontFire)
                this.fire('change', this.getValue());
        }
    },

    getVisible: function() {
        return this._visible;
    },

    setVisible: function(visible) {
        // NOTE: Only set the visibility of the whole row if this is a row item,
        // in which case this._input is not defined.
        DomElement.toggleClass(this._cell || this._row, 'hidden', !visible);
        DomElement.toggleClass(this._labelCell, 'hidden', !visible);
        this._visible = !!visible;
    },

    getEnabled: function() {
        return this._enabled;
    },

    setEnabled: function(enabled, _fromPalette) {
        if (_fromPalette) {
            // When called from Palette#setEnabled, we have to remember the
            // component's previous enabled state when disabling the palette,
            // so we can restore it when enabling the palette again.
            var prev = Base.pick(this._previousEnabled, this._enabled);
            this._previousEnabled = enabled ? undefined : prev; // clear
            enabled = enabled && prev;
        }
        if (this._input) {
            DomElement.set(this._input, 'disabled', !enabled);
        } else if (this._childPane) {
            this._childPane.setEnabled(enabled);
        }
        this._enabled = !!enabled;
    },

    getRange: function() {
        return [parseFloat(DomElement.get(this._input, 'min')),
                parseFloat(DomElement.get(this._input, 'max'))];
    },

    setRange: function(min, max) {
        var range = Array.isArray(min) ? min : [min, max];
        DomElement.set(this._input, { min: range[0], max: range[1] });
    },

    getMin: function() {
        return this.getRange()[0];
    },

    setMin: function(min) {
        this.setRange(min, this.getMax());
    },

    getMax: function() {
        return this.getRange()[1];
    },

    setMax: function(max) {
        this.setRange(this.getMin(), max);
    },

    getStep: function() {
        return parseFloat(DomElement.get(this._input, 'step'));
    },

    setStep: function(step) {
        DomElement.set(this._input, 'step', step);
    },

    reset: function() {
        if (this._childPane) {
            this._childPane.reset();
        } else {
            this.setValue(this._defaultValue);
        }
    }
});
<|endoftext|>


<commit_before>// include core Park class
var Park = require("../park");

var Moment = require("moment-timezone");
var https = require("https");

var rawRideData = require("./bellewaerdeData.js");
var rideData = {};
for (var i = 0, ride; ride = rawRideData[i++];) {
    rideData[ride.code] = ride;
}

var s_apiBase = Symbol();
var s_calendarURL = Symbol();

/**
 * Implements the Bellewaerde Park API
 * @class
 * @extends Park
 */
class Bellewaerde extends Park {
    constructor(options = {}) {
        options.name = options.name || "Bellewaerde";
        options.timezone = options.timezone || "Europe/Brussels";
        options.latitude = options.latitude || 50.846996;
        options.longitude = options.longitude || 2.947948;

        // inherit from base class
        super(options);

        // API Options
        this[s_apiBase] = options.api_base || "http://bellewaer.de/realtime/api/";
        this[s_calendarURL] = options.calendarURL || "https://www.bellewaerde.be/en/api/calendar/";
    }

    FetchWaitTimes() {
        return new Promise(function(resolve, reject) {
            this.HTTP({
                url: this[s_apiBase] + "api-realtime.php"
            }).then(function(waittimes) {
                // loop over returned data
                var rideNames = {};

                for (var i = 0, ridetime; ridetime = waittimes[i++];) {
                    // Filter attractions from poi
                    if (rideData[ridetime.id] && rideData[ridetime.id].type === "Attractions") {
                        var rideObject = this.GetRideObject({
                            id: ridetime.id,
                            name: rideData[ridetime.id].name,
                        });

                        rideObject.WaitTime = Number(ridetime.wait) || 0;
                    }
                }

                resolve(rideNames);
            }.bind(this), reject);
        }.bind(this));
    }

    /**
     * Request park opening times.
     * @returns {Promise}
     */
    FetchOpeningTimes() {
        // calculate how many (and which) years we want to check
        const endYear = Moment().tz(this.Timezone).add(this.ScheduleDays, "days");
        var datePointer = Moment().tz(this.Timezone);
        const years = [];

        this.Log(`Fetching opening hours between ${datePointer.format()} and ${endYear.format()}`);

        // slide along between start and end until we go past endYear to get an array of required year combos
        while (datePointer.isSameOrBefore(endYear, "year")) {
            years.push(datePointer.format("YYYY"));
            datePointer.add(1, "year");
        }

        // loop through each year, calling FetchYearOpeningTimes
        return Promise.all(years.map((year) => {
            return this.FetchYearOpeningTimes(year);
        })).then((results) => {
            // inject results into calendar
            results.map((hours) => {
                hours.map((times) => {
                    this.Schedule.SetDate(times);
                });
            });

            return results;
        });
    }

    /**
     * Fetch park opening times for a specific year and add to park's opening times
     * @param {String} [year]
     */
    FetchYearOpeningTimes(year) {
        return new Promise(function(resolve, reject) {
            https.get(this[s_calendarURL] + year + "?_format=json", function(response) {
                var rawData = "";

                response.on("data", function(chunk) {
                    rawData += chunk;
                });

                response.on("end", function() {
                    var openingJSON = null;

                    try {
                        openingJSON = JSON.parse(rawData).opening_hours;
                    } catch (e) {
                        openingJSON = null;
                    }

                    if (openingJSON === null) {
                        return reject("API didn't return expected format");
                    }

                    var result = [];
                    Object.keys(openingJSON).forEach((key) => {
                        //FYI, status: "open" / "closed" / "soldout"
                        if (openingJSON[key].status === "open") {
                            result.push({
                                date: Moment.tz(`${key}/${year}`, "MM/DD/YYYY", this.Timezone),
                                openingTime: Moment.tz(`${key}/${year}${openingJSON[key].mo_time}`, "MM/DD/YYYYHH:mm", this.Timezone),
                                closingTime: Moment.tz(`${key}/${year}${openingJSON[key].mc_time}`, "MM/DD/YYYYHH:mm", this.Timezone),
                                type: "Operating"
                            });
                        } else {
                            result.push({
                                date: Moment.tz(`${key}/${year}`, "MM/DD/YYYY", this.Timezone),
                                type: "Closed"
                            });
                        }
                    });

                    resolve(result);
                }.bind(this));
            }.bind(this));
        }.bind(this));
    }
}

// export the class
module.exports = Bellewaerde;<commit_msg>[!] Fix generic HTTP use for opening times * Pass GET params with data value<commit_after>// include core Park class
var Park = require("../park");

var Moment = require("moment-timezone");

var rawRideData = require("./bellewaerdeData.js");
var rideData = {};
for (var i = 0, ride; ride = rawRideData[i++];) {
    rideData[ride.code] = ride;
}

var s_apiBase = Symbol();
var s_calendarURL = Symbol();

/**
 * Implements the Bellewaerde Park API
 * @class
 * @extends Park
 */
class Bellewaerde extends Park {
    constructor(options = {}) {
        options.name = options.name || "Bellewaerde";
        options.timezone = options.timezone || "Europe/Brussels";
        options.latitude = options.latitude || 50.846996;
        options.longitude = options.longitude || 2.947948;

        // inherit from base class
        super(options);

        // API Options
        this[s_apiBase] = options.api_base || "http://bellewaer.de/realtime/api/";
        this[s_calendarURL] = options.calendarURL || "https://www.bellewaerde.be/en/api/calendar/";
    }

    FetchWaitTimes() {
        return new Promise(function(resolve, reject) {
            this.HTTP({
                url: this[s_apiBase] + "api-realtime.php"
            }).then(function(waittimes) {
                // loop over returned data
                var rideNames = {};

                for (var i = 0, ridetime; ridetime = waittimes[i++];) {
                    // Filter attractions from poi
                    if (rideData[ridetime.id] && rideData[ridetime.id].type === "Attractions") {
                        var rideObject = this.GetRideObject({
                            id: ridetime.id,
                            name: rideData[ridetime.id].name,
                        });

                        rideObject.WaitTime = Number(ridetime.wait) || 0;
                    }
                }

                resolve(rideNames);
            }.bind(this), reject);
        }.bind(this));
    }

    /**
     * Request park opening times.
     * @returns {Promise}
     */
    FetchOpeningTimes() {
        // calculate how many (and which) years we want to check
        const endYear = Moment().tz(this.Timezone).add(this.ScheduleDays, "days");
        var datePointer = Moment().tz(this.Timezone);
        const years = [];

        this.Log(`Fetching opening hours between ${datePointer.format()} and ${endYear.format()}`);

        // slide along between start and end until we go past endYear to get an array of required year combos
        while (datePointer.isSameOrBefore(endYear, "year")) {
            years.push(datePointer.format("YYYY"));
            datePointer.add(1, "year");
        }

        // loop through each year, calling FetchYearOpeningTimes
        return Promise.all(years.map((year) => {
            return this.FetchYearOpeningTimes(year);
        })).then((results) => {
            // inject results into calendar
            results.map((hours) => {
                hours.map((times) => {
                    this.Schedule.SetDate(times);
                });
            });

            return results;
        });
    }

    /**
     * Fetch park opening times for a specific year and add to park's opening times
     * @param {String} [year]
     */
    FetchYearOpeningTimes(year) {
        return this.HTTP({
            url: this[s_calendarURL] + year,
            method: "GET",
            data: {
                _format: "json"
            },
            json: true
        }).then((openingJSON) => {
            if (openingJSON === null) {
                return Promise.reject("API didn't return expected format");
            }

            var result = [];
            Object.keys(openingJSON.opening_hours).forEach((key) => {
                //FYI, status: "open" / "closed" / "soldout"
                if (openingJSON.opening_hours[key].status === "open") {
                    result.push({
                        date: Moment.tz(`${key}/${year}`, "MM/DD/YYYY", this.Timezone),
                        openingTime: Moment.tz(`${key}/${year}${openingJSON.opening_hours[key].mo_time}`, "MM/DD/YYYYHH:mm", this.Timezone),
                        closingTime: Moment.tz(`${key}/${year}${openingJSON.opening_hours[key].mc_time}`, "MM/DD/YYYYHH:mm", this.Timezone),
                        type: "Operating"
                    });
                } else {
                    result.push({
                        date: Moment.tz(`${key}/${year}`, "MM/DD/YYYY", this.Timezone),
                        type: "Closed"
                    });
                }
            });

            Promise.resolve(result);
        });
    }
}

// export the class
module.exports = Bellewaerde;<|endoftext|>