"].join("")),this.meridium.insertAfter(this.lists[this.lists.length-1].$el)},flip:function(a,b){this.meridiumText!=this.getMeridium()&&(this.meridiumText=this.getMeridium(),this.meridium.find("a").html(this.meridiumText)),this.base(this.factory.time.getTime(!1,this.showSeconds),b)},getMeridium:function(){return(new Date).getHours()>=12?"PM":"AM"},isPM:function(){return"PM"==this.getMeridium()?!0:!1},isAM:function(){return"AM"==this.getMeridium()?!0:!1}})}(jQuery),function(){FlipClock.Lang.Arabic={years:"سنوات",months:"شهور",days:"أيام",hours:"ساعات",minutes:"دقائق",seconds:"ثواني"},FlipClock.Lang.ar=FlipClock.Lang.Arabic,FlipClock.Lang["ar-ar"]=FlipClock.Lang.Arabic,FlipClock.Lang.arabic=FlipClock.Lang.Arabic}(jQuery),function(){FlipClock.Lang.Danish={years:"År",months:"Måneder",days:"Dage",hours:"Timer",minutes:"Minutter",seconds:"Sekunder"},FlipClock.Lang.da=FlipClock.Lang.Danish,FlipClock.Lang["da-dk"]=FlipClock.Lang.Danish,FlipClock.Lang.danish=FlipClock.Lang.Danish}(jQuery),function(){FlipClock.Lang.German={years:"Jahre",months:"Monate",days:"Tage",hours:"Stunden",minutes:"Minuten",seconds:"Sekunden"},FlipClock.Lang.de=FlipClock.Lang.German,FlipClock.Lang["de-de"]=FlipClock.Lang.German,FlipClock.Lang.german=FlipClock.Lang.German}(jQuery),function(){FlipClock.Lang.English={years:"Years",months:"Months",days:"Days",hours:"Hours",minutes:"Minutes",seconds:"Seconds"},FlipClock.Lang.en=FlipClock.Lang.English,FlipClock.Lang["en-us"]=FlipClock.Lang.English,FlipClock.Lang.english=FlipClock.Lang.English}(jQuery),function(){FlipClock.Lang.Spanish={years:"Años",months:"Meses",days:"DÍas",hours:"Horas",minutes:"Minutos",seconds:"Segundo"},FlipClock.Lang.es=FlipClock.Lang.Spanish,FlipClock.Lang["es-es"]=FlipClock.Lang.Spanish,FlipClock.Lang.spanish=FlipClock.Lang.Spanish}(jQuery),function(){FlipClock.Lang.Finnish={years:"Vuotta",months:"Kuukautta",days:"Päivää",hours:"Tuntia",minutes:"Minuuttia",seconds:"Sekuntia"},FlipClock.Lang.fi=FlipClock.Lang.Finnish,FlipClock.Lang["fi-fi"]=FlipClock.Lang.Finnish,FlipClock.Lang.finnish=FlipClock.Lang.Finnish}(jQuery),function(){FlipClock.Lang.French={years:"Ans",months:"Mois",days:"Jours",hours:"Heures",minutes:"Minutes",seconds:"Secondes"},FlipClock.Lang.fr=FlipClock.Lang.French,FlipClock.Lang["fr-ca"]=FlipClock.Lang.French,FlipClock.Lang.french=FlipClock.Lang.French}(jQuery),function(){FlipClock.Lang.Italian={years:"Anni",months:"Mesi",days:"Giorni",hours:"Ore",minutes:"Minuti",seconds:"Secondi"},FlipClock.Lang.it=FlipClock.Lang.Italian,FlipClock.Lang["it-it"]=FlipClock.Lang.Italian,FlipClock.Lang.italian=FlipClock.Lang.Italian}(jQuery),function(){FlipClock.Lang.Latvian={years:"Gadi",months:"Mēneši",days:"Dienas",hours:"Stundas",minutes:"Minūtes",seconds:"Sekundes"},FlipClock.Lang.lv=FlipClock.Lang.Latvian,FlipClock.Lang["lv-lv"]=FlipClock.Lang.Latvian,FlipClock.Lang.latvian=FlipClock.Lang.Latvian}(jQuery),function(){FlipClock.Lang.Dutch={years:"Jaren",months:"Maanden",days:"Dagen",hours:"Uren",minutes:"Minuten",seconds:"Seconden"},FlipClock.Lang.nl=FlipClock.Lang.Dutch,FlipClock.Lang["nl-be"]=FlipClock.Lang.Dutch,FlipClock.Lang.dutch=FlipClock.Lang.Dutch}(jQuery),function(){FlipClock.Lang.Norwegian={years:"År",months:"Måneder",days:"Dager",hours:"Timer",minutes:"Minutter",seconds:"Sekunder"},FlipClock.Lang.no=FlipClock.Lang.Norwegian,FlipClock.Lang.nb=FlipClock.Lang.Norwegian,FlipClock.Lang["no-nb"]=FlipClock.Lang.Norwegian,FlipClock.Lang.norwegian=FlipClock.Lang.Norwegian}(jQuery),function(){FlipClock.Lang.Portuguese={years:"Anos",months:"Meses",days:"Dias",hours:"Horas",minutes:"Minutos",seconds:"Segundos"},FlipClock.Lang.pt=FlipClock.Lang.Portuguese,FlipClock.Lang["pt-br"]=FlipClock.Lang.Portuguese,FlipClock.Lang.portuguese=FlipClock.Lang.Portuguese}(jQuery),function(){FlipClock.Lang.Russian={years:"лет",months:"месяцев",days:"дней",hours:"часов",minutes:"минут",seconds:"секунд"},FlipClock.Lang.ru=FlipClock.Lang.Russian,FlipClock.Lang["ru-ru"]=FlipClock.Lang.Russian,FlipClock.Lang.russian=FlipClock.Lang.Russian}(jQuery),function(){FlipClock.Lang.Swedish={years:"År",months:"Månader",days:"Dagar",hours:"Timmar",minutes:"Minuter",seconds:"Sekunder"},FlipClock.Lang.sv=FlipClock.Lang.Swedish,FlipClock.Lang["sv-se"]=FlipClock.Lang.Swedish,FlipClock.Lang.swedish=FlipClock.Lang.Swedish}(jQuery);
\ No newline at end of file
diff --git a/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/CarbonDioxide.png b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/CarbonDioxide.png
new file mode 100644
index 0000000..5e8674a
Binary files /dev/null and b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/CarbonDioxide.png differ
diff --git a/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/Humidity.png b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/Humidity.png
new file mode 100644
index 0000000..a21cc57
Binary files /dev/null and b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/Humidity.png differ
diff --git a/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/Lux.png b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/Lux.png
new file mode 100644
index 0000000..fe9b40a
Binary files /dev/null and b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/Lux.png differ
diff --git a/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/SB_logo.png b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/SB_logo.png
new file mode 100644
index 0000000..bb8e817
Binary files /dev/null and b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/SB_logo.png differ
diff --git a/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/Temperature.png b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/Temperature.png
new file mode 100644
index 0000000..c37f37c
Binary files /dev/null and b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/Temperature.png differ
diff --git a/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/censis_logo_white.png b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/censis_logo_white.png
new file mode 100644
index 0000000..10631a9
Binary files /dev/null and b/mdot/mDotServer.censis/mDotServer.censis/app/lib/images/censis_logo_white.png differ
diff --git a/mdot/mDotServer.censis/mDotServer.censis/app/lib/jquery.flatWeatherPlugin.js b/mdot/mDotServer.censis/mDotServer.censis/app/lib/jquery.flatWeatherPlugin.js
new file mode 100644
index 0000000..9fe710c
--- /dev/null
+++ b/mdot/mDotServer.censis/mDotServer.censis/app/lib/jquery.flatWeatherPlugin.js
@@ -0,0 +1,598 @@
+
+
+// the semi-colon before function invocation is a safety net against concatenated
+// scripts and/or other plugins which may not be closed properly.
+;(function ( $, window, document, undefined ) {
+
+
+ var pluginName = "flatWeatherPlugin";
+
+ // Create the defaults once
+ var defaults = {
+ location: "Waterloo, ON", //city, region
+ country: "Canada", //country
+ displayCityNameOnly: false,
+ api : "openweathermap", //api: yahoo or openweathermap
+ forecast: 5, //number of days to forecast, max 5
+ apikey : "", //optional api key for openweathermap
+ view : "full", //options: simple, today, partial, forecast, full
+ render : true, //render: false if you to make your own markup, true plugin generates markup
+ loadingAnimation: true, //show loading animation
+ //units : "metric" or "imperial" default: "auto"
+ };
+
+ var apiurls = {
+ "openweathermap" : ["http://api.openweathermap.org/data/2.5/weather", "http://api.openweathermap.org/data/2.5/forecast/daily"],
+ "yahoo" : ["https://query.yahooapis.com/v1/public/yql"]
+ };
+
+ // Plugin Constructor
+ function Plugin (element, options ) {
+
+ this.element = element;
+
+ // jQuery has an extend method which merges the contents of two or
+ // more objects, storing the result in the first object. The first object
+ // is generally empty as we don't want to alter the default options for
+ // future instances of the plugin
+ this.settings = $.extend( {}, defaults, options );
+
+ //set units if otherwise not set
+ if (!this.settings.units || this.settings.units == "auto") {
+ //basically just support for auto units of USA
+ this.settings.units = (["united states", "usa", "united states of america", "us"].indexOf(this.settings.country.toLowerCase()) == -1)?"metric":"imperial";
+ }
+
+ //bound forecast to max of 5 days, api won't return more then that
+ this.settings.forecast = Math.min(this.settings.forecast, 5);
+
+ //store plugin name for local reference
+ this._name = pluginName;
+
+ this.once = false;
+
+ //call initilizaiton
+ this.init();
+ };
+
+ // Avoid Plugin.prototype conflicts
+ $.extend(Plugin.prototype, {
+ init: function () {
+ //if you want the pluging to render markup init will do all the work
+ //otherwise you are on your own
+ if (this.settings.render) {
+
+ //if first run show loading icon (if enabled)
+ if (this.settings.loadingAnimation && !this.once) {
+ //add a loading spinner, animated with css
+ this.loading = $("", {"id" : "flatWeatherLoading", "class" : "wi loading"});
+ this.loading.appendTo(this.element);
+ }
+
+ this.fetchWeather().then(this.render, this.error);
+
+ }
+ this.once = true; //init has happened, can be used to prevent some init tasks happening again
+ },
+ fetchWeather: function () {
+ //Fetches the weather from the API with an ajax request
+ //Returns a promise of (weather object, this)
+
+ //scope of this for nested functions
+ var that = this;
+
+ //create promise
+ var promise = new $.Deferred();
+
+
+ //data params to send along with each ajax request
+ //array because some apis may require multiple requests
+ //params[0] is sent to apiurls[api][0] and so on
+ var params = [];
+
+ //build location query string
+ var location = this.settings.location + " " + this.settings.country;
+
+ //build the paramaters required for specified api
+ if (this.settings.api == "openweathermap") {
+ //openweathermap requires two requests: one for today, another for the forecast.
+
+ //see openweathermap api for details on params passed to api
+
+ //the first request grabs the daily forecast
+ var parameters = {};
+ parameters.q = location;
+ parameters.units = this.settings.units;
+ if(this.settings.apikey) parameters.appid = this.settings.apikey;
+
+ params.push(parameters); //params for first request url
+
+ //same as the first with added cnt forecast paramater in days
+ //the second request grabs the forecast for the number of days requested
+ parameters.cnt = this.settings.forecast + 1; //plus one to include today
+ params.push(parameters); //params for second request url
+
+ }
+ else if (this.settings.api == "yahoo") {
+ //yahoo weather uses c and f for metric/imperial unit identifiers,
+ //convert our stored text string to match what they expect
+ var u = (this.settings.units == "metric")?"c":"f";
+
+ //see yahoo yql weather api for details on params passed to api
+ var parameters = {};
+ parameters.q = "select * from weather.forecast where woeid in (select woeid from geo.places(1) where text='" + location + "') AND u='" + u +"'";
+ parameters.env = "store://datatables.org/alltableswithkeys"; //some sort of api version info... because yahoo.
+ parameters.format = "json";
+ params.push(parameters);
+
+ }
+
+
+ //for each request send the associated paramaters, then when all are done render all data
+ var requests = []; //requests sent
+ //for each url in apiurls for the api set, send the associated params to it in an ajax request
+ for (var i = 0; i < apiurls[this.settings.api].length; i++) {
+ //jquery ajax request promise
+ requests.push($.get(apiurls[this.settings.api][i], params[i]));
+ }
+
+ //when all request promises are done
+ $.when.apply(this, requests)
+ .done(function(){
+
+ //grab the result from the promise as passed by arguments
+ //and convert it to an actual array with slice
+ var args = Array.prototype.slice.call(arguments);
+
+ //remove a layer of nesting for easier use
+ //the [0] element is the result, the rest of the array is
+ //info about the ajax request and promise that we can toss
+ if (requests.length > 1) {
+ //if multiple requests, each promise result of the ajax request is part of an array
+ args = args.map(function(val) { return val[0]});
+ }
+ else {
+ args = args[0];
+ }
+
+
+ //check for results that returned http 200 but had errors from api
+ if (that.settings.api == "openweathermap" && !(args[0].cod == "200" && args[1].cod == "200")) {
+ console.log("Error interacting with the openweathermap api see error object below for details:");
+ console.log(args);
+ promise.reject(args, that);
+ }
+ else if (that.settings.api == "yahoo" && (args.query.count == 0 || args.query.results.channel.description == "Yahoo! Weather Error")) {
+ //yahoo weather really should return a better error checking method.
+ console.log("Error interacting with the yahoo api see error object below for details:");
+ console.log(args);
+ promise.reject(args, that);
+ }
+ else {
+
+ //now take that fancy api data and map it to a common format with datamapper function
+ var weather = datamapper(args, that.settings);
+
+ that._weather = weather; //store it on the instance
+
+ $.data( that.element, "weather", weather); //and store it on the DOM for general use
+
+ promise.resolve(weather, that);
+
+ }
+
+
+ })
+ .fail(function(error){
+ //TODO draw fails.
+ console.log("fail");
+ promise.reject(error, that);
+ });
+
+ return promise;
+
+ },
+ error : function(error, context) {
+
+ if (!context) {
+ //if called directly and not via plugin we need to set context to this vs passed when a promise
+ context = this;
+ }
+
+ if (context.settings.loadingAnimation && context.settings.render) {
+ context.loading.remove(); //remove loading spinner
+ }
+
+ if (context.settings.api == "openweathermap") {
+ if (error[0].cod != "200") {
+ error = error[0].cod + " " + error[0].message + ". See console log for details.";
+ }
+ else {
+ error = error[1] + " See console log for details.";
+ }
+ }
+ else if (context.settings.api == "yahoo") {
+
+ if (error.query.results) {
+ error = "Error: " + error.query.results.channel.item.title + ". See console log for details.";
+ }
+ else {
+ error = "Error: no results. See console log for details.";
+ }
+ }
+
+ var div = $("", {"class": "flatWeatherPlugin " + context.settings.view});
+ $("").text("Error").appendTo(div);
+ $("").text(error).appendTo(div);
+ $(context.element).html(div); //recall that this.element is set in plugin constructor
+ return $(context.element);
+ },
+ //Generates the DOM elements
+ render : function (weather, context) {
+
+ if (!context) {
+ //if called directly and not via plugin we need to set context to this vs passed when a promise
+ context = this;
+ weather = this._weather;
+ }
+
+ //string showing degree symbol + F or C
+ var degrees = context.settings.units == "metric"?"°C":"°F";
+
+ if (context.settings.loadingAnimation && context.settings.render) {
+ context.loading.remove(); //remove loading spinner
+ }
+
+ //Now that we have everything lets make a dom fragment of our data.
+ //Then append that fragment once to the dom once its all made.
+ //There is a bunch of if switches for various view options but this
+ //is mostly self-explainatory dom generating code from the weather object
+ var div = $("", {"class": "flatWeatherPlugin " + context.settings.view});
+
+ if (context.settings.displayCityNameOnly) {
+ $("").text(weather.city).appendTo(div);
+ }
+ else {
+ $("").text(weather.location).appendTo(div);
+ }
+
+
+ if (context.settings.view != "forecast") {
+ var today = $("", {"class": "wiToday"});
+ var iconGroup = $("", {"class": "wiIconGroup"});
+ $("", {"class" : "wi "+ "wi"+weather.today.code}).appendTo(iconGroup);
+ $("", {"class" : "wiText"}).text(weather.today.desc).appendTo(iconGroup);
+ iconGroup.appendTo(today);
+ $("", {"class" : "wiTemperature"}).html(weather.today.temp.now + "" + degrees + "").appendTo(today);
+ today.appendTo(div);
+ }
+
+ if (context.settings.view != "simple") {
+ var detail = $("", {"class": "wiDetail"});
+
+ if (context.settings.view == "partial") {
+ $("", {"class" : "wiDay"}).text(weather.today.day).appendTo(today);
+ }
+
+ if (context.settings.view != "partial") {
+ if (context.settings.view != "today") {
+ $("", {"class" : "wiDay"}).text(weather.today.day).appendTo(detail);
+ }
+ var astro = $("
", {"class": "wiForecasts"});
+ var startingIndex = (context.settings.view == "forecast")?0:1;
+ //index should include today for forecast view exclude for other views
+ for (var i = startingIndex; i < weather.forecast.length; i++) {
+ var day = $("", {"class" : "wiDay"}).html(""+weather.forecast[i].day+"").appendTo(forecast);
+ var sub = $("
", {"class" : "wiForecast"}).appendTo(day);
+ $("", {"class" : "wi "+ "wi"+ weather.forecast[i].code}).appendTo(sub);
+ $("", {"class" : "wiMax"}).html(weather.forecast[i].temp.max + "" + degrees + "").appendTo(sub);
+ $("", {"class" : "wiMin"}).html(weather.forecast[i].temp.min + "" + degrees + "").appendTo(sub);
+ }
+ forecast.appendTo(div);
+ }
+ }
+
+
+ //now append our dom fragment to the target element
+ $(context.element).html(div); //recall that this.element is set in plugin constructor
+
+ return $(context.element);
+
+ }
+
+ });
+
+
+ //jQuery Constructor
+ // A lightweight plugin wrapper on the jquery fn constructor,
+ // preventing against multiple instantiations on the same element
+ $.fn[pluginName] = function ( options, args ) {
+ if ($.isFunction(Plugin.prototype[options])) {
+ //enable function access via .flatWeatherPlugin('function', 'args')
+ //grab the plugin instance from the dom reference and call function with any args
+ //return the results of the
+ return this.data("plugin_" + pluginName)[options](args);
+ }
+ //return this for jquery chainability
+ return this.each(function() {
+ //check if plugin has been attached to the dom
+ if (!$.data(this, "plugin_" + pluginName)) {
+ var plugin = new Plugin(this, options); //call constructor
+ return $.data(this, "plugin_" + pluginName, plugin); //attach plugin instance to the dom data
+ }
+ });
+ };
+
+
+ /*
+ //datamapper converts raw aka dirty un-standardize data from either api
+ //into a unified format for easier use as follows:
+ {
+ location : String, //as returned back from api
+ today : {
+ temp : {
+ //temperatures are in units requested from api
+ now : Number, ex. 18
+ min : Number, ex. 24
+ max : Number ex. 12
+ },
+ desc : String, ex. "Partly Cloudy"
+ code : Number, ex. "801" see css or weather codes for meaning
+ wind : {
+ speed : 4, //either km/h or mph
+ deg : Number, //direction in degrees from North
+ },
+ pressure : Number, //barometric pressure
+ humidity : Number, //% humidity
+ sunrise : Time,
+ sunset : Time,
+ day : String,
+
+ },
+ forecast : [{Day: String, code:Number, desc: String, temp : {min:number, max:number}}]
+ }
+ //note: input data is in an array of the returned api result request(s) in the same order as setup in the apiurls
+ //All data manipulation and cleaning up happens below
+ //making this was tedious.
+ */
+ function datamapper (input, settings) {
+
+ var out = {}; //map input to out
+
+ if (settings.api == "openweathermap") {
+
+ //data[0] is current weather, data[1] is forecast
+ if (input[0].name != "") {
+ out.location = input[0].name + ", " + input[0].sys.country;
+ out.city = input[0].name;
+ }
+ else if (input[1].city.name != ""){ //sometimes the api doesn't return a location. weird, try the name from second request
+ out.location = input[1].city.name + ", " + input[1].city.country;
+ out.city = input[1].city.name;
+ }
+ else { //still no location? fall back to settings
+ out.location = settings.location + ", " + settings.country;
+ out.city = settings.location;
+ }
+
+ out.today = {};
+ out.today.temp = {};
+ out.today.temp.now = Math.round(input[0].main.temp);
+ out.today.temp.min = Math.round(input[0].main.temp_min);
+ out.today.temp.max = Math.round(input[0].main.temp_max);
+
+ out.today.desc = input[0].weather[0].description.capitalize();
+ out.today.code = input[0].weather[0].id;
+ //no weather id code remapping needed, we will use this as our default weather code system
+ //and convert all other codes to the openweathermap weather code format
+
+ out.today.wind = input[0].wind;
+ out.today.humidity = input[0].main.humidity;
+ out.today.pressure = input[0].main.pressure;
+ out.today.sunrise = epochToHours(input[0].sys.sunrise);
+ out.today.sunset = epochToHours(input[0].sys.sunset);
+
+ out.today.day = getDayString(new Date());
+
+ out.forecast = [];
+ for (var i = 0; i < settings.forecast; i++) {
+ var forecast = {};
+ forecast.day = getDayString(new Date(input[1].list[i].dt * 1000)); //api time is in unix epoch
+ forecast.code = input[1].list[i].weather[0].id;
+ forecast.desc = input[1].list[i].weather[0].description.capitalize();
+ forecast.temp = {max: Math.round(input[1].list[i].temp.max), min: Math.round(input[1].list[i].temp.min)}
+ out.forecast.push(forecast);
+ }
+
+ }
+ else if (settings.api == "yahoo") {
+
+ //key = yahoo code, value = standard code (based on openweathermap codes)
+ var codes = {
+ 0 : "900", //tornado
+ 1 : "901", //tropical storm
+ 2 : "902", //hurricane
+ 3 : "212", //severe thunderstorms
+ 4 : "200", //thunderstorms
+ 5 : "616", //mixed rain and snow
+ 6 : "612", //mixed rain and sleet
+ 7 : "611", //mixed snow and sleet
+ 8 : "511", //freezing drizzle
+ 9 : "301", //drizzle
+ 10 : "511", //freezing rain
+ 11 : "521", //showers
+ 12 : "521", //showers
+ 13 : "600", //snow flurries
+ 14 : "615", //light snow showers
+ 15 : "601", //blowing snow
+ 16 : "601", //snow
+ 17 : "906", //hail
+ 18 : "611", //sleet
+ 19 : "761", //dust
+ 20 : "741", //foggy
+ 21 : "721", //haze
+ 22 : "711", //smoky
+ 23 : "956", //blustery
+ 24 : "954", //windy
+ 25 : "903", //cold
+ 26 : "802", //cloudy
+ 27 : "802", //mostly cloudy (night)
+ 28 : "802", //mostly cloudy (day)
+ 29 : "802", //partly cloudy (night)
+ 30 : "802", //partly cloudy (day)
+ 31 : "800", //clear (night)
+ 32 : "800", //sunny
+ 33 : "951", //fair (night)
+ 34 : "951", //fair (day)
+ 35 : "906", //mixed rain and hail
+ 36 : "904", //hot
+ 37 : "210", //isolated thunderstorms
+ 38 : "210", //scattered thunderstorms
+ 39 : "210", //scattered thunderstorms
+ 40 : "521", //scattered showers
+ 41 : "602", //heavy snow
+ 42 : "621", //scattered snow showers
+ 43 : "602", //heavy snow
+ 44 : "802", //partly cloudy
+ 45 : "201", //thundershowers
+ 46 : "621", //snow showers
+ 47 : "210", //isolated thundershowers
+ 3200: "951", //not available... alright... lets make that sunny.
+ }
+
+ input = input.query.results.channel; //get rid of a bunch of silly yahoo nested objects;
+
+ out.location = input.location.city + ", " + input.location.country;
+ out.city = input.location.city;
+
+ out.today = {};
+ out.today.temp = {};
+ out.today.temp.now = Math.round(input.item.condition.temp);
+ out.today.temp.min = Math.round(input.item.forecast[0].low);
+ out.today.temp.max = Math.round(input.item.forecast[0].high);
+
+ out.today.desc = input.item.condition.text.capitalize();
+ out.today.code = codes[input.item.condition.code]; //map weather code
+
+ out.today.wind = {};
+ out.today.wind.speed = input.wind.speed;
+ out.today.wind.deg = input.wind.direction;
+ out.today.humidity = input.atmosphere.humidity;
+ out.today.pressure = input.atmosphere.pressure;
+ out.today.sunrise = input.astronomy.sunrise.toUpperCase();
+ out.today.sunset = input.astronomy.sunset.toUpperCase();
+
+ out.today.day = getDayString(new Date());
+
+ out.forecast = [];
+ //grab only the number of forecast days desired from settings
+ for (var i = 0; i < settings.forecast; i++) {
+ var forecast = {};
+ forecast.day = getDayString(new Date(input.item.forecast[i].date));
+ forecast.code = codes[input.item.forecast[i].code]; //map weather code
+ forecast.desc = input.item.forecast[i].text.capitalize();
+ forecast.temp = {max: Math.round(input.item.forecast[i].high), min: Math.round(input.item.forecast[i].low)}
+ out.forecast.push(forecast);
+ }
+ }
+
+ return out;
+
+ };
+
+ //Helpers
+ String.prototype.capitalize = function() {
+ return this.charAt(0).toUpperCase() + this.slice(1);
+ };
+
+ //take a date object and return a day string
+ function getDayString(date) {
+ return ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'][date.getDay()];
+ };
+
+ //converts and epoch time in seconds to hours in the day
+ function epochToHours(date) {
+ date = new Date(date * 1000);
+ var hours = date.getHours();
+ var minutes = date.getMinutes();
+ var ampm = hours >= 12 ? 'PM' : 'AM';
+ hours = hours % 12;
+ hours = hours ? hours : 12; // the hour '0' should be '12'
+ minutes = minutes < 10 ? '0'+minutes : minutes;
+ var strTime = hours + ':' + minutes + ' ' + ampm;
+ return strTime;
+ };
+
+ //Takes wind speed, direction in degrees and units
+ //and returns a string ex. (8.5, 270, "metric") returns "W 8.5 km/h"
+ function formatWind(speed, degrees, units) {
+ var wd = degrees;
+ if ((wd >= 0 && wd <= 11.25) || (wd > 348.75 && wd <= 360)) {
+ wd = "N";
+ }
+ else if (wd > 11.25 && wd <= 33.75){
+ wd = "NNE";
+ }
+ else if (wd > 33.75 && wd <= 56.25){
+ wd = "NE";
+ }
+ else if (wd > 56.25 && wd <= 78.75){
+ wd = "ENE";
+ }
+ else if (wd > 78.75 && wd <= 101.25){
+ wd = "E";
+ }
+ else if (wd > 101.25 && wd <= 123.75){
+ wd = "ESE";
+ }
+ else if (wd > 123.75 && wd <= 146.25){
+ wd = "SE";
+ }
+ else if (wd > 146.25 && wd <= 168.75){
+ wd = "SSE";
+ }
+ else if (wd > 168.75 && wd <= 191.25){
+ wd = "S";
+ }
+ else if (wd > 191.25 && wd <= 213.75){
+ wd = "SSW";
+ }
+ else if (wd > 213.75 && wd <= 236.25){
+ wd = "SW";
+ }
+ else if (wd > 236.25 && wd <= 258.75){
+ wd = "WSW";
+ }
+ else if (wd > 258.75 && wd <= 281.25){
+ wd = "W";
+ }
+ else if (wd > 281.25 && wd <= 303.75){
+ wd = "WNW";
+ }
+ else if (wd > 303.75 && wd <= 326.25){
+ wd = "NW";
+ }
+ else if (wd > 326.25 && wd <= 348.75){
+ wd = "NNW";
+ }
+ var speedUnits = (units == "metric")?"km/h":"mph";
+ return wd + " " + speed + " " + speedUnits;
+ };
+
+
+})( jQuery, window, document );
diff --git a/mdot/mDotServer.censis/mDotServer.censis/app/lib/jquery.flatWeatherPlugin.min.js b/mdot/mDotServer.censis/mDotServer.censis/app/lib/jquery.flatWeatherPlugin.min.js
new file mode 100644
index 0000000..1cc2e8e
--- /dev/null
+++ b/mdot/mDotServer.censis/mDotServer.censis/app/lib/jquery.flatWeatherPlugin.min.js
@@ -0,0 +1,3 @@
+//flatWeatherJqueryPlugin min
+//2014-10-21
+(function(e,t,n,r){function u(t,n){this.element=t;this.settings=e.extend({},s,n);if(!this.settings.units||this.settings.units=="auto"){this.settings.units=["united states","usa","united states of america","us"].indexOf(this.settings.country.toLowerCase())==-1?"metric":"imperial"}this.settings.forecast=Math.min(this.settings.forecast,5);this._name=i;this.once=false;this.init()}function a(e,t){var n={};if(t.api=="openweathermap"){if(e[0].name!=""){n.location=e[0].name+", "+e[0].sys.country;n.city=e[0].name}else if(e[1].city.name!=""){n.location=e[1].city.name+", "+e[1].city.country;n.city=e[1].city.name}else{n.location=t.location+", "+t.country;n.city=t.location}n.today={};n.today.temp={};n.today.temp.now=Math.round(e[0].main.temp);n.today.temp.min=Math.round(e[0].main.temp_min);n.today.temp.max=Math.round(e[0].main.temp_max);n.today.desc=e[0].weather[0].description.capitalize();n.today.code=e[0].weather[0].id;n.today.wind=e[0].wind;n.today.humidity=e[0].main.humidity;n.today.pressure=e[0].main.pressure;n.today.sunrise=l(e[0].sys.sunrise);n.today.sunset=l(e[0].sys.sunset);n.today.day=f(new Date);n.forecast=[];for(var r=0;r=12?"PM":"AM";t=t%12;t=t?t:12;n=n<10?"0"+n:n;var i=t+":"+n+" "+r;return i}function c(e,t,n){var r=t;if(r>=0&&r<=11.25||r>348.75&&r<=360){r="N"}else if(r>11.25&&r<=33.75){r="NNE"}else if(r>33.75&&r<=56.25){r="NE"}else if(r>56.25&&r<=78.75){r="ENE"}else if(r>78.75&&r<=101.25){r="E"}else if(r>101.25&&r<=123.75){r="ESE"}else if(r>123.75&&r<=146.25){r="SE"}else if(r>146.25&&r<=168.75){r="SSE"}else if(r>168.75&&r<=191.25){r="S"}else if(r>191.25&&r<=213.75){r="SSW"}else if(r>213.75&&r<=236.25){r="SW"}else if(r>236.25&&r<=258.75){r="WSW"}else if(r>258.75&&r<=281.25){r="W"}else if(r>281.25&&r<=303.75){r="WNW"}else if(r>303.75&&r<=326.25){r="NW"}else if(r>326.25&&r<=348.75){r="NNW"}var i=n=="metric"?"km/h":"mph";return r+" "+e+" "+i}var i="flatWeatherPlugin";var s={location:"Waterloo, ON",country:"Canada",displayCityNameOnly:false,api:"openweathermap",forecast:5,apikey:"",view:"full",render:true,loadingAnimation:true};var o={openweathermap:["http://api.openweathermap.org/data/2.5/weather","http://api.openweathermap.org/data/2.5/forecast/daily"],yahoo:["https://query.yahooapis.com/v1/public/yql"]};e.extend(u.prototype,{init:function(){if(this.settings.render){if(this.settings.loadingAnimation&&!this.once){this.loading=e("",{id:"flatWeatherLoading","class":"wi loading"});this.loading.appendTo(this.element)}this.fetchWeather().then(this.render,this.error)}this.once=true},fetchWeather:function(){var t=this;var n=new e.Deferred;var r=[];var i=this.settings.location+" "+this.settings.country;if(this.settings.api=="openweathermap"){var s={};s.q=i;s.units=this.settings.units;if(this.settings.apikey)s.appid=this.settings.apikey;r.push(s);s.cnt=this.settings.forecast+1;r.push(s)}else if(this.settings.api=="yahoo"){var u=this.settings.units=="metric"?"c":"f";var s={};s.q="select * from weather.forecast where woeid in (select woeid from geo.places(1) where text='"+i+"') AND u='"+u+"'";s.env="store://datatables.org/alltableswithkeys";s.format="json";r.push(s)}var f=[];for(var l=0;l1){r=r.map(function(e){return e[0]})}else{r=r[0]}if(t.settings.api=="openweathermap"&&!(r[0].cod=="200"&&r[1].cod=="200")){console.log("Error interacting with the openweathermap api see error object below for details:");console.log(r);n.reject(r,t)}else if(t.settings.api=="yahoo"&&(r.query.count==0||r.query.results.channel.description=="Yahoo! Weather Error")){console.log("Error interacting with the yahoo api see error object below for details:");console.log(r);n.reject(r,t)}else{var i=a(r,t.settings);t._weather=i;e.data(t.element,"weather",i);n.resolve(i,t)}}).fail(function(e){console.log("fail");n.reject(e,t)});return n},error:function(t,n){if(!n){n=this}if(n.settings.loadingAnimation&&n.settings.render){n.loading.remove()}if(n.settings.api=="openweathermap"){if(t[0].cod!="200"){t=t[0].cod+" "+t[0].message+". See console log for details."}else{t=t[1]+" See console log for details."}}else if(n.settings.api=="yahoo"){if(t.query.results){t="Error: "+t.query.results.channel.item.title+". See console log for details."}else{t="Error: no results. See console log for details."}}var r=e("",{"class":"flatWeatherPlugin "+n.settings.view});e("").text("Error").appendTo(r);e("").text(t).appendTo(r);e(n.element).html(r);return e(n.element)},render:function(t,n){if(!n){n=this;t=this._weather}var r=n.settings.units=="metric"?"°C":"°F";if(n.settings.loadingAnimation&&n.settings.render){n.loading.remove()}var i=e("",{"class":"flatWeatherPlugin "+n.settings.view});if(n.settings.displayCityNameOnly){e("").text(t.city).appendTo(i)}else{e("").text(t.location).appendTo(i)}if(n.settings.view!="forecast"){var s=e("",{"class":"wiToday"});var o=e("",{"class":"wiIconGroup"});e("",{"class":"wi "+"wi"+t.today.code}).appendTo(o);e("",{"class":"wiText"}).text(t.today.desc).appendTo(o);o.appendTo(s);e("",{"class":"wiTemperature"}).html(t.today.temp.now+""+r+"").appendTo(s);s.appendTo(i)}if(n.settings.view!="simple"){var u=e("",{"class":"wiDetail"});if(n.settings.view=="partial"){e("",{"class":"wiDay"}).text(t.today.day).appendTo(s)}if(n.settings.view!="partial"){if(n.settings.view!="today"){e("",{"class":"wiDay"}).text(t.today.day).appendTo(u)}var a=e("