<commit_before>var mongo = require('mongodb'),
  Server = mongo.Server,
  Db = mongo.Db;
var server = new Server('localhost', 27017, {
  auto_reconnect: true
});
var db = new Db('euro2012', server);
var onErr = function(err, callback) {
  db.close();
  callback(err);
};
exports.teamlist = function(gname, callback) {
  db.open(function(err, db) {
    if (!err) {
      db.collection('teams', function(err, collection) {
        if (!err) {
          collection.find({
            'GroupName': gname
          }).toArray(function(err, docs) {
            if (!err) {
              db.close();
              var intCount = docs.length;
              if (intCount > 0) {
                var strJson = "";
                for (var i = 0; i < intCount;) {
                  strJson += '{"country":"' + docs[i].country + '"}'
                  i = i + 1;
                  if (i < intCount) {
                    strJson += ',';
                  }
                }
                strJson = '{"GroupName":"' + gname + '","count":' + intCount + ',"teams":[' + strJson + "]}"
                callback("", JSON.parse(strJson));
              }
            } else {
              onErr(err, callback);
            }
          }); //end collection.find
        } else {
          onErr(err, callback);
        }
      }); //end db.collection
    } else {
      onErr(err, callback);
    }
  }); // end db.open
};
<commit_msg>Delete pull-from-mongo.js<commit_after><|endoftext|>


<commit_before>angular.module('aurora.services', [])

//Local storage services
.factory('$localstorage', ['$window', function($window) {
    return {
        set: function(key, value) {
            $window.localStorage[key] = JSON.stringify(value);
        },
        get: function(key, defaultValue) {
            var temp = $window.localStorage[key];
            if(typeof temp != 'undefined')
                return JSON.parse(temp);
            else return defaultValue;
        },
        setObject: function(key, value) {
            $window.localStorage[key] = JSON.stringify(value);
        },
        getObject: function(key) {
            return JSON.parse($window.localStorage[key] || '{}');
        }
    };
}])

//Push notification services
.factory('$push', function($http, $location, $localstorage) {
    var push      = false;
    var gcmID     = '209803454821'; // this is static for GCM
    var apnsId    = ''; //Apple iTunes App ID
    var windowsId = ''; //Windows Store ID

    var initData = {
        'android' : {
            'senderID' : gcmID
        },
        'ios' : {
            'senderID' : apnsId
        },
        'windows' : {
            'senderID' : windowsId
        }
    };

    postToPushServer = function(params, onSuccess, onFailure) {
        $http.post("http://aurora.cs.uaf.edu/push_notification/", params)
        .then(onSuccess, onFailure);
    };

    receivedNotification = function(data) {
        //Switch to notification view somehow
        alert("Notification: " + JSON.stringify(data.message));
        console.log("AURORA: " + data.message);
        console.log("AURORA: " + data.title);
        console.log("AURORA: " + data.count);
        console.log("AURORA: " + data.sound);
        console.log("AURORA: " + data.image);
        console.log("AURORA: " + data.additionalData);
    };

    receivedError = function(data) {
        console.log("AURORA: " + e.message);
    };

    notificationServiceRegistered = function(data) {
        postData = {
            "service": "gcm",
            "token": data.registrationId,
            "kpTrigger": 6
        };

        postToPushServer(postData, function(response) {
            if(response.status == 200) {
                console.log("AURORA: " + "Key has been added to push server!");
                $localstorage.set('pushToken', data.registrationId);
            }
        }, function(response) {
            console.log("AURORA: " + "Key has not been added to the push server!");
            console.log("AURORA: Failure status: " + response.status);
        });
    };

    return {
        requestTestPushNotification : function() {
            postData = {
                "test_push": true,
                "kpTrigger": "",
                "service": "gcm",
                "method": "all",
                "token": ""
            };

            postToPushServer(postData, function(response) {
                if(response.status == 200) {
                    console.log("AURORA: " + "You should receive a notification momentarily.");
                }
            }, function(response) {
                console.log("AURORA: " + "Request was denied.");
                console.log("AURORA: Failure status: " + response.status);
            });
        },
        initPushNotifications : function() {
            push = PushNotification.init(initData);

            if (push) {
                console.log("AURORA: " + "Push notification service successfully initialized.");
            }
            else {
                console.log("AURORA: " + "Push notification service NOT initialized.");
            }

            push.on('registration', notificationServiceRegistered);

            PushNotification.hasPermission(function(data) {
                if (data.isEnabled) {
                    console.log("AURORA: " + "Push notifications enabled.");
                }
                else {
                    console.log("AURORA: " + "Push notifications disabled.");
                }
            });

            push.on('notification', receivedNotification);

            push.on('error', receivedError);
        },
        unregister : function() {
            push.unregister(function() {
                console.log('AURORA: Push notifications unregistered.');
            }, function() {
                console.log('AURORA: Could not unregisted push notifications.');
            });
        },
        changeKpTrigger : function(kpTrigger) {
            var registrationId = $localstorage.get('pushToken');

            var postData = {
                'changeKpTrigger' : true,
                'token' : registrationId,
                'kpTrigger' : kpTrigger
            };

            postToPushServer(postData, function() {
                console.log("AURORA: kpTrigger changed!");
            }, function() {
                console.log("AURORA: Could not change kpTrigger.");
            });
        }
    };
})

//Geolocation services
.factory('$geolocation', function($localstorage) {
    return {
        showGeoLocationInfo : function() {
            var gps = $localstorage.get('gps', false);

            if(gps) {
                var options = {
                    enableHighAccuracy: true,
                    timeout: 15000,
                    maximumAge: 1000 * 60 * 5 //Five minutes
                };

                navigator.geolocation.getCurrentPosition(function(position) {
                    alert('Latitude: ' + position.coords.latitude + '\n' +
                        'Longitude: ' + position.coords.longitude + '\n' +
                        'Altitude: ' + position.coords.altitude + '\n' +
                        'Accuracy: ' + position.coords.accuracy + '\n' +
                        'Altitude Accuracy: ' + position.coords.altitudeAccuracy + '\n' +
                        'Heading: ' + position.coords.heading + '\n' +
                        'Speed: ' + position.coords.speed + '\n' +
                        'Timestamp: ' + position.timestamp + '\n');
                }, function(error) {
                    alert('Code: ' + error.code + '\n' +
                        'Message: ' + error.message + '\n');
                }, options);
            }
        }
    };
})

//GI API service
.factory('$kpAPI', function($http, $localstorage) {
    var latestForecast;
    var apiURL = 'http://cs472.gi.alaska.edu/kp.php?';

    loadForecastFromStorage = function() {
        latestForecast = $localstorage.getObject('forecast');

        if(typeof latestForecast == 'undefined' || Object.keys(latestForecast).length === 0)
            updateForecast();
    };

    saveForecast = function(forecast) {
        $localstorage.setObject('forecast', forecast);
    };

    updateForecast = function() {
        $http.get(apiURL + 'd=d').success(function(data) {
            var jsonData = {};
            //Convert array to JSON object

            var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
            var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

            for (var i = 0; i < data.data.length; i++) {
                jsonData['kp' + i]      = {};
                jsonData['kp' + i].kp   = data.data[i].kp;

                var dateObject = new Date(data.data[i].predicted_time.substring(0,16));
                var theDay = days[dateObject.getDay()];
                var theHour = dateObject.getHours();
                var theMin = dateObject.getMinutes();
                if(theMin < 10) { theMin = "0" + theMin; }
                var AMorPM = theHour < 12 ? "am" : "pm";
                if(theHour > 12) { theHour -= 12; }
                var theDate = dateObject.getDate();
                var theMonth = months[dateObject.getMonth()];
                //var theYear = dateObject.getFullYear();

                var timeString = theHour + ":" + theMin + AMorPM;
                var dateString = theDay + "," + theMonth + " " + theDate;// + ", " + theYear;

                jsonData['kp' + i].time = timeString;
                jsonData['kp' + i].date = dateString;

            }

            latestForecast = jsonData;
            console.log('Updated KP data.');
        }).error(function(error) {
            //Finish writing
            console.log(error);
        });

        $http.get(apiURL + 'd=n').success(function(data) {
            latestForecast.now = Math.floor(data.data[0].kp);
            saveForecast(latestForecast);
        }).error(function(error) {
            //Finish writing
            console.log(error);
        });
    };

    return {
        getForecast : function() {
            window.setInterval(updateForecast, 1000*60*15);
            updateForecast(); //TODO: Needs to be removed on production
            if(typeof latestForecast == 'undefined')
                loadForecastFromStorage();

            return latestForecast;
        }
    };
})

.factory('$background', function($kpAPI) {
	backgroundlist = [
		{
			id: 1,
			url: "../../img/background-none.jpg"
		},
		{
			id: 2,
			url: "../../img/background-low.jpg"
		},
		{
			id: 3,
			url: "../../img/background-moderate.jpg"
		},
		{
			id: 4,
			url: "../../img/background-high.jpg"
		}
	]

	return {
		getBackground : function() {
			forecast = $kpAPI.getForecast();
			var url = null;
			//forecast.now = 2;
			switch(forecast.now)
			{
				case 1:
				case 2:
				case 3:
					url = backgroundlist[0].url;
					break;
				case 4:
				case 5:
					url = backgroundlist[1].url;
					break;
				case 6:
				case 7:
					url = backgroundlist[2].url;
					break;
				case 8:
				case 9:
					url = backgroundlist[3].url;
					break;
				default:
					url = backgroundlist[0].url;
					break;
			}
			return url;
		}
	}
});

<commit_msg>Inserted missing semicolons.<commit_after>angular.module('aurora.services', [])

//Local storage services
.factory('$localstorage', ['$window', function($window) {
    return {
        set: function(key, value) {
            $window.localStorage[key] = JSON.stringify(value);
        },
        get: function(key, defaultValue) {
            var temp = $window.localStorage[key];
            if(typeof temp != 'undefined')
                return JSON.parse(temp);
            else return defaultValue;
        },
        setObject: function(key, value) {
            $window.localStorage[key] = JSON.stringify(value);
        },
        getObject: function(key) {
            return JSON.parse($window.localStorage[key] || '{}');
        }
    };
}])

//Push notification services
.factory('$push', function($http, $location, $localstorage) {
    var push      = false;
    var gcmID     = '209803454821'; // this is static for GCM
    var apnsId    = ''; //Apple iTunes App ID
    var windowsId = ''; //Windows Store ID

    var initData = {
        'android' : {
            'senderID' : gcmID
        },
        'ios' : {
            'senderID' : apnsId
        },
        'windows' : {
            'senderID' : windowsId
        }
    };

    postToPushServer = function(params, onSuccess, onFailure) {
        $http.post("http://aurora.cs.uaf.edu/push_notification/", params)
        .then(onSuccess, onFailure);
    };

    receivedNotification = function(data) {
        //Switch to notification view somehow
        alert("Notification: " + JSON.stringify(data.message));
        console.log("AURORA: " + data.message);
        console.log("AURORA: " + data.title);
        console.log("AURORA: " + data.count);
        console.log("AURORA: " + data.sound);
        console.log("AURORA: " + data.image);
        console.log("AURORA: " + data.additionalData);
    };

    receivedError = function(data) {
        console.log("AURORA: " + e.message);
    };

    notificationServiceRegistered = function(data) {
        postData = {
            "service": "gcm",
            "token": data.registrationId,
            "kpTrigger": 6
        };

        postToPushServer(postData, function(response) {
            if(response.status == 200) {
                console.log("AURORA: " + "Key has been added to push server!");
                $localstorage.set('pushToken', data.registrationId);
            }
        }, function(response) {
            console.log("AURORA: " + "Key has not been added to the push server!");
            console.log("AURORA: Failure status: " + response.status);
        });
    };

    return {
        requestTestPushNotification : function() {
            postData = {
                "test_push": true,
                "kpTrigger": "",
                "service": "gcm",
                "method": "all",
                "token": ""
            };

            postToPushServer(postData, function(response) {
                if(response.status == 200) {
                    console.log("AURORA: " + "You should receive a notification momentarily.");
                }
            }, function(response) {
                console.log("AURORA: " + "Request was denied.");
                console.log("AURORA: Failure status: " + response.status);
            });
        },
        initPushNotifications : function() {
            push = PushNotification.init(initData);

            if (push) {
                console.log("AURORA: " + "Push notification service successfully initialized.");
            }
            else {
                console.log("AURORA: " + "Push notification service NOT initialized.");
            }

            push.on('registration', notificationServiceRegistered);

            PushNotification.hasPermission(function(data) {
                if (data.isEnabled) {
                    console.log("AURORA: " + "Push notifications enabled.");
                }
                else {
                    console.log("AURORA: " + "Push notifications disabled.");
                }
            });

            push.on('notification', receivedNotification);

            push.on('error', receivedError);
        },
        unregister : function() {
            push.unregister(function() {
                console.log('AURORA: Push notifications unregistered.');
            }, function() {
                console.log('AURORA: Could not unregisted push notifications.');
            });
        },
        changeKpTrigger : function(kpTrigger) {
            var registrationId = $localstorage.get('pushToken');

            var postData = {
                'changeKpTrigger' : true,
                'token' : registrationId,
                'kpTrigger' : kpTrigger
            };

            postToPushServer(postData, function() {
                console.log("AURORA: kpTrigger changed!");
            }, function() {
                console.log("AURORA: Could not change kpTrigger.");
            });
        }
    };
})

//Geolocation services
.factory('$geolocation', function($localstorage) {
    return {
        showGeoLocationInfo : function() {
            var gps = $localstorage.get('gps', false);

            if(gps) {
                var options = {
                    enableHighAccuracy: true,
                    timeout: 15000,
                    maximumAge: 1000 * 60 * 5 //Five minutes
                };

                navigator.geolocation.getCurrentPosition(function(position) {
                    alert('Latitude: ' + position.coords.latitude + '\n' +
                        'Longitude: ' + position.coords.longitude + '\n' +
                        'Altitude: ' + position.coords.altitude + '\n' +
                        'Accuracy: ' + position.coords.accuracy + '\n' +
                        'Altitude Accuracy: ' + position.coords.altitudeAccuracy + '\n' +
                        'Heading: ' + position.coords.heading + '\n' +
                        'Speed: ' + position.coords.speed + '\n' +
                        'Timestamp: ' + position.timestamp + '\n');
                }, function(error) {
                    alert('Code: ' + error.code + '\n' +
                        'Message: ' + error.message + '\n');
                }, options);
            }
        }
    };
})

//GI API service
.factory('$kpAPI', function($http, $localstorage) {
    var latestForecast;
    var apiURL = 'http://cs472.gi.alaska.edu/kp.php?';

    loadForecastFromStorage = function() {
        latestForecast = $localstorage.getObject('forecast');

        if(typeof latestForecast == 'undefined' || Object.keys(latestForecast).length === 0)
            updateForecast();
    };

    saveForecast = function(forecast) {
        $localstorage.setObject('forecast', forecast);
    };

    updateForecast = function() {
        $http.get(apiURL + 'd=d').success(function(data) {
            var jsonData = {};
            //Convert array to JSON object

            var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
            var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

            for (var i = 0; i < data.data.length; i++) {
                jsonData['kp' + i]      = {};
                jsonData['kp' + i].kp   = data.data[i].kp;

                var dateObject = new Date(data.data[i].predicted_time.substring(0,16));
                var theDay = days[dateObject.getDay()];
                var theHour = dateObject.getHours();
                var theMin = dateObject.getMinutes();
                if(theMin < 10) { theMin = "0" + theMin; }
                var AMorPM = theHour < 12 ? "am" : "pm";
                if(theHour > 12) { theHour -= 12; }
                var theDate = dateObject.getDate();
                var theMonth = months[dateObject.getMonth()];
                //var theYear = dateObject.getFullYear();

                var timeString = theHour + ":" + theMin + AMorPM;
                var dateString = theDay + "," + theMonth + " " + theDate;// + ", " + theYear;

                jsonData['kp' + i].time = timeString;
                jsonData['kp' + i].date = dateString;

            }

            latestForecast = jsonData;
            console.log('Updated KP data.');
        }).error(function(error) {
            //Finish writing
            console.log(error);
        });

        $http.get(apiURL + 'd=n').success(function(data) {
            latestForecast.now = Math.floor(data.data[0].kp);
            saveForecast(latestForecast);
        }).error(function(error) {
            //Finish writing
            console.log(error);
        });
    };

    return {
        getForecast : function() {
            window.setInterval(updateForecast, 1000*60*15);
            updateForecast(); //TODO: Needs to be removed on production
            if(typeof latestForecast == 'undefined')
                loadForecastFromStorage();

            return latestForecast;
        }
    };
})

.factory('$background', function($kpAPI) {
	backgroundlist = [
		{
			id: 1,
			url: "../../img/background-none.jpg"
		},
		{
			id: 2,
			url: "../../img/background-low.jpg"
		},
		{
			id: 3,
			url: "../../img/background-moderate.jpg"
		},
		{
			id: 4,
			url: "../../img/background-high.jpg"
		}
	];

	return {
		getBackground : function() {
			forecast = $kpAPI.getForecast();
			var url = null;
			//forecast.now = 2;
			switch(forecast.now)
			{
				case 1:
				case 2:
				case 3:
					url = backgroundlist[0].url;
					break;
				case 4:
				case 5:
					url = backgroundlist[1].url;
					break;
				case 6:
				case 7:
					url = backgroundlist[2].url;
					break;
				case 8:
				case 9:
					url = backgroundlist[3].url;
					break;
				default:
					url = backgroundlist[0].url;
					break;
			}
			return url;
		}
	};
});

<|endoftext|>


<commit_before>/**
* This class contains the Canon of Scripture as 66 books.  It is used to control
* which books are published using this App.  The codes are used to identify the
* books of the Bible, while the names, which are in English are only used to document
* the meaning of each code.  These names are not used for display in the App.
*/
function Canon() {
	this.books = [
		{ code: 'FRT', name: 'Preface' },
    	{ code: 'GEN', name: 'Genesis' },
    	{ code: 'EXO', name: 'Exodus' },
    	{ code: 'LEV', name: 'Leviticus' },
    	{ code: 'NUM', name: 'Numbers' },
    	{ code: 'DEU', name: 'Deuteronomy' },
    	{ code: 'JOS', name: 'Joshua' },
    	{ code: 'JDG', name: 'Judges' },
    	{ code: 'RUT', name: 'Ruth' },
    	{ code: '1SA', name: '1 Samuel' },
    	{ code: '2SA', name: '2 Samuel' },
    	{ code: '1KI', name: '1 Kings' },
    	{ code: '2KI', name: '2 Kings' },
    	{ code: '1CH', name: '1 Chronicles' },
    	{ code: '2CH', name: '2 Chronicles' },
    	{ code: 'EZR', name: 'Ezra' },
    	{ code: 'NEH', name: 'Nehemiah' },
    	{ code: 'EST', name: 'Esther' },
    	{ code: 'JOB', name: 'Job' },
    	{ code: 'PSA', name: 'Psalms' },
    	{ code: 'PRO', name: 'Proverbs' },
    	{ code: 'ECC', name: 'Ecclesiastes' },
    	{ code: 'SNG', name: 'Song of Solomon' },
    	{ code: 'ISA', name: 'Isaiah' },
    	{ code: 'JER', name: 'Jeremiah' },
    	{ code: 'LAM', name: 'Lamentations' },
    	{ code: 'EZK', name: 'Ezekiel' },
    	{ code: 'DAN', name: 'Daniel' },
    	{ code: 'HOS', name: 'Hosea' },
    	{ code: 'JOL', name: 'Joel' },
    	{ code: 'AMO', name: 'Amos' },
    	{ code: 'OBA', name: 'Obadiah' },
    	{ code: 'JON', name: 'Jonah' },
    	{ code: 'MIC', name: 'Micah' },
    	{ code: 'NAM', name: 'Nahum' },
    	{ code: 'HAB', name: 'Habakkuk' },
    	{ code: 'ZEP', name: 'Zephaniah' },
    	{ code: 'HAG', name: 'Haggai' },
    	{ code: 'ZEC', name: 'Zechariah' },
    	{ code: 'MAL', name: 'Malachi' },
    	{ code: 'MAT', name: 'Matthew' },
    	{ code: 'MRK', name: 'Mark' },
    	{ code: 'LUK', name: 'Luke' },
    	{ code: 'JHN', name: 'John' },
    	{ code: 'ACT', name: 'Acts' },
    	{ code: 'ROM', name: 'Romans' },
    	{ code: '1CO', name: '1 Corinthians' },
    	{ code: '2CO', name: '2 Corinthians' },
    	{ code: 'GAL', name: 'Galatians' },
    	{ code: 'EPH', name: 'Ephesians' },
    	{ code: 'PHP', name: 'Philippians' },
    	{ code: 'COL', name: 'Colossians' },
    	{ code: '1TH', name: '1 Thessalonians' },
    	{ code: '2TH', name: '2 Thessalonians' },
    	{ code: '1TI', name: '1 Timothy' },
    	{ code: '2TI', name: '2 Timothy' },
    	{ code: 'TIT', name: 'Titus' },
    	{ code: 'PHM', name: 'Philemon' },
    	{ code: 'HEB', name: 'Hebrews' },
    	{ code: 'JAS', name: 'James' },
    	{ code: '1PE', name: '1 Peter' },
    	{ code: '2PE', name: '2 Peter' },
    	{ code: '1JN', name: '1 John' },
    	{ code: '2JN', name: '2 John' },
    	{ code: '3JN', name: '3 John' },
    	{ code: 'JUD', name: 'Jude' },
    	{ code: 'REV', name: 'Revelation' },
    	{ code: 'GLO', name: 'Glossary' } ];
}
Canon.prototype.sequenceMap = function() {
	var result = {};
	for (var i=0; i<this.books.length; i++) {
		var item = this.books[i];
		result[item.code] = i;
	}
	return(result);
};
<commit_msg>Add BAK to canon.<commit_after>/**
* This class contains the Canon of Scripture as 66 books.  It is used to control
* which books are published using this App.  The codes are used to identify the
* books of the Bible, while the names, which are in English are only used to document
* the meaning of each code.  These names are not used for display in the App.
*/
function Canon() {
	this.books = [
		{ code: 'FRT', name: 'Preface' },
    	{ code: 'GEN', name: 'Genesis' },
    	{ code: 'EXO', name: 'Exodus' },
    	{ code: 'LEV', name: 'Leviticus' },
    	{ code: 'NUM', name: 'Numbers' },
    	{ code: 'DEU', name: 'Deuteronomy' },
    	{ code: 'JOS', name: 'Joshua' },
    	{ code: 'JDG', name: 'Judges' },
    	{ code: 'RUT', name: 'Ruth' },
    	{ code: '1SA', name: '1 Samuel' },
    	{ code: '2SA', name: '2 Samuel' },
    	{ code: '1KI', name: '1 Kings' },
    	{ code: '2KI', name: '2 Kings' },
    	{ code: '1CH', name: '1 Chronicles' },
    	{ code: '2CH', name: '2 Chronicles' },
    	{ code: 'EZR', name: 'Ezra' },
    	{ code: 'NEH', name: 'Nehemiah' },
    	{ code: 'EST', name: 'Esther' },
    	{ code: 'JOB', name: 'Job' },
    	{ code: 'PSA', name: 'Psalms' },
    	{ code: 'PRO', name: 'Proverbs' },
    	{ code: 'ECC', name: 'Ecclesiastes' },
    	{ code: 'SNG', name: 'Song of Solomon' },
    	{ code: 'ISA', name: 'Isaiah' },
    	{ code: 'JER', name: 'Jeremiah' },
    	{ code: 'LAM', name: 'Lamentations' },
    	{ code: 'EZK', name: 'Ezekiel' },
    	{ code: 'DAN', name: 'Daniel' },
    	{ code: 'HOS', name: 'Hosea' },
    	{ code: 'JOL', name: 'Joel' },
    	{ code: 'AMO', name: 'Amos' },
    	{ code: 'OBA', name: 'Obadiah' },
    	{ code: 'JON', name: 'Jonah' },
    	{ code: 'MIC', name: 'Micah' },
    	{ code: 'NAM', name: 'Nahum' },
    	{ code: 'HAB', name: 'Habakkuk' },
    	{ code: 'ZEP', name: 'Zephaniah' },
    	{ code: 'HAG', name: 'Haggai' },
    	{ code: 'ZEC', name: 'Zechariah' },
    	{ code: 'MAL', name: 'Malachi' },
    	{ code: 'MAT', name: 'Matthew' },
    	{ code: 'MRK', name: 'Mark' },
    	{ code: 'LUK', name: 'Luke' },
    	{ code: 'JHN', name: 'John' },
    	{ code: 'ACT', name: 'Acts' },
    	{ code: 'ROM', name: 'Romans' },
    	{ code: '1CO', name: '1 Corinthians' },
    	{ code: '2CO', name: '2 Corinthians' },
    	{ code: 'GAL', name: 'Galatians' },
    	{ code: 'EPH', name: 'Ephesians' },
    	{ code: 'PHP', name: 'Philippians' },
    	{ code: 'COL', name: 'Colossians' },
    	{ code: '1TH', name: '1 Thessalonians' },
    	{ code: '2TH', name: '2 Thessalonians' },
    	{ code: '1TI', name: '1 Timothy' },
    	{ code: '2TI', name: '2 Timothy' },
    	{ code: 'TIT', name: 'Titus' },
    	{ code: 'PHM', name: 'Philemon' },
    	{ code: 'HEB', name: 'Hebrews' },
    	{ code: 'JAS', name: 'James' },
    	{ code: '1PE', name: '1 Peter' },
    	{ code: '2PE', name: '2 Peter' },
    	{ code: '1JN', name: '1 John' },
    	{ code: '2JN', name: '2 John' },
    	{ code: '3JN', name: '3 John' },
    	{ code: 'JUD', name: 'Jude' },
    	{ code: 'REV', name: 'Revelation' },
    	{ code: 'GLO', name: 'Glossary' },
    	{ code: 'BAK', name: 'Appendix' } ];
}
Canon.prototype.sequenceMap = function() {
	var result = {};
	for (var i=0; i<this.books.length; i++) {
		var item = this.books[i];
		result[item.code] = i;
	}
	return(result);
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import openSocket from 'socket.io-client';
import './App.css';
import AccordionGroup from './AccordionGroup';
import Settings from './PersonalSettings';

import Banner from '../components/Banner';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      webModel: {
        status: 'Robot Offline',
      },
      personalData: {},
    };
    this.sendDataToRobot = this.sendDataToRobot.bind(this);
  }

  componentDidMount() {
    // For local testing.
    // this.socket = openSocket(`http://${window.location.hostname}:8080`); // For testing
    this.socket = openSocket();

    this.socket.on('startup', (data) => {
      this.setState({
        webModel: data,
      });
    });

    this.socket.on('webModel', (data) => {
      this.setState({
        webModel: data,
      });
    });

    this.socket.on('personalData', (data) => {
      this.setState({
        personalData: data,
      });
    });

    this.socket.on('disconnect', () => {
      this.setState({
        webModel: {
          status: 'Robot Offline',
        },
      });
    });
  }

  handleBottomButton = (e) => {
    this.sendDataToRobot('getPersonalData');
    this.setState({ appFunction: e.target.id });
  };

  sendDataToRobot(value, data) {
    if (this.socket) {
      if (data !== undefined) {
        this.socket.emit(value, data);
      } else {
        this.socket.emit(value);
      }
    }
  }

  render() {
    let pageContent = <></>;
    let bottomButton = <></>;
    if (this.state.webModel.status !== 'Robot Offline') {
      if (this.state.appFunction === 'settings') {
        pageContent = <Settings personalData={this.state.personalData} />;
        bottomButton = (
          <button
            type="button"
            id="control"
            className="btn btn-primary settings-button"
            onClick={this.handleBottomButton}
          >
            Control
          </button>
        );
      } else {
        pageContent = (
          <AccordionGroup
            laptopBatteryPercentage={
              this.state.webModel.laptopBatteryPercentage
            }
            laptopFullyCharged={this.state.webModel.laptopFullyCharged}
            pluggedIn={this.state.webModel.pluggedIn}
            doorsOpen={this.state.webModel.doorsOpen}
            explorePaused={this.state.webModel.rosParameters.explorePaused}
            mapName={this.state.webModel.mapName}
            autoExplore={this.state.webModel.autoExplore}
            debugging={this.state.webModel.debugging}
            cameraOn={this.state.webModel.cameraOn}
            videoSource={this.state.webModel.videoSource}
            masterRelayOn={this.state.webModel.masterRelayOn}
            ROSisRunning={this.state.webModel.ROSisRunning}
            rosTopicItems={this.state.webModel.rosTopicItems}
            relays={this.state.webModel.relays}
            idleTimeout={this.state.webModel.idleTimeout}
            beQuiet={this.state.webModel.beQuiet}
            myCroftSaid={this.state.webModel.myCroftSaid}
            colorFollowerRunning={this.state.webModel.colorFollowerRunning}
            neoPixelsOn={this.state.webModel.neoPixelsOn}
            ROSstart={this.state.webModel.ROSstart}
            monitorACconnection={
              !this.state.webModel.rosParameters.monitorACconnection
            }
            ignoreIRSensors={this.state.webModel.rosParameters.ignoreIRSensors}
            ignoreCliffSensors={
              this.state.webModel.rosParameters.ignoreCliffSensors
            }
            ignoreFloorSensors={
              this.state.webModel.rosParameters.ignoreFloorSensors
            }
            ignoreProximity={this.state.webModel.rosParameters.ignoreProximity}
            makeMap={this.state.webModel.makeMap}
            makeMapRunning={this.state.webModel.makeMapRunning}
            mapList={this.state.webModel.mapList}
            wayPoints={this.state.webModel.wayPoints}
            unplugYourself={this.state.webModel.unplugYourself}
            scrollingStatus={this.state.webModel.scrollingStatus}
            logStreamerRunning={this.state.webModel.logStreamerRunning}
            RosService={this.RosService}
            sendDataToRobot={this.sendDataToRobot}
          />
        );
        bottomButton = (
          <button
            type="button"
            id="settings"
            className="btn btn-primary settings-button"
            onClick={this.handleBottomButton}
          >
            Settings
          </button>
        );
      }
    }
    return (

        <Banner
          haltRobot={this.state.webModel.haltRobot}
          status={this.state.webModel.status}
          behaviorStatus={this.state.webModel.behaviorStatus}
          sendDataToRobot={this.sendDataToRobot}
        />
        {pageContent}

            https://github.com/chrisl8/ArloBot

          {bottomButton}

    );
  }
}

export default App;
<commit_msg>Add some testing option lines to the web site.<commit_after>import React, { Component } from 'react';
import openSocket from 'socket.io-client';
import './App.css';
import AccordionGroup from './AccordionGroup';
import Settings from './PersonalSettings';

import Banner from '../components/Banner';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      webModel: {
        status: 'Robot Offline',
      },
      personalData: {},
    };
    this.sendDataToRobot = this.sendDataToRobot.bind(this);
  }

  componentDidMount() {
    // For local testing on the robot:
    // this.socket = openSocket(`http://${window.location.hostname}:8080`);
    // For testing running locally while connecting site to a remote robot:
    // this.socket = openSocket(`http://twoflower.local:8080`);
    // For production:
    this.socket = openSocket();

    this.socket.on('startup', (data) => {
      this.setState({
        webModel: data,
      });
    });

    this.socket.on('webModel', (data) => {
      this.setState({
        webModel: data,
      });
    });

    this.socket.on('personalData', (data) => {
      this.setState({
        personalData: data,
      });
    });

    this.socket.on('disconnect', () => {
      this.setState({
        webModel: {
          status: 'Robot Offline',
        },
      });
    });
  }

  handleBottomButton = (e) => {
    this.sendDataToRobot('getPersonalData');
    this.setState({ appFunction: e.target.id });
  };

  sendDataToRobot(value, data) {
    if (this.socket) {
      if (data !== undefined) {
        this.socket.emit(value, data);
      } else {
        this.socket.emit(value);
      }
    }
  }

  render() {
    let pageContent = <></>;
    let bottomButton = <></>;
    if (this.state.webModel.status !== 'Robot Offline') {
      if (this.state.appFunction === 'settings') {
        pageContent = <Settings personalData={this.state.personalData} />;
        bottomButton = (
          <button
            type="button"
            id="control"
            className="btn btn-primary settings-button"
            onClick={this.handleBottomButton}
          >
            Control
          </button>
        );
      } else {
        pageContent = (
          <AccordionGroup
            laptopBatteryPercentage={
              this.state.webModel.laptopBatteryPercentage
            }
            laptopFullyCharged={this.state.webModel.laptopFullyCharged}
            pluggedIn={this.state.webModel.pluggedIn}
            doorsOpen={this.state.webModel.doorsOpen}
            explorePaused={this.state.webModel.rosParameters.explorePaused}
            mapName={this.state.webModel.mapName}
            autoExplore={this.state.webModel.autoExplore}
            debugging={this.state.webModel.debugging}
            cameraOn={this.state.webModel.cameraOn}
            videoSource={this.state.webModel.videoSource}
            masterRelayOn={this.state.webModel.masterRelayOn}
            ROSisRunning={this.state.webModel.ROSisRunning}
            rosTopicItems={this.state.webModel.rosTopicItems}
            relays={this.state.webModel.relays}
            idleTimeout={this.state.webModel.idleTimeout}
            beQuiet={this.state.webModel.beQuiet}
            myCroftSaid={this.state.webModel.myCroftSaid}
            colorFollowerRunning={this.state.webModel.colorFollowerRunning}
            neoPixelsOn={this.state.webModel.neoPixelsOn}
            ROSstart={this.state.webModel.ROSstart}
            monitorACconnection={
              !this.state.webModel.rosParameters.monitorACconnection
            }
            ignoreIRSensors={this.state.webModel.rosParameters.ignoreIRSensors}
            ignoreCliffSensors={
              this.state.webModel.rosParameters.ignoreCliffSensors
            }
            ignoreFloorSensors={
              this.state.webModel.rosParameters.ignoreFloorSensors
            }
            ignoreProximity={this.state.webModel.rosParameters.ignoreProximity}
            makeMap={this.state.webModel.makeMap}
            makeMapRunning={this.state.webModel.makeMapRunning}
            mapList={this.state.webModel.mapList}
            wayPoints={this.state.webModel.wayPoints}
            unplugYourself={this.state.webModel.unplugYourself}
            scrollingStatus={this.state.webModel.scrollingStatus}
            logStreamerRunning={this.state.webModel.logStreamerRunning}
            RosService={this.RosService}
            sendDataToRobot={this.sendDataToRobot}
          />
        );
        bottomButton = (
          <button
            type="button"
            id="settings"
            className="btn btn-primary settings-button"
            onClick={this.handleBottomButton}
          >
            Settings
          </button>
        );
      }
    }
    return (

        <Banner
          haltRobot={this.state.webModel.haltRobot}
          status={this.state.webModel.status}
          behaviorStatus={this.state.webModel.behaviorStatus}
          sendDataToRobot={this.sendDataToRobot}
        />
        {pageContent}

            https://github.com/chrisl8/ArloBot

          {bottomButton}

    );
  }
}

export default App;
<|endoftext|>


<commit_before>/**
 * Created by DT314 on 2017/5/5.
 */
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Event from '../_vendors/Event';

import './TextArea.css';

export default class TextArea extends Component {
    constructor(props) {
        super();

        this.state = {
            focus: false,
            width: props.initialWidth,
            height: props.initialHeight,
            value: props.value
        };

        this.onFocus = this :: this.onFocus;
        this.onBlur = this :: this.onBlur;
        this.onChange = this :: this.onChange;
        this.resizeHandle = this :: this.resizeHandle;
        this.mouseUpHandle = this :: this.mouseUpHandle;

    }

    onFocus() {
        this.setState({
            focus: true
        }, () => {
            this.props.onFocus && this.props.onFocus();
        });
    }

    onBlur() {
        this.setState({
            focus: false
        }, () => {
            this.props.onBlur && this.props.onBlur();
        });
    }

    /**
     * 根据textArea的宽高设置state中宽高
     */
    resizeHandle(e) {
        this.setState({
            width: e.target.clientWidth + 2,
            height: e.target.clientHeight + 2
        });
    }

    /**
     * mouseUp时，若textArea的宽高右边，则resizeHandle
     */
    mouseUpHandle(e) {
        if (e.target.clientWidth + 2 !== this.state.width || e.target.clientHeight + 2 !== this.state.height) {
            this.resizeHandle(e);
        }
    }

    /**
     * input变化时，如果为autoSize，则控制高度，使之随内容变化而变化
     */
    onChange(ev) {
        const {initialHeight, maxHeight, autoSize} = this.props;
        const oEvent = ev || event;
        const {target} = oEvent;

        if (autoSize) {

            const {style} = target;

            style.height = initialHeight + 'px';
            style.overflow = 'hidden';
            if (initialHeight < target.scrollHeight + 2) {
                if (maxHeight && maxHeight > target.scrollHeight + 2) {
                    style.height = target.scrollHeight + 2 + 'px';
                } else {
                    style.height = maxHeight + 'px';
                    style.overflow = 'auto';
                }
            }
        }

        this.setState({
            value: target.value
        }, () => this.props.onChange && this.props.onChange());

    }

    componentWillReceiveProps(nextProps) {
        const {width, height, value} = this.state;

        if (nextProps.initialWidth !== width || nextProps.initialHeight !== height || nextProps.value !== value) {
            this.setState({
                width: nextProps.initialWidth,
                height: nextProps.initialHeight,
                value: nextProps.value
            });
        }
    }

    componentDidMount() {
        const {autoSize, autoFocus} = this.props;

        if (!autoSize) {
            Event.addEvent(this.refs.textarea, 'mouseup', this.mouseUpHandle);
        }

        if (autoFocus === true) {
            this.refs.textarea.focus();
        }
    }

    componentWillUnmount() {
        const {autoSize} = this.props;

        if (!autoSize) {
            Event.removeEvent(this.refs.textarea, 'mouseup', this.mouseUpHandle);
        }
    }

    render() {
        const {className, style, cols, rows, autoSize, placeholder, maxWidth} = this.props;
        const {focus, width, height, value} = this.state;

        let textStyle = {
            height: height,
            width: width,
            overflow: autoSize ? 'hidden' : 'auto',
            resize: autoSize ? 'none' : 'both',
            maxWidth: maxWidth,
            ...style
        };

        return (
            <textarea ref="textarea"
                      className={`text-area ${focus ? 'area-focus' : ''} ${className}`}
                      style={{...textStyle}}
                      cols={cols}
                      rows={rows}
                      placeholder={placeholder}
                      value={value}
                      autoComplete="off"
                      autoCorrect="off"
                      autoCapitalize="off"
                      spellCheck="false"
                      onFocus={this.onFocus}
                      onBlur={this.onBlur}
                      onChange={this.onChange}>
            </textarea>
        );
    }
};

TextArea.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The number of cols.
     */
    cols: PropTypes.number,

    /**
     * The number of rows.
     */
    rows: PropTypes.number,

    /**
     * The initial height of textArea.
     */
    initialHeight: PropTypes.number,

    /**
     * The initial height of textArea.
     */
    initialWidth: PropTypes.number,

    /**
     * The value of textArea.
     */
    value: PropTypes.string,

    /**
     * The max height of textArea.
     */
    maxHeight: PropTypes.number,

    /**
     * The max width of textArea.
     */
    maxWidth: PropTypes.number,

    /**
     * If true, the textArea will change its size by words.
     */
    autoSize: PropTypes.bool,

    /**
     * If true,the textField will autoFocus.
     */
    autoFocus: PropTypes.bool,

    /**
     * The placeholder of textArea.
     */
    placeholder: PropTypes.string,

    /**
     * When the value of textArea change, it will execute.
     */
    onChange: PropTypes.func,

    /**
     * When the textArea onBlur, it will execute.
     */
    onBlur: PropTypes.func,

    /**
     * When the textArea onFocus, it will execute.
     */
    onFocus: PropTypes.func

};

TextArea.defaultProps = {

    className: '',
    style: null,

    cols: 50,
    rows: 3,
    initialHeight: 30,
    initialWidth: 200,
    maxHeight: 100,
    maxWidth: 500,
    autoSize: true,
    autoFocus: false,
    placeholder: 'Please input something.',
    value: ''

};<commit_msg>change TextArea onChange to onInput<commit_after>/**
 * Created by DT314 on 2017/5/5.
 */
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Event from '../_vendors/Event';

import './TextArea.css';

export default class TextArea extends Component {
    constructor(props) {
        super();

        this.state = {
            focus: false,
            width: props.initialWidth,
            height: props.initialHeight,
            value: props.value
        };

        this.onFocus = this :: this.onFocus;
        this.onBlur = this :: this.onBlur;
        this.onChange = this :: this.onChange;
        this.resizeHandle = this :: this.resizeHandle;
        this.mouseUpHandle = this :: this.mouseUpHandle;

    }

    onFocus() {
        this.setState({
            focus: true
        }, () => {
            this.props.onFocus && this.props.onFocus();
        });
    }

    onBlur() {
        this.setState({
            focus: false
        }, () => {
            this.props.onBlur && this.props.onBlur();
        });
    }

    /**
     * 根据textArea的宽高设置state中宽高
     */
    resizeHandle(e) {
        this.setState({
            width: e.target.clientWidth + 2,
            height: e.target.clientHeight + 2
        });
    }

    /**
     * mouseUp时，若textArea的宽高右边，则resizeHandle
     */
    mouseUpHandle(e) {
        if (e.target.clientWidth + 2 !== this.state.width || e.target.clientHeight + 2 !== this.state.height) {
            this.resizeHandle(e);
        }
    }

    /**
     * input变化时，如果为autoSize，则控制高度，使之随内容变化而变化
     */
    onChange(ev) {
        const {initialHeight, maxHeight, autoSize} = this.props;
        const oEvent = ev || event;
        const {target} = oEvent;

        if (autoSize) {

            const {style} = target;

            style.height = initialHeight + 'px';
            style.overflow = 'hidden';
            if (initialHeight < target.scrollHeight + 2) {
                if (maxHeight && maxHeight > target.scrollHeight + 2) {
                    style.height = target.scrollHeight + 2 + 'px';
                } else {
                    style.height = maxHeight + 'px';
                    style.overflow = 'auto';
                }
            }
        }

        this.setState({
            value: target.value
        }, () => this.props.onChange && this.props.onChange());

    }

    componentWillReceiveProps(nextProps) {
        const {width, height, value} = this.state;

        if (nextProps.initialWidth !== width || nextProps.initialHeight !== height || nextProps.value !== value) {
            this.setState({
                width: nextProps.initialWidth,
                height: nextProps.initialHeight,
                value: nextProps.value
            });
        }
    }

    componentDidMount() {
        const {autoSize, autoFocus} = this.props;

        if (!autoSize) {
            Event.addEvent(this.refs.textarea, 'mouseup', this.mouseUpHandle);
        }

        if (autoFocus === true) {
            this.refs.textarea.focus();
        }
    }

    componentWillUnmount() {
        const {autoSize} = this.props;

        if (!autoSize) {
            Event.removeEvent(this.refs.textarea, 'mouseup', this.mouseUpHandle);
        }
    }

    render() {
        const {className, style, cols, rows, autoSize, placeholder, maxWidth} = this.props;
        const {focus, width, height, value} = this.state;

        let textStyle = {
            height: height,
            width: width,
            overflow: autoSize ? 'hidden' : 'auto',
            resize: autoSize ? 'none' : 'both',
            maxWidth: maxWidth,
            ...style
        };

        return (
            <textarea ref="textarea"
                      className={`text-area ${focus ? 'area-focus' : ''} ${className}`}
                      style={{...textStyle}}
                      cols={cols}
                      rows={rows}
                      placeholder={placeholder}
                      value={value}
                      autoComplete="off"
                      autoCorrect="off"
                      autoCapitalize="off"
                      spellCheck="false"
                      onFocus={this.onFocus}
                      onBlur={this.onBlur}
                      onInput={this.onChange}>
            </textarea>
        );
    }
};

TextArea.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The number of cols.
     */
    cols: PropTypes.number,

    /**
     * The number of rows.
     */
    rows: PropTypes.number,

    /**
     * The initial height of textArea.
     */
    initialHeight: PropTypes.number,

    /**
     * The initial height of textArea.
     */
    initialWidth: PropTypes.number,

    /**
     * The value of textArea.
     */
    value: PropTypes.string,

    /**
     * The max height of textArea.
     */
    maxHeight: PropTypes.number,

    /**
     * The max width of textArea.
     */
    maxWidth: PropTypes.number,

    /**
     * If true, the textArea will change its size by words.
     */
    autoSize: PropTypes.bool,

    /**
     * If true,the textField will autoFocus.
     */
    autoFocus: PropTypes.bool,

    /**
     * The placeholder of textArea.
     */
    placeholder: PropTypes.string,

    /**
     * When the value of textArea change, it will execute.
     */
    onChange: PropTypes.func,

    /**
     * When the textArea onBlur, it will execute.
     */
    onBlur: PropTypes.func,

    /**
     * When the textArea onFocus, it will execute.
     */
    onFocus: PropTypes.func

};

TextArea.defaultProps = {

    className: '',
    style: null,

    cols: 50,
    rows: 3,
    initialHeight: 30,
    initialWidth: 200,
    maxHeight: 100,
    maxWidth: 500,
    autoSize: true,
    autoFocus: false,
    placeholder: 'Please input something.',
    value: ''

};<|endoftext|>


<commit_before> // JavaScript Olympics

// I paired with:Jack Huang on this challenge.

// This challenge took me [1.5] hours.

// Warm Up

// Bulk Up

var jordan = {
  name: "Michael Jordan",
  event: "Basketball",
}
var curry = {
  name: "Stephen Curry",
  event: "Basketball",
}
var athlete = [jordan, curry];
function bulkUp(athlete) {
  for (var i = 0; i < athlete.length; i++) {
    athlete[i].win = athlete[i].name + " has won " + athlete[i].event;
    console.log(athlete[i].win)
  }
}

bulkUp(athlete);
// Jumble your words

function reverse (str) {
  var rev = "";
  for (var i = str.length-1 ; i > -1; i--) {
    rev += str[i];
  }
  console.log(rev);
}

reverse("Hello")

// 2,4,6,8

function evenNumbers(array) {
  var evenArray = [];
  for (var i = 0; i < array.length; i++) {
    if (array[i] % 2 === 0) {
      evenArray += array[i];
    }
  }
  console.log(evenArray)
}

evenNumbers([1,2,3,4,5])

// "We built this city"

function Athlete(name, age, sport, quote) {
    this.name = name;
    this.age = age;
    this.sport = sport;
    this.quote = quote;
}

var michaelPhelps = new Athlete("Michael Phelps", 29, "swimming", "It's medicinal I swear!")

console.log(michaelPhelps.constructor === Athlete)
console.log(michaelPhelps.name + " " + michaelPhelps.sport + " " + michaelPhelps.quote)

// Reflection
//What JavaScript knowledge did you solidify in this challenge?
//I found this challenge to be quite confusing. It took us a
//long time to sort of figure out what the releases are
//asking us to do. I guess one thing I got out of this challenge
// was that I was not completely familiar with several JavaScript
//concepts, so I went back and did some more readings to further
//solidify my understanding.

//What are constructor functions?
//
//How are constructors different from Ruby classes (in your research)?<commit_msg>Challenge complete<commit_after> // JavaScript Olympics

// I paired with:Jack Huang on this challenge.

// This challenge took me [2]hours.

// Warm Up

// Bulk Up

var jordan = {
  name: "Michael Jordan",
  event: "Basketball",
}
var curry = {
  name: "Stephen Curry",
  event: "Basketball",
}
var athlete = [jordan, curry];
function bulkUp(athlete) {
  for (var i = 0; i < athlete.length; i++) {
    athlete[i].win = athlete[i].name + " has won " + athlete[i].event;
    console.log(athlete[i].win)
  }
}

bulkUp(athlete);
// Jumble your words

function reverse (str) {
  var rev = "";
  for (var i = str.length-1 ; i > -1; i--) {
    rev += str[i];
  }
  console.log(rev);
}

reverse("Hello")

// 2,4,6,8

function evenNumbers(array) {
  var evenArray = [];
  for (var i = 0; i < array.length; i++) {
    if (array[i] % 2 === 0) {
      evenArray += array[i];
    }
  }
  console.log(evenArray)
}

evenNumbers([1,2,3,4,5])

// "We built this city"

function Athlete(name, age, sport, quote) {
    this.name = name;
    this.age = age;
    this.sport = sport;
    this.quote = quote;
}

var michaelPhelps = new Athlete("Michael Phelps", 29, "swimming", "It's medicinal I swear!")

console.log(michaelPhelps.constructor === Athlete)
console.log(michaelPhelps.name + " " + michaelPhelps.sport + " " + michaelPhelps.quote)

// Reflection
//What JavaScript knowledge did you solidify in this challenge?
//I found this challenge to be quite confusing. It took us a
//long time to sort of figure out what the releases are
//asking us to do. I guess one thing I got out of this challenge
// was that I was not completely familiar with several JavaScript
//concepts, so I went back and did some more readings to further
//solidify my understanding.

//What are constructor functions?
// Constructor functions can be used as a template for creating multiple instances of an object.
//How are constructors different from Ruby classes (in your research)?
//JavaScript does not restrict access to properties.<|endoftext|>


<commit_before>import MetadataItem from './MetadataItem';

let girder = window.girder;

let DEFAULT_INTERPRETATIONS = {
  'undefined': 'ignore',
  boolean: 'categorical',
  integer: 'quantitative',
  number: 'quantitative',
  date: 'categorical',
  string: 'categorical',
  object: 'ignore'
};

let BIN_COUNT = 10;

function DuplicateDatasetError (message) {
  this.name = 'DuplicateDatasetError';
  this.message = message;
  this.stack = (new Error()).stack;
}
DuplicateDatasetError.prototype = Object.create(Error.prototype);

let Dataset = MetadataItem.extend({
  initialize: function () {
    if (window.mainPage.loadedDatasets[this.getId()]) {
      throw new DuplicateDatasetError();
    }
    window.mainPage.loadedDatasets[this.getId()] = this;

    // If any of this initialization stuff ends up
    // saving a copy of this item, we'll get our
    // id swapped from under us...
    this.listenTo(this, 'rl:swapId', this.swapId);

    this.rawCache = null;
    this.parsedCache = null;
    let meta = this.getMeta();

    let schemaPromise;

    let girderUpdate = this.get('updated');
    // TODO: do database items update their girder 'updated' flag
    // when the database is modified? If not, we may need a deeper
    // check...
    if (meta.schema && meta.lastUpdated && girderUpdate &&
      new Date(meta.lastUpdated) >= new Date(girderUpdate)) {
      // We can just use the cached schema
      schemaPromise = Promise.resolve(meta.schema);
    } else {
      // We need to run schema inference...
      schemaPromise = this.inferSchema();
    }

    schemaPromise.then(schema => {
      // Now that we know the schema, if we have filters,
      // we should validate and reapply them
      return this.setFilters(meta.filters);
    }).then();
  },
  getAttributeInterpretation: function (attrSpec) {
    if (attrSpec.interpretation) {
      // The user has specified an interpretation
      return attrSpec.interpretation;
    } else {
      // Go with the default interpretation for the attribute type
      return DEFAULT_INTERPRETATIONS[this.getAttributeType(attrSpec)];
    }
  },
  getAttributeType: function (attrSpec) {
    if (attrSpec.coerceToType) {
      // The user has specified a data type
      return attrSpec.coerceToType;
    } else {
      // The user hasn't specified a type; go with the
      // most frequently observed type in the dataset
      let maxCount = 0;
      let attrType = 'undefined';
      for (let dataType of Object.keys(attrSpec.stats)) {
        if (attrSpec.stats[dataType].count >= maxCount) {
          maxCount = attrSpec.stats[dataType].count;
          attrType = dataType;
        }
      }
      return attrType;
    }
  },
  getHistogramParameters: function (ignoreFilters) {
    let schema = this.getMeta('schema');
    let excludeAttributes = this.getMeta('excludeAttributes') || [];
    let filters = this.getMeta('filters') || [];
    let parameters = {
      categoricalAttrs: [],
      quantitativeAttrs: {}
    };
    // Assemble the parameters for which attributes we want to see
    // (and provide the bin settings for quantitative attributes)
    for (let attrName of Object.keys(schema)) {
      if (!ignoreFilters && excludeAttributes.indexOf(attrName) !== -1) {
        continue;
      }
      let attrSpec = schema[attrName];
      if (this.getAttributeInterpretation(attrSpec) === 'categorical') {
        parameters.categoricalAttrs.push(attrName);
      } else if (this.getAttributeInterpretation(attrSpec) === 'quantitative') {
        // Our schema should tell us the lowest / highest values
        // for this attribute as a number...
        if (!attrSpec.stats.number) {
          // Even though we want to interpret this value as quantitative,
          // we can't (yet) figure out how to ask for min and max values...

          // TODO: what about other potentially quantitative values (like dates?
          // the server will probably auto-infer that these are strings...)

          // For now, as a fallback, we'll add this as a categorical query,
          // but this could be bad for performance (probably lots of "categories"
          // if it's really quantitative). This may also cause some UI confusion...
          parameters.categoricalAttrs.push(attrName);
          continue;
        }
        let desiredType = this.getAttributeType(attrSpec);
        let result = {
          binCount: BIN_COUNT,
          min: this.coerceValue(attrSpec.stats.number.min, desiredType),
          max: this.coerceValue(attrSpec.stats.number.max, desiredType)
        };
        // TODO: there are probably more intelligent things we can
        // do with binCount based on the data type...
        if (desiredType === 'boolean') {
          result.binCount = 2;
        }
        if (result.min === result.max) {
          // Shoot... there's really only one value for this attribute
          // after all. So it's really categorical, even if we want it to be
          // quantitative (at least as far as the histogram calculations
          // are concerned)
          parameters.categoricalAttrs.push(attrName);
        } else {
          parameters.quantitativeAttrs[attrName] = result;
        }
      }
    }
    // Add the filters if there are any
    if (!ignoreFilters && filters && filters.length > 0) {
      parameters.filters = filters;
    }
    // Format the parameters for the endpoint...
    parameters.categoricalAttrs = parameters.categoricalAttrs.join(',');
    parameters.quantitativeAttrs = JSON.stringify(parameters.quantitativeAttrs);
    return parameters;
  },
  updateHistograms: function (updateSummary) {
    // Always update the current histogram (with the filters)
    let promises = [new Promise((resolve, reject) => {
      girder.restRequest({
        path: 'item/' + this.getId() + '/getHistograms',
        type: 'GET',
        data: this.getHistogramParameters(false),
        error: reject,
        dataType: 'json'
      }).done(resolve).error(reject);
    })];
    // Sometimes we need to update the summary histogram (without the filters)
    // as well...
    if (updateSummary) {
      promises.push(new Promise((resolve, reject) => {
        girder.restRequest({
          path: 'item/' + this.getId() + '/getHistograms',
          type: 'GET',
          data: this.getHistogramParameters(true),
          error: reject,
          dataType: 'json'
        }).done(resolve).error(reject);
      }));
    }
    return Promise.all(promises).then((results) => {
      this.setMeta('currentHistogram', results[0]);
      if (updateSummary) {
        this.setMeta('summaryHistogram', results[1]);
      }
      return this.save().then(() => {
        this.trigger('rl:changeSpec');
      });
    });
  },
  getSpec: function (includeExcluded = false) {
    let schema = this.getMeta('schema') || {};
    let excludeAttributes = this.getMeta('excludeAttributes') || [];
    let spec = {
      name: this.name(),
      attributes: {}
    };
    for (let attrName of Object.keys(schema)) {
      if (!includeExcluded && excludeAttributes.indexOf(attrName) !== -1) {
        continue;
      }
      spec.attributes[attrName] = this.getAttributeType(schema[attrName]);
    }
    return spec;
  },
  swapId: function (newData) {
    window.mainPage.loadedDatasets[newData._id] = window.mainPage.loadedDatasets[newData._oldId];
    delete window.mainPage.loadedDatasets[newData._oldId];
    window.mainPage.loadedDatasets[newData._id].set(newData);
  },
  drop: function () {
    this.dropped = true;
    this.stopListening();
    delete window.mainPage.loadedDatasets[this.getId()];
  },
  save: function () {
    // It's possible for a dataset to be dropped from a collection
    // (e.g. it's replaced with a copy). In this case, we want to
    // stop all future attempts to save any changes to the dropped
    // dataset)
    if (this.dropped) {
      return Promise.resolve();
    } else {
      return MetadataItem.prototype.save.apply(this).catch(errorObj => {
        window.mainPage.trigger('rl:error', errorObj);
      });
    }
  },
  loadData: function (cache = true) {
    // TODO: support more file formats / non-Girder
    // files (e.g. pasted browser data)
    if (cache && this.rawCache !== null) {
      return Promise.resolve(this.rawCache);
    } else {
      let parameters = {
        format: 'dict',
        filters: this.getMeta('filters'),
        fields: Object.keys(this.getSpec().attributes)
      };
      return new Promise((resolve, reject) => {
        girder.restRequest({
          path: `item/${this.getId()}/filterData`,
          type: 'GET',
          dataType: 'text',
          error: reject,
          data: parameters
        }).done(resolve).error(reject);
      }).then(data => {
        this.rawCache = data;
      }).catch((e) => {
        window.mainPage.trigger('rl:error', e);
      });
    }
  },
  coerceValue: function (value, dataType) {
    if (dataType === 'undefined') {
      return undefined;
    } else if (dataType === 'boolean') {
      return !!value;
    } else if (dataType === 'integer') {
      return parseInt(String(value).replace(/[^0-9\.]+/g, ''));
    } else if (dataType === 'number') {
      return parseFloat(String(value).replace(/[^0-9\.]+/g, ''));
    } else if (dataType === 'date') {
      return new Date(value);
    } else if (dataType === 'string') {
      return String(value);
    } else if (dataType === 'object') {
      // TODO: should I be doing something else?
      return value;
    } else {
      throw new Error('Unknown data type: ' + dataType);
    }
  },
  parse: function (cache = true) {
    if (cache && this.parsedCache !== null) {
      return Promise.resolve(this.parsedCache);
    } else {
      let parsedData;
      return this.loadData().then(rawData => {
        let schema = this.getMeta('schema');
        if (rawData === null || !schema) {
          this.parsedCache = parsedData = null;
        } else {
          try {
            parsedData = JSON.parse(rawData);
            // If that was successful, we can pretty-print the raw data...
            this.rawCache = JSON.stringify(parsedData, null, '  ');

            // Okay, now we need to coerce data types (and deliberately remove
            // attributes if necessary)
            let excludeAttributes = this.getMeta('excludeAttributes') || [];
            parsedData.forEach(dataItem => {
              for (let attrName of Object.keys(dataItem)) {
                if (excludeAttributes.indexOf(attrName) !== -1) {
                  delete dataItem[attrName];
                } else {
                  let dataType = this.getAttributeType(schema[attrName]);
                  dataItem[attrName] = this.coerceValue(dataItem[attrName], dataType);
                }
              }
            });
          } catch (e) {
            parsedData = null;
            if (!(e instanceof SyntaxError)) {
              window.mainPage.trigger('rl:error', e);
            }
          }

          if (cache) {
            this.parsedCache = parsedData;
          }
        }
        return parsedData;
      });
    }
  },
  inferSchema: function () {
    return new Promise((resolve, reject) => {
      girder.restRequest({
        path: `item/${this.getId()}/inferSchema`,
        type: 'GET',
        dataType: 'json',
        error: reject
      }).done(resolve).error(reject);
    }).then(stats => {
      // Keep any user preferences for attributes
      // (e.g. forced types / interpretations / excluded attributes)
      let existingSchema = this.getMeta('schema') || {};
      let excludedAttributes = this.getMeta('excludeAttributes') || [];
      let newSchema = {};
      let excludeAttributes = [];
      for (let attrName of Object.keys(stats)) {
        newSchema[attrName] = {
          stats: stats[attrName]
        };
        if (excludedAttributes.indexOf(attrName) !== -1) {
          excludeAttributes.push(attrName);
        }
        if (existingSchema[attrName]) {
          if (existingSchema[attrName].coerceToType) {
            newSchema[attrName].coerceToType = existingSchema[attrName].coerceToType;
          }
          if (existingSchema[attrName].interpretation) {
            newSchema[attrName].interpretation = existingSchema[attrName].interpretation;
          }
        }
      }
      // Store the new schema
      this.setMeta('schema', newSchema);
      // Store the new excludeAttributes
      this.setMeta('excludeAttributes', excludeAttributes);
      // Store the current time
      this.setMeta('lastUpdated', new Date().toISOString());
      // Now that we have the schema, update the summaryHistogram
      // (eventually calls save as well)
      return this.updateHistograms(true);
    });
  },
  includeAttribute: function (attrName, include) {
    let excludeAttributes = this.getMeta('excludeAttributes') || [];
    let attrIndex = excludeAttributes.indexOf(attrName);
    if (include === true) {
      if (attrIndex !== -1) {
        excludeAttributes.splice(attrIndex, 1);
      }
    } else {
      if (attrIndex === -1) {
        excludeAttributes.push(attrName);
      }
    }
    this.setMeta('excludeAttributes', excludeAttributes);

    return this.updateHistograms(false);
  },
  setFilters: function (filters) {
    if (filters) {
      this.setMeta('filters', filters);
    } else {
      this.unsetMeta('filters');
    }
    // TODO: validate that the filters make sense in terms of the schema

    return this.updateHistograms(false);
  },
  setAttributeType: function (attrName, dataType) {
    let schema = this.getMeta('schema');
    schema[attrName].coerceToType = dataType;
    this.setMeta('schema', schema);

    return this.updateHistograms(true);
  },
  setAttributeInterpretation: function (attrName, interpretation) {
    let schema = this.getMeta('schema');
    schema[attrName].interpretation = interpretation;
    this.setMeta('schema', schema);

    return this.updateHistograms(true);
  }
});

Dataset.DEFAULT_INTERPRETATIONS = DEFAULT_INTERPRETATIONS;
Dataset.DuplicateDatasetError = DuplicateDatasetError;
export default Dataset;
<commit_msg>Remove item limit<commit_after>import MetadataItem from './MetadataItem';

let girder = window.girder;

let DEFAULT_INTERPRETATIONS = {
  'undefined': 'ignore',
  boolean: 'categorical',
  integer: 'quantitative',
  number: 'quantitative',
  date: 'categorical',
  string: 'categorical',
  object: 'ignore'
};

let BIN_COUNT = 10;

function DuplicateDatasetError (message) {
  this.name = 'DuplicateDatasetError';
  this.message = message;
  this.stack = (new Error()).stack;
}
DuplicateDatasetError.prototype = Object.create(Error.prototype);

let Dataset = MetadataItem.extend({
  initialize: function () {
    if (window.mainPage.loadedDatasets[this.getId()]) {
      throw new DuplicateDatasetError();
    }
    window.mainPage.loadedDatasets[this.getId()] = this;

    // If any of this initialization stuff ends up
    // saving a copy of this item, we'll get our
    // id swapped from under us...
    this.listenTo(this, 'rl:swapId', this.swapId);

    this.rawCache = null;
    this.parsedCache = null;
    let meta = this.getMeta();

    let schemaPromise;

    let girderUpdate = this.get('updated');
    // TODO: do database items update their girder 'updated' flag
    // when the database is modified? If not, we may need a deeper
    // check...
    if (meta.schema && meta.lastUpdated && girderUpdate &&
      new Date(meta.lastUpdated) >= new Date(girderUpdate)) {
      // We can just use the cached schema
      schemaPromise = Promise.resolve(meta.schema);
    } else {
      // We need to run schema inference...
      schemaPromise = this.inferSchema();
    }

    schemaPromise.then(schema => {
      // Now that we know the schema, if we have filters,
      // we should validate and reapply them
      return this.setFilters(meta.filters);
    }).then();
  },
  getAttributeInterpretation: function (attrSpec) {
    if (attrSpec.interpretation) {
      // The user has specified an interpretation
      return attrSpec.interpretation;
    } else {
      // Go with the default interpretation for the attribute type
      return DEFAULT_INTERPRETATIONS[this.getAttributeType(attrSpec)];
    }
  },
  getAttributeType: function (attrSpec) {
    if (attrSpec.coerceToType) {
      // The user has specified a data type
      return attrSpec.coerceToType;
    } else {
      // The user hasn't specified a type; go with the
      // most frequently observed type in the dataset
      let maxCount = 0;
      let attrType = 'undefined';
      for (let dataType of Object.keys(attrSpec.stats)) {
        if (attrSpec.stats[dataType].count >= maxCount) {
          maxCount = attrSpec.stats[dataType].count;
          attrType = dataType;
        }
      }
      return attrType;
    }
  },
  getHistogramParameters: function (ignoreFilters) {
    let schema = this.getMeta('schema');
    let excludeAttributes = this.getMeta('excludeAttributes') || [];
    let filters = this.getMeta('filters') || [];
    let parameters = {
      categoricalAttrs: [],
      quantitativeAttrs: {}
    };
    // Assemble the parameters for which attributes we want to see
    // (and provide the bin settings for quantitative attributes)
    for (let attrName of Object.keys(schema)) {
      if (!ignoreFilters && excludeAttributes.indexOf(attrName) !== -1) {
        continue;
      }
      let attrSpec = schema[attrName];
      if (this.getAttributeInterpretation(attrSpec) === 'categorical') {
        parameters.categoricalAttrs.push(attrName);
      } else if (this.getAttributeInterpretation(attrSpec) === 'quantitative') {
        // Our schema should tell us the lowest / highest values
        // for this attribute as a number...
        if (!attrSpec.stats.number) {
          // Even though we want to interpret this value as quantitative,
          // we can't (yet) figure out how to ask for min and max values...

          // TODO: what about other potentially quantitative values (like dates?
          // the server will probably auto-infer that these are strings...)

          // For now, as a fallback, we'll add this as a categorical query,
          // but this could be bad for performance (probably lots of "categories"
          // if it's really quantitative). This may also cause some UI confusion...
          parameters.categoricalAttrs.push(attrName);
          continue;
        }
        let desiredType = this.getAttributeType(attrSpec);
        let result = {
          binCount: BIN_COUNT,
          min: this.coerceValue(attrSpec.stats.number.min, desiredType),
          max: this.coerceValue(attrSpec.stats.number.max, desiredType)
        };
        // TODO: there are probably more intelligent things we can
        // do with binCount based on the data type...
        if (desiredType === 'boolean') {
          result.binCount = 2;
        }
        if (result.min === result.max) {
          // Shoot... there's really only one value for this attribute
          // after all. So it's really categorical, even if we want it to be
          // quantitative (at least as far as the histogram calculations
          // are concerned)
          parameters.categoricalAttrs.push(attrName);
        } else {
          parameters.quantitativeAttrs[attrName] = result;
        }
      }
    }
    // Add the filters if there are any
    if (!ignoreFilters && filters && filters.length > 0) {
      parameters.filters = filters;
    }
    // Format the parameters for the endpoint...
    parameters.categoricalAttrs = parameters.categoricalAttrs.join(',');
    parameters.quantitativeAttrs = JSON.stringify(parameters.quantitativeAttrs);
    return parameters;
  },
  updateHistograms: function (updateSummary) {
    // Always update the current histogram (with the filters)
    let promises = [new Promise((resolve, reject) => {
      girder.restRequest({
        path: 'item/' + this.getId() + '/getHistograms',
        type: 'GET',
        data: this.getHistogramParameters(false),
        error: reject,
        dataType: 'json'
      }).done(resolve).error(reject);
    })];
    // Sometimes we need to update the summary histogram (without the filters)
    // as well...
    if (updateSummary) {
      promises.push(new Promise((resolve, reject) => {
        girder.restRequest({
          path: 'item/' + this.getId() + '/getHistograms',
          type: 'GET',
          data: this.getHistogramParameters(true),
          error: reject,
          dataType: 'json'
        }).done(resolve).error(reject);
      }));
    }
    return Promise.all(promises).then((results) => {
      this.setMeta('currentHistogram', results[0]);
      if (updateSummary) {
        this.setMeta('summaryHistogram', results[1]);
      }
      return this.save().then(() => {
        this.trigger('rl:changeSpec');
      });
    });
  },
  getSpec: function (includeExcluded = false) {
    let schema = this.getMeta('schema') || {};
    let excludeAttributes = this.getMeta('excludeAttributes') || [];
    let spec = {
      name: this.name(),
      attributes: {}
    };
    for (let attrName of Object.keys(schema)) {
      if (!includeExcluded && excludeAttributes.indexOf(attrName) !== -1) {
        continue;
      }
      spec.attributes[attrName] = this.getAttributeType(schema[attrName]);
    }
    return spec;
  },
  swapId: function (newData) {
    window.mainPage.loadedDatasets[newData._id] = window.mainPage.loadedDatasets[newData._oldId];
    delete window.mainPage.loadedDatasets[newData._oldId];
    window.mainPage.loadedDatasets[newData._id].set(newData);
  },
  drop: function () {
    this.dropped = true;
    this.stopListening();
    delete window.mainPage.loadedDatasets[this.getId()];
  },
  save: function () {
    // It's possible for a dataset to be dropped from a collection
    // (e.g. it's replaced with a copy). In this case, we want to
    // stop all future attempts to save any changes to the dropped
    // dataset)
    if (this.dropped) {
      return Promise.resolve();
    } else {
      return MetadataItem.prototype.save.apply(this).catch(errorObj => {
        window.mainPage.trigger('rl:error', errorObj);
      });
    }
  },
  loadData: function (cache = true) {
    // TODO: support more file formats / non-Girder
    // files (e.g. pasted browser data)
    if (cache && this.rawCache !== null) {
      return Promise.resolve(this.rawCache);
    } else {
      let parameters = {
        format: 'dict',
        filters: this.getMeta('filters'),
        fields: Object.keys(this.getSpec().attributes),
        limit: 0
      };
      return new Promise((resolve, reject) => {
        girder.restRequest({
          path: `item/${this.getId()}/filterData`,
          type: 'GET',
          dataType: 'text',
          error: reject,
          data: parameters
        }).done(resolve).error(reject);
      }).then(data => {
        this.rawCache = data;
      }).catch((e) => {
        window.mainPage.trigger('rl:error', e);
      });
    }
  },
  coerceValue: function (value, dataType) {
    if (dataType === 'undefined') {
      return undefined;
    } else if (dataType === 'boolean') {
      return !!value;
    } else if (dataType === 'integer') {
      return parseInt(String(value).replace(/[^0-9\.]+/g, ''));
    } else if (dataType === 'number') {
      return parseFloat(String(value).replace(/[^0-9\.]+/g, ''));
    } else if (dataType === 'date') {
      return new Date(value);
    } else if (dataType === 'string') {
      return String(value);
    } else if (dataType === 'object') {
      // TODO: should I be doing something else?
      return value;
    } else {
      throw new Error('Unknown data type: ' + dataType);
    }
  },
  parse: function (cache = true) {
    if (cache && this.parsedCache !== null) {
      return Promise.resolve(this.parsedCache);
    } else {
      let parsedData;
      return this.loadData().then(rawData => {
        let schema = this.getMeta('schema');
        if (rawData === null || !schema) {
          this.parsedCache = parsedData = null;
        } else {
          try {
            parsedData = JSON.parse(rawData);
            // If that was successful, we can pretty-print the raw data...
            this.rawCache = JSON.stringify(parsedData, null, '  ');

            // Okay, now we need to coerce data types (and deliberately remove
            // attributes if necessary)
            let excludeAttributes = this.getMeta('excludeAttributes') || [];
            parsedData.forEach(dataItem => {
              for (let attrName of Object.keys(dataItem)) {
                if (excludeAttributes.indexOf(attrName) !== -1) {
                  delete dataItem[attrName];
                } else {
                  let dataType = this.getAttributeType(schema[attrName]);
                  dataItem[attrName] = this.coerceValue(dataItem[attrName], dataType);
                }
              }
            });
          } catch (e) {
            parsedData = null;
            if (!(e instanceof SyntaxError)) {
              window.mainPage.trigger('rl:error', e);
            }
          }

          if (cache) {
            this.parsedCache = parsedData;
          }
        }
        return parsedData;
      });
    }
  },
  inferSchema: function () {
    return new Promise((resolve, reject) => {
      girder.restRequest({
        path: `item/${this.getId()}/inferSchema`,
        type: 'GET',
        dataType: 'json',
        error: reject
      }).done(resolve).error(reject);
    }).then(stats => {
      // Keep any user preferences for attributes
      // (e.g. forced types / interpretations / excluded attributes)
      let existingSchema = this.getMeta('schema') || {};
      let excludedAttributes = this.getMeta('excludeAttributes') || [];
      let newSchema = {};
      let excludeAttributes = [];
      for (let attrName of Object.keys(stats)) {
        newSchema[attrName] = {
          stats: stats[attrName]
        };
        if (excludedAttributes.indexOf(attrName) !== -1) {
          excludeAttributes.push(attrName);
        }
        if (existingSchema[attrName]) {
          if (existingSchema[attrName].coerceToType) {
            newSchema[attrName].coerceToType = existingSchema[attrName].coerceToType;
          }
          if (existingSchema[attrName].interpretation) {
            newSchema[attrName].interpretation = existingSchema[attrName].interpretation;
          }
        }
      }
      // Store the new schema
      this.setMeta('schema', newSchema);
      // Store the new excludeAttributes
      this.setMeta('excludeAttributes', excludeAttributes);
      // Store the current time
      this.setMeta('lastUpdated', new Date().toISOString());
      // Now that we have the schema, update the summaryHistogram
      // (eventually calls save as well)
      return this.updateHistograms(true);
    });
  },
  includeAttribute: function (attrName, include) {
    let excludeAttributes = this.getMeta('excludeAttributes') || [];
    let attrIndex = excludeAttributes.indexOf(attrName);
    if (include === true) {
      if (attrIndex !== -1) {
        excludeAttributes.splice(attrIndex, 1);
      }
    } else {
      if (attrIndex === -1) {
        excludeAttributes.push(attrName);
      }
    }
    this.setMeta('excludeAttributes', excludeAttributes);

    return this.updateHistograms(false);
  },
  setFilters: function (filters) {
    if (filters) {
      this.setMeta('filters', filters);
    } else {
      this.unsetMeta('filters');
    }
    // TODO: validate that the filters make sense in terms of the schema

    return this.updateHistograms(false);
  },
  setAttributeType: function (attrName, dataType) {
    let schema = this.getMeta('schema');
    schema[attrName].coerceToType = dataType;
    this.setMeta('schema', schema);

    return this.updateHistograms(true);
  },
  setAttributeInterpretation: function (attrName, interpretation) {
    let schema = this.getMeta('schema');
    schema[attrName].interpretation = interpretation;
    this.setMeta('schema', schema);

    return this.updateHistograms(true);
  }
});

Dataset.DEFAULT_INTERPRETATIONS = DEFAULT_INTERPRETATIONS;
Dataset.DuplicateDatasetError = DuplicateDatasetError;
export default Dataset;
<|endoftext|>


<commit_before>import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class CurriculumInventoryReportReport extends Route {
  @service session;

  beforeModel(transition) {
    this.session.requireAuthentication(transition, 'login');
  }
}
<commit_msg>explicitly load model.<commit_after>import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default class CurriculumInventoryReportReport extends Route {
  @service session;
  @service store;

  beforeModel(transition) {
    this.session.requireAuthentication(transition, 'login');
  }

  model(params) {
    return this.store.findRecord(
      'curriculum-inventory-report',
      params.curriculum_inventory_report_id
    );
  }
}
<|endoftext|>


<commit_before>PhotoportCMS.module('CollectionsApp.Editor', function (Editor, PhotoportCMS, Backbone, Marionette, $, _) {

  Editor.Controller = {
    show: function () {
      var layout = new Editor.Layout();
      PhotoportCMS.mainRegion.show(layout);

      var collection = new PhotoportCMS.Collection(PHOTOPORT_CMS.collection);

      var photoportEditorView  = new PhotoportCMS.PhotoportEditor.Controller.makeView({
        collection: collection
      })

      layout.contentRegion.show(photoportEditorView);
    }
  };
});<commit_msg>cleanup spacing and syntax<commit_after>PhotoportCMS.module('CollectionsApp.Editor', function (Editor, PhotoportCMS, Backbone, Marionette, $, _) {

  Editor.Controller = {
    show: function () {
      var layout = new Editor.Layout();
      PhotoportCMS.mainRegion.show(layout);

      var collection = new PhotoportCMS.Collection(PHOTOPORT_CMS.collection);

      var photoportEditorView = new PhotoportCMS.PhotoportEditor.Controller.makeView({
        collection: collection
      });

      layout.contentRegion.show(photoportEditorView);
    }
  };
});<|endoftext|>


<commit_before>/**
 * Copyright (C) 2015 Laverna project Authors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
/* global define */
define([
    'underscore',
    'q',
    'jquery',
    'backbone.radio',
    'marionette',
    'apps/notes/form/views/formView',
    'apps/notes/form/views/notebooks'
], function (_, Q, $, Radio, Marionette, View, NotebooksView) {
    'use strict';

    /**
     * Note form controller.
     *
     * Triggers the following events:
     * 1. channel: notesForm, event: stop
     *
     * Listens to the following events:
     * 1. channel: notes, event: save:after
     *
     * requests:
     * 1. channel: notes, request: save
     *    to save the changes.
     */
    var Controller = Marionette.Object.extend({

        initialize: function(options) {
            this.options = options;

            _.bindAll(this, 'show', 'redirect');

            // Fetch everything
            Q.all([
                Radio.request('notes', 'get:model:full', options),
                Radio.request('notebooks', 'get:all', _.pick(options, 'profile'))
            ])
            .spread(this.show)
            .catch(function() {
                console.error('Editor error', arguments);
            });

            // Events
            this.listenTo(Radio.channel('notes'), 'update:model', this.redirect);
            this.listenTo(Radio.channel('Confirm'), 'confirm', this.redirect);
            this.listenTo(Radio.channel('Confirm'), 'cancel', this.onConfirmCancel);
        },

        onDestroy: function() {
            this.stopListening();
            this.view.trigger('destroy');
        },

        show: function(note, notebooks) {
            var notebooksView;
            note = note[0];

            // Set document title
            Radio.request('global', 'set:title', note.get('title'));

            // Use behaviours that are appropriate for a device.
            if (Radio.request('global', 'platform') === 'mobile') {
                delete View.prototype.behaviors.Desktop;
            }
            else {
                delete View.prototype.behaviors.Mobile;
            }

            this.view = new View({
                model     : note,
                profile   : note.profileId
            });

            // Show the view and trigger an event
            Radio.request('global', 'region:show', 'content', this.view);
            this.view.trigger('rendered');

            /*
             * Resolve the notebook ID.
             * If the current note doesn't have a notebook attached,
             * try to use one from the filter if it specifies a notebook.
             */
            var activeId = note.get('notebookId');
            if (activeId === '0' && this.options.filter === 'notebook') {
                activeId = this.options.query;
            }

            // Show notebooks selector
            notebooksView = new NotebooksView({
                collection : notebooks,
                activeId   : activeId
            });
            this.view.notebooks.show(notebooksView);

            // Listen to view events
            this.listenTo(this.view, 'save', this.save);
            this.listenTo(this.view, 'cancel', this.showConfirm);
        },

        save: function() {
            var self = this;

            return this.getContent()
            .then(function(data) {
                if (data.title === '') {
                    var title = 'New-Note-' + new Date().toLocaleDateString();
                    data.title = title;
                    Radio.request('global', 'set:title', title);
                }
                return Radio.request('notes', 'save', self.view.model, data);
            })
            .fail(function(e) {
                console.error('Error', e);
            });
        },

        getContent: function() {
            var self = this;

            return Radio.request('editor', 'get:data')
            .then(function(data) {
                return _.extend(data, {
                    title      : self.view.ui.title.val().trim(),
                    notebookId : self.view.notebooks.currentView.ui.notebookId.val().trim(),
                });
            });
        },

        /**
         * Warn a user that they have made some changes.
         */
        showConfirm: function() {
            var self = this;

            return this.getContent()
            .then(function(data) {
                var model = self.view.model.pick('title', 'content', 'notebookId');
                data      = _.pick(data, 'title', 'content', 'notebookId');

                // To check if they are equal
                model.content = _.unescape(model.content);
                model.title   = _.unescape(model.title);

                if (_.isEqual(model, data)) {
                    return self.redirect();
                }

                Radio.request('Confirm', 'start', $.t('You have unsaved changes.'));
            })
            .fail(function(e) {
                console.error('form ShowConfirm', e);
            });
        },

        redirect: function() {
            if (!this.view.getOption('redirect')) {
                return;
            }

            // Stop the module and navigate back
            Radio.trigger('notesForm', 'stop');
            Radio.request('uri', 'back');
        },

        onConfirmCancel: function() {
            // Rebind keybindings again because TW bootstrap modal overrites ESC.
            this.view.trigger('bind:keys');
            this.view.options.isClosed = false;

            if (this.view.options.focus !== 'editor') {
                return this.view.ui[this.view.options.focus].focus();
            }
            Radio.trigger('editor', 'focus');
        }

    });

    return Controller;
});
<commit_msg>Use i18n for translating the 'New Note' strin<commit_after>/**
 * Copyright (C) 2015 Laverna project Authors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
/* global define */
define([
    'underscore',
    'q',
    'jquery',
    'backbone.radio',
    'marionette',
    'i18next',
    'apps/notes/form/views/formView',
    'apps/notes/form/views/notebooks'
], function (_, Q, $, Radio, Marionette, i18n, View, NotebooksView) {
    'use strict';

    /**
     * Note form controller.
     *
     * Triggers the following events:
     * 1. channel: notesForm, event: stop
     *
     * Listens to the following events:
     * 1. channel: notes, event: save:after
     *
     * requests:
     * 1. channel: notes, request: save
     *    to save the changes.
     */
    var Controller = Marionette.Object.extend({

        initialize: function(options) {
            this.options = options;

            _.bindAll(this, 'show', 'redirect');

            // Fetch everything
            Q.all([
                Radio.request('notes', 'get:model:full', options),
                Radio.request('notebooks', 'get:all', _.pick(options, 'profile'))
            ])
            .spread(this.show)
            .catch(function() {
                console.error('Editor error', arguments);
            });

            // Events
            this.listenTo(Radio.channel('notes'), 'update:model', this.redirect);
            this.listenTo(Radio.channel('Confirm'), 'confirm', this.redirect);
            this.listenTo(Radio.channel('Confirm'), 'cancel', this.onConfirmCancel);
        },

        onDestroy: function() {
            this.stopListening();
            this.view.trigger('destroy');
        },

        show: function(note, notebooks) {
            var notebooksView;
            note = note[0];

            // Set document title
            Radio.request('global', 'set:title', note.get('title'));

            // Use behaviours that are appropriate for a device.
            if (Radio.request('global', 'platform') === 'mobile') {
                delete View.prototype.behaviors.Desktop;
            }
            else {
                delete View.prototype.behaviors.Mobile;
            }

            this.view = new View({
                model     : note,
                profile   : note.profileId
            });

            // Show the view and trigger an event
            Radio.request('global', 'region:show', 'content', this.view);
            this.view.trigger('rendered');

            /*
             * Resolve the notebook ID.
             * If the current note doesn't have a notebook attached,
             * try to use one from the filter if it specifies a notebook.
             */
            var activeId = note.get('notebookId');
            if (activeId === '0' && this.options.filter === 'notebook') {
                activeId = this.options.query;
            }

            // Show notebooks selector
            notebooksView = new NotebooksView({
                collection : notebooks,
                activeId   : activeId
            });
            this.view.notebooks.show(notebooksView);

            // Listen to view events
            this.listenTo(this.view, 'save', this.save);
            this.listenTo(this.view, 'cancel', this.showConfirm);
        },

        save: function() {
            var self = this;

            return this.getContent()
            .then(function(data) {
                if (data.title === '') {
                    var title = i18n.t('New Note');
                    data.title = title;
                    Radio.request('global', 'set:title', title);
                }
                return Radio.request('notes', 'save', self.view.model, data);
            })
            .fail(function(e) {
                console.error('Error', e);
            });
        },

        getContent: function() {
            var self = this;

            return Radio.request('editor', 'get:data')
            .then(function(data) {
                return _.extend(data, {
                    title      : self.view.ui.title.val().trim(),
                    notebookId : self.view.notebooks.currentView.ui.notebookId.val().trim(),
                });
            });
        },

        /**
         * Warn a user that they have made some changes.
         */
        showConfirm: function() {
            var self = this;

            return this.getContent()
            .then(function(data) {
                var model = self.view.model.pick('title', 'content', 'notebookId');
                data      = _.pick(data, 'title', 'content', 'notebookId');

                // To check if they are equal
                model.content = _.unescape(model.content);
                model.title   = _.unescape(model.title);

                if (_.isEqual(model, data)) {
                    return self.redirect();
                }

                Radio.request('Confirm', 'start', $.t('You have unsaved changes.'));
            })
            .fail(function(e) {
                console.error('form ShowConfirm', e);
            });
        },

        redirect: function() {
            if (!this.view.getOption('redirect')) {
                return;
            }

            // Stop the module and navigate back
            Radio.trigger('notesForm', 'stop');
            Radio.request('uri', 'back');
        },

        onConfirmCancel: function() {
            // Rebind keybindings again because TW bootstrap modal overrites ESC.
            this.view.trigger('bind:keys');
            this.view.options.isClosed = false;

            if (this.view.options.focus !== 'editor') {
                return this.view.ui[this.view.options.focus].focus();
            }
            Radio.trigger('editor', 'focus');
        }

    });

    return Controller;
});
<|endoftext|>


<commit_before>// @ngInject
export default function appstoreRoutes($stateProvider) {
  $stateProvider
    .state('appstore', {
      url: '/appstore/',
      abstract: true,
      templateUrl: 'views/appstore/base.html',
      data: {
        auth: true,
        pageTitle: 'Service store',
        workspace: 'project'
      }
    })

    .state('appstore.store', {
      url: ':category/',
      templateUrl: 'views/appstore/store.html',
      controller: 'AppStoreController',
      controllerAs: 'AppStore'
    })

    .state('appstore.offering', {
      url: 'offering/:category/',
      templateUrl: '<appstore-offering></appstore-offering>',
    })

    .state('compare', {
      url: '/compare/',
      templateUrl: 'views/project/base.html',
      abstract: true,
      data: {
        auth: true,
        pageTitle: 'Compare flavors',
      }
    })

    .state('compare.compare', {
      url: '',
      templateUrl: 'views/compare/table.html',
    })
}
<commit_msg>Fix typo.<commit_after>// @ngInject
export default function appstoreRoutes($stateProvider) {
  $stateProvider
    .state('appstore', {
      url: '/appstore/',
      abstract: true,
      templateUrl: 'views/appstore/base.html',
      data: {
        auth: true,
        pageTitle: 'Service store',
        workspace: 'project'
      }
    })

    .state('appstore.store', {
      url: ':category/',
      templateUrl: 'views/appstore/store.html',
      controller: 'AppStoreController',
      controllerAs: 'AppStore'
    })

    .state('appstore.offering', {
      url: 'offering/:category/',
      template: '<appstore-offering></appstore-offering>',
    })

    .state('compare', {
      url: '/compare/',
      templateUrl: 'views/project/base.html',
      abstract: true,
      data: {
        auth: true,
        pageTitle: 'Compare flavors',
      }
    })

    .state('compare.compare', {
      url: '',
      templateUrl: 'views/compare/table.html',
    })
}
<|endoftext|>