From 960ff44b724aa59db757516154c4084d265a58b8 Mon Sep 17 00:00:00 2001 From: buffbears <54551697+buffbears@users.noreply.github.com> Date: Thu, 1 Apr 2021 21:40:58 -0400 Subject: [PATCH] Added Extended Forecast, Daypart + general tweaks --- webroot/audio.js | 231 ++++++++++++++++ webroot/data-manager.js | 114 ++++++++ webroot/date_fns.min.js | 4 + webroot/groupull.js | 75 +++++ webroot/location.js | 179 ++++++++++++ webroot/loops.js | 522 ++++++++++++++++++++++++++++++++++ webroot/main.js | 34 +++ webroot/radar.js | 188 +++++++++++++ webroot/slides-loop.js | 599 ++++++++++++++++++++++++++++++++++++++++ webroot/utils.js | 113 ++++++++ webroot/weather.js | 109 ++++++++ 11 files changed, 2168 insertions(+) create mode 100644 webroot/audio.js create mode 100644 webroot/data-manager.js create mode 100644 webroot/date_fns.min.js create mode 100644 webroot/groupull.js create mode 100644 webroot/location.js create mode 100644 webroot/loops.js create mode 100644 webroot/main.js create mode 100644 webroot/radar.js create mode 100644 webroot/slides-loop.js create mode 100644 webroot/utils.js create mode 100644 webroot/weather.js diff --git a/webroot/audio.js b/webroot/audio.js new file mode 100644 index 0000000..c8be941 --- /dev/null +++ b/webroot/audio.js @@ -0,0 +1,231 @@ +function WeatherAudio() { + + var musicarr = [], + $players = $('
'), + that=this, + mobilePlaying = false; + + (function() { + + $('body').append($players); + + // start the music + buildMusicArray(musicarr); + shuffle(musicarr); + + startPlaying(musicarr, true); + + function buildMusicArray(arr) { + + var musicpath = "music/"; + + // insert track names + for (var i = 1; i<66; i++) { + arr.push(musicpath + "Track " + String('0'+i).slice(-2) + '.mp3'); + } + + } + + })(); + + + function startPlaying(arrPlayList, bLoop) { + + + // only allow one set of players to be created + var myclass = (bLoop ? 'music' : 'voice'); + if ($players.find('.' + myclass).length>0) {return} + + var current=-1, + len = arrPlayList.length, + $player = initPlayer('p1'), + $preloader = initPlayer('p2'), + $myplayers = $players.find('.' + myclass); + + // init the event to output ID3 track info if this is a music play + if (myclass=='music') { + $players.find('.music').bind($.jPlayer.event.play, + function() { // event.jPlayer.status.media + + if (that.playCallback) { + + var mp3url = $(this).data('jPlayer').status.src, + relativeUrl = mp3url.replace('%20',' ').slice(-arrPlayList[current].length); + + // only trigger on current track, do not do on preload play/stop + if (relativeUrl==arrPlayList[current]) { + + ID3.loadTags(mp3url, function() { + var tags = ID3.getAllTags(mp3url); + that.playCallback(tags); //alert(tags.artist + " - " + tags.title + ", " + tags.album); + }); + } + } + } + ); + } else { + // duck the music if we're going to play a vocal + $players.find('.music').jPlayer('volume', 0.30); + } + + // prime the preloader + $preloader.jPlayer("setMedia", {mp3:arrPlayList[0]}); + + playNext(); + + + function playNext() { + + current = nextIndex(); + + if (nextIndex()===null) { + // nothing to preload so don't fire off a playNext after this play + $preloader.unbind($.jPlayer.event.ended); + $preloader.bind($.jPlayer.event.ended, + function() { + $players.find('.music').jPlayer('volume', 0.80); // bring music volume back up + $player.remove(); + $preloader.remove(); + } + ); + swapAndPlay(); + } else { + swapAndPlay(); + + // preload the next track + function doPreload(trackname) { + try { + $preloader.jPlayer("setMedia", {mp3:arrPlayList[nextIndex()]}).jPlayer("play").jPlayer("stop"); + } catch(e) { + setTimeout( function() {doPreload(trackname)}, 500); + } + } + doPreload( arrPlayList[nextIndex()] ); + + } + + function nextIndex() { + var nextI = current+1; + if (nextI'); + $div.jPlayer({ + swfPath: document.baseURI + "jplayer", + preload: 'auto', + ended: playNext + }); + $players.append($div); + return $div; + } + + + + function swapAndPlay() { + // who would think swapping two vars would be so hard? + var $temp1 = $player, + $temp2 = $preloader; + $player = null; $preloader = null; + $player=$temp2; $preloader=$temp1; + + $player.jPlayer("play"); + + $(document).mousedown( function() { + if (!mobilePlaying) { + $player.jPlayer("play"); + mobilePlaying = true; + } + }); + } + + + + } + + + + + // click for debugging or whater you want + $('body').on('click', function(){ + //$player.jPlayer("playHead", 100); + //getWeatherbyLocation(); + }); + + + this.playCallback = {}; + + + // plays the vocal current conditions announcement + this.playCurrentConditions = function (currentConditions) { + + var array2play = ['CC_INTRO' + (Math.floor(Math.random()*2)+1), currentConditions.temp.replace('-', 'M')], + condfile = mapCurrentConditions(currentConditions.code); + + if (condfile) { array2play.push(condfile); } + + $.each(array2play, function(i,v){ + array2play[i] = '/localvocals/' + v + '.mp3'; + }); + + startPlaying(array2play, false); + + function mapCurrentConditions(ccCode){ + return "CC" + {0:"422",1:"EF300",2:"EF300",3:"422",4:"400",5:"500",6:"600",7:"700",8:"800",9:"901",10:"1000",11:"1100",12:"2680",13:"1601",14:"1312",15:"1500",16:"1600",17:"1730",18:"1800",19:"1939",20:"2000",21:"2000",22:"2200",23:"2410",24:"2410",26:"2600",27:"2700",28:"2700",29:"2900",30:"2900",31:"3100",32:"3200",33:"3400",34:"3400",35:"1730",37:"429",38:"429",39:"429",40:"2680",41:"1402",42:"1312",43:"1402",44:"2900",45:"1100",46:"1312",47:"EF3900"}[ccCode]; + } + + } + + + this.playLocalRadar = function() { + startPlaying(['/localvocals/RADAR.mp3'], false); + } + + + +} +var weatherAudio = new WeatherAudio(); + +//ID3 Reader +//https://github.com/aadsm/JavaScript-ID3-Reader +(function(A){if("object"===typeof exports&&"undefined"!==typeof module)module.f=A();else if("function"===typeof define&&define.M)define([],A);else{var g;"undefined"!==typeof window?g=window:"undefined"!==typeof global?g=global:"undefined"!==typeof self?g=self:g=this;g.ID3=A()}})(function(){return function g(l,h,f){function c(b,d){if(!h[b]){if(!l[b]){var e="function"==typeof require&&require;if(!d&&e)return e(b,!0);if(a)return a(b,!0);e=Error("Cannot find module '"+b+"'");throw e.code="MODULE_NOT_FOUND", +e;}e=h[b]={f:{}};l[b][0].call(e.f,function(a){var e=l[b][1][a];return c(e?e:a)},e,e.f,g,l,h,f)}return h[b].f}for(var a="function"==typeof require&&require,b=0;ba&&(a+=65536);return a};this.m=function(a){var b=this.a(a),d=this.a(a+1),m=this.a(a+2);a=this.a(a+3);b=(((b<<8)+d<<8)+m<<8)+a;0>b&&(b+=4294967296);return b};this.w=function(a){var b=this.a(a),d=this.a(a+1);a=this.a(a+2);b=((b<<8)+d<<8)+a;0>b&&(b+=16777216);return b};this.c=function(a,b){for(var d=[],m=a,c=0;mb&&(b=0);a>=blockTotal&&(a=blockTotal-1);return[b,a]}function g(c,f){for(;n[c[0]];)if(c[0]++,c[0]>c[1]){f&&f();return}for(;n[c[1]];)if(c[1]--,c[0]>c[1]){f&&f();return}var h=[c[0]*m,(c[1]+1)*m-1];b(d,function(a){parseInt(a.getResponseHeader("Content-Length"),10)==e&&(c[0]=0,c[1]=blockTotal-1,h[0]=0,h[1]=e-1);a={data:a.W||a.responseText,offset:h[0]};for(var b=c[0];b<=c[1];b++)n[b]= +a;f&&f()},a,h,k,!!f)}var k,l=new h("",0,e),n=[];m=m||2048;c="undefined"===typeof c?0:c;blockTotal=~~((e-1)/m)+1;for(var p in l)l.hasOwnProperty(p)&&"function"===typeof l[p]&&(this[p]=l[p]);this.a=function(a){var b;g(f([a,a]));return(b=n[~~(a/m)])&&"string"==typeof b.data?b.data.charCodeAt(a-b.offset)&255:b&&"unknown"==typeof b.data?IEBinary_getByteAt(b.data,a-b.offset):""};this.i=function(a,b){g(f(a),b)}}(function(){d(f,function(a){a=parseInt(a.getResponseHeader("Content-Length"),10)||-1;c(new e(f, +a))},a)})()}},{"./binaryfile":1,xmlhttprequest:void 0}],3:[function(g,l){var h=g("./binaryfile");l.f=function(f,c){return function(a,b){var m=c||new FileReader;m.onload=function(a){b(new h(a.target.result))};m.readAsBinaryString(f)}}},{"./binaryfile":1}],4:[function(g,l){function h(b){return"ftypM4A"==b.c(4,7)?f:"ID3"==b.c(0,3)?a:c}var f=g("./id4"),c=g("./id3v1"),a=g("./id3v2"),b=g("./bufferedbinaryajax"),m=g("./filereader");"undefined"!==typeof window&&(window.FileAPIReader=m);var d={},e={},r=[0, +7];d.B=function(a){delete e[a]};d.A=function(){e={}};d.H=function(a,d,c){c=c||{};(c.dataReader||b)(a,function(b){b.i(r,function(){var m=h(b);m.u(b,function(){var f=c.tags,h=m.v(b,f),f=e[a]||{},r;for(r in h)h.hasOwnProperty(r)&&(f[r]=h[r]);e[a]=f;d&&d()})})},c.onError)};d.D=function(a){if(!e[a])return null;var b={},d;for(d in e[a])e[a].hasOwnProperty(d)&&(b[d]=e[a][d]);return b};d.G=function(a,b){return e[a]?e[a][b]:null};d.FileAPIReader=m;d.loadTags=d.H;d.getAllTags=d.D;d.getTag=d.G;d.clearTags=d.B; +d.clearAll=d.A;l.f=d},{"./bufferedbinaryajax":2,"./filereader":3,"./id3v1":5,"./id3v2":6,"./id4":8}],5:[function(g,l){var h={},f="Blues;Classic Rock;Country;Dance;Disco;Funk;Grunge;Hip-Hop;Jazz;Metal;New Age;Oldies;Other;Pop;R&B;Rap;Reggae;Rock;Techno;Industrial;Alternative;Ska;Death Metal;Pranks;Soundtrack;Euro-Techno;Ambient;Trip-Hop;Vocal;Jazz+Funk;Fusion;Trance;Classical;Instrumental;Acid;House;Game;Sound Clip;Gospel;Noise;AlternRock;Bass;Soul;Punk;Space;Meditative;Instrumental Pop;Instrumental Rock;Ethnic;Gothic;Darkwave;Techno-Industrial;Electronic;Pop-Folk;Eurodance;Dream;Southern Rock;Comedy;Cult;Gangsta;Top 40;Christian Rap;Pop/Funk;Jungle;Native American;Cabaret;New Wave;Psychadelic;Rave;Showtunes;Trailer;Lo-Fi;Tribal;Acid Punk;Acid Jazz;Polka;Retro;Musical;Rock & Roll;Hard Rock;Folk;Folk-Rock;National Folk;Swing;Fast Fusion;Bebob;Latin;Revival;Celtic;Bluegrass;Avantgarde;Gothic Rock;Progressive Rock;Psychedelic Rock;Symphonic Rock;Slow Rock;Big Band;Chorus;Easy Listening;Acoustic;Humour;Speech;Chanson;Opera;Chamber Music;Sonata;Symphony;Booty Bass;Primus;Porn Groove;Satire;Slow Jam;Club;Tango;Samba;Folklore;Ballad;Power Ballad;Rhythmic Soul;Freestyle;Duet;Punk Rock;Drum Solo;Acapella;Euro-House;Dance Hall".split(";"); +h.u=function(c,a){var b=c.l();c.i([b-128-1,b],a)};h.v=function(c){var a=c.l()-128;if("TAG"==c.c(a,3)){var b=c.c(a+3,30).replace(/\0/g,""),m=c.c(a+33,30).replace(/\0/g,""),d=c.c(a+63,30).replace(/\0/g,""),e=c.c(a+93,4).replace(/\0/g,"");if(0==c.a(a+97+28))var h=c.c(a+97,28).replace(/\0/g,""),g=c.a(a+97+29);else h="",g=0;c=c.a(a+97+30);return{version:"1.1",title:b,artist:m,album:d,year:e,comment:h,track:g,genre:255>c?f[c]:""}}return{}};l.f=h},{}],6:[function(g,l){function h(a,c){var d=c.a(a),e=c.a(a+ +1),f=c.a(a+2);return c.a(a+3)&127|(f&127)<<7|(e&127)<<14|(d&127)<<21}var f=g("./id3v2frames");f.frames={BUF:"Recommended buffer size",CNT:"Play counter",COM:"Comments",CRA:"Audio encryption",CRM:"Encrypted meta frame",ETC:"Event timing codes",EQU:"Equalization",GEO:"General encapsulated object",IPL:"Involved people list",LNK:"Linked information",MCI:"Music CD Identifier",MLL:"MPEG location lookup table",PIC:"Attached picture",POP:"Popularimeter",REV:"Reverb",RVA:"Relative volume adjustment",SLT:"Synchronized lyric/text", +STC:"Synced tempo codes",TAL:"Album/Movie/Show title",TBP:"BPM (Beats Per Minute)",TCM:"Composer",TCO:"Content type",TCR:"Copyright message",TDA:"Date",TDY:"Playlist delay",TEN:"Encoded by",TFT:"File type",TIM:"Time",TKE:"Initial key",TLA:"Language(s)",TLE:"Length",TMT:"Media type",TOA:"Original artist(s)/performer(s)",TOF:"Original filename",TOL:"Original Lyricist(s)/text writer(s)",TOR:"Original release year",TOT:"Original album/Movie/Show title",TP1:"Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group", +TP2:"Band/Orchestra/Accompaniment",TP3:"Conductor/Performer refinement",TP4:"Interpreted, remixed, or otherwise modified by",TPA:"Part of a set",TPB:"Publisher",TRC:"ISRC (International Standard Recording Code)",TRD:"Recording dates",TRK:"Track number/Position in set",TSI:"Size",TSS:"Software/hardware and settings used for encoding",TT1:"Content group description",TT2:"Title/Songname/Content description",TT3:"Subtitle/Description refinement",TXT:"Lyricist/text writer",TXX:"User defined text information frame", +TYE:"Year",UFI:"Unique file identifier",ULT:"Unsychronized lyric/text transcription",WAF:"Official audio file webpage",WAR:"Official artist/performer webpage",WAS:"Official audio source webpage",WCM:"Commercial information",WCP:"Copyright/Legal information",WPB:"Publishers official webpage",WXX:"User defined URL link frame",AENC:"Audio encryption",APIC:"Attached picture",COMM:"Comments",COMR:"Commercial frame",ENCR:"Encryption method registration",EQUA:"Equalization",ETCO:"Event timing codes",GEOB:"General encapsulated object", +GRID:"Group identification registration",IPLS:"Involved people list",LINK:"Linked information",MCDI:"Music CD identifier",MLLT:"MPEG location lookup table",OWNE:"Ownership frame",PRIV:"Private frame",PCNT:"Play counter",POPM:"Popularimeter",POSS:"Position synchronisation frame",RBUF:"Recommended buffer size",RVAD:"Relative volume adjustment",RVRB:"Reverb",SYLT:"Synchronized lyric/text",SYTC:"Synchronized tempo codes",TALB:"Album/Movie/Show title",TBPM:"BPM (beats per minute)",TCOM:"Composer",TCON:"Content type", +TCOP:"Copyright message",TDAT:"Date",TDLY:"Playlist delay",TENC:"Encoded by",TEXT:"Lyricist/Text writer",TFLT:"File type",TIME:"Time",TIT1:"Content group description",TIT2:"Title/songname/content description",TIT3:"Subtitle/Description refinement",TKEY:"Initial key",TLAN:"Language(s)",TLEN:"Length",TMED:"Media type",TOAL:"Original album/movie/show title",TOFN:"Original filename",TOLY:"Original lyricist(s)/text writer(s)",TOPE:"Original artist(s)/performer(s)",TORY:"Original release year",TOWN:"File owner/licensee", +TPE1:"Lead performer(s)/Soloist(s)",TPE2:"Band/orchestra/accompaniment",TPE3:"Conductor/performer refinement",TPE4:"Interpreted, remixed, or otherwise modified by",TPOS:"Part of a set",TPUB:"Publisher",TRCK:"Track number/Position in set",TRDA:"Recording dates",TRSN:"Internet radio station name",TRSO:"Internet radio station owner",TSIZ:"Size",TSRC:"ISRC (international standard recording code)",TSSE:"Software/Hardware and settings used for encoding",TYER:"Year",TXXX:"User defined text information frame", +UFID:"Unique file identifier",USER:"Terms of use",USLT:"Unsychronized lyric/text transcription",WCOM:"Commercial information",WCOP:"Copyright/Legal information",WOAF:"Official audio file webpage",WOAR:"Official artist/performer webpage",WOAS:"Official audio source webpage",WORS:"Official internet radio station homepage",WPAY:"Payment",WPUB:"Publishers official webpage",WXXX:"User defined URL link frame"};var c={title:["TIT2","TT2"],artist:["TPE1","TP1"],album:["TALB","TAL"],year:["TYER","TYE"],comment:["COMM", +"COM"],track:["TRCK","TRK"],genre:["TCON","TCO"],picture:["APIC","PIC"],lyrics:["USLT","ULT"]},a=["title","artist","album","track"];f.u=function(a,c){a.i([0,h(6,a)],c)};f.v=function(b,m){var d=0,e=b.a(d+3);if(42.4"};var r=b.a(d+4),g=b.g(d+5,7),l=b.g(d+5,6),w=b.g(d+5,5),x=h(d+6,b),d=d+10;if(l)var q=b.m(d),d=d+(q+4);var e={version:"2."+e+"."+r,major:e,revision:r,flags:{unsynchronisation:g,extended_header:l,experimental_indicator:w},size:x},k;if(g)k={};else{for(var x=x-10,g=b,r=m, +l={},w=e.major,q=[],u=0,n;n=(r||a)[u];u++)q=q.concat(c[n]||[n]);for(r=q;dr.indexOf(k))){if(2e||224<=e?f[d]=String.fromCharCode(l): +(e=(h[a+b]<<8)+h[a+g],a+=2,f[d]=String.fromCharCode(l,e))}h=new String(f.join(""));h.j=a;return h},K:function(h,f){var c=0;f=Math.min(f||h.length,h.length);239==h[0]&&187==h[1]&&191==h[2]&&(c=3);for(var a=[],b=0;cg)a[b]=String.fromCharCode(g);else if(194<=g&&224>g){var d=h[c++];a[b]=String.fromCharCode(((g&31)<<6)+(d&63))}else if(224<=g&&240>g){var d=h[c++],e=h[c++];a[b]=String.fromCharCode(((g&255)<<12)+((d&63)<<6)+(e&63))}else if(240<=g&&245>g){var d= +h[c++],e=h[c++],l=h[c++],g=((g&7)<<18)+((d&63)<<12)+((e&63)<<6)+(l&63)-65536;a[b]=String.fromCharCode((g>>10)+55296,(g&1023)+56320)}}a=new String(a.join(""));a.j=c;return a},I:function(g,f){var c=[];f=f||g.length;for(var a=0;a x.woeid === woeid); + } + + this.init = function (searchString) { + _locations[0] = new Location(); + + $(_locations[0]) + + .on('refresh', function(){ $this.trigger('refresh') }) + .on('ready', function(){ + $this.trigger('ready:main'); + }) + .on('init', initLocations); + _locations[0].first = true; + _locations[0].init(searchString); + + }; + + // kicks off after main location is returned. + // create the list of neighboring cities + function initLocations(){ + + // find reporting stations + var observationData = _locations[0].observations(0), + lat = observationData.lat, + lon = observationData.lon, + locList = []; + + // begin the forcast pull + _locations[0].initForecasts(); + + // get a list of observation stations info + $.getJSON('https://api.weather.gov/points/' + lat + ',' + lon + '/stations', function(data) { + + var feature, geo, station, dist; + for (var i=0; i < data.features.length; i++) { + + feature = data.features[i]; + geo = feature.geometry.coordinates; + dist = distance(lat, lon, geo[1], geo[0]); + + if (dist < includeRadiusMiles && dist > excludeRadiusMiles) { + locList.push({lat: geo[1], long:geo[0], distance:dist, stationUrl:feature.id}); + } + } + + if (locList.length===0) { + $this.trigger('allinit'); + return + } + + // sort list by distance + locList.sort(function(a, b) { + return parseInt(a.distance) - parseInt(b.distance); + }); + + // set the station for location 0 + _locations[0].stationUrl = locList[0].stationUrl + _locations[0].initNWSObservations(); + + // create location objects, get inital pull + for(var loc of locList) { + loc.location = new Location(); + $(loc.location).on('init',onLocationInit); + loc.location.init(loc.lat+','+loc.long); + loc.location.stationUrl = loc.stationUrl; + } + + }); + + var initCount=0; + function onLocationInit() { + initCount++; + if (initCount===locList.length) { + allLocationsInit(); + } + } + + + + + function allLocationsInit() { + + var location, cities=[], city; + + // add locations removing any duplicate cities by name + for(var loc of locList) { + + if (_locations.filter(e => e.city == loc.location.city).length === 0) { + _locations.push(loc.location); + loc.location.initForecasts(); + loc.location.initNWSObservations(); + } + + } + + $this.trigger('allinit'); + + } + + } + +} diff --git a/webroot/date_fns.min.js b/webroot/date_fns.min.js new file mode 100644 index 0000000..e88794d --- /dev/null +++ b/webroot/date_fns.min.js @@ -0,0 +1,4 @@ +(function webpackUniversalModuleDefinition(root,factory){if(typeof exports==="object"&&typeof module==="object")module.exports=factory();else if(typeof define==="function"&&define.amd)define([],factory);else if(typeof exports==="object")exports["dateFns"]=factory();else root["dateFns"]=factory()})(this,function(){return function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId])return installedModules[moduleId].exports;var module=installedModules[moduleId]={exports:{},id:moduleId,loaded:false};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.loaded=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.p="";return __webpack_require__(0)}([function(module,exports,__webpack_require__){module.exports={addDays:__webpack_require__(1),addHours:__webpack_require__(4),addISOYears:__webpack_require__(6),addMilliseconds:__webpack_require__(5),addMinutes:__webpack_require__(14),addMonths:__webpack_require__(15),addQuarters:__webpack_require__(17),addSeconds:__webpack_require__(18),addWeeks:__webpack_require__(19),addYears:__webpack_require__(20),areRangesOverlapping:__webpack_require__(21),closestIndexTo:__webpack_require__(22),closestTo:__webpack_require__(23),compareAsc:__webpack_require__(24),compareDesc:__webpack_require__(25),differenceInCalendarDays:__webpack_require__(12),differenceInCalendarISOWeeks:__webpack_require__(26),differenceInCalendarISOYears:__webpack_require__(27),differenceInCalendarMonths:__webpack_require__(28),differenceInCalendarQuarters:__webpack_require__(29),differenceInCalendarWeeks:__webpack_require__(31),differenceInCalendarYears:__webpack_require__(32),differenceInDays:__webpack_require__(33),differenceInHours:__webpack_require__(34),differenceInISOYears:__webpack_require__(36),differenceInMilliseconds:__webpack_require__(35),differenceInMinutes:__webpack_require__(38),differenceInMonths:__webpack_require__(39),differenceInQuarters:__webpack_require__(40),differenceInSeconds:__webpack_require__(41),differenceInWeeks:__webpack_require__(42),differenceInYears:__webpack_require__(43),distanceInWords:__webpack_require__(44),distanceInWordsStrict:__webpack_require__(49),distanceInWordsToNow:__webpack_require__(50),eachDay:__webpack_require__(51),endOfDay:__webpack_require__(52),endOfHour:__webpack_require__(53),endOfISOWeek:__webpack_require__(54),endOfISOYear:__webpack_require__(56),endOfMinute:__webpack_require__(57),endOfMonth:__webpack_require__(58),endOfQuarter:__webpack_require__(59),endOfSecond:__webpack_require__(60),endOfToday:__webpack_require__(61),endOfTomorrow:__webpack_require__(62),endOfWeek:__webpack_require__(55),endOfYear:__webpack_require__(63),endOfYesterday:__webpack_require__(64),format:__webpack_require__(65),getDate:__webpack_require__(70),getDay:__webpack_require__(71),getDayOfYear:__webpack_require__(66),getDaysInMonth:__webpack_require__(16),getDaysInYear:__webpack_require__(72),getHours:__webpack_require__(74),getISODay:__webpack_require__(75),getISOWeek:__webpack_require__(68),getISOWeeksInYear:__webpack_require__(76),getISOYear:__webpack_require__(7),getMilliseconds:__webpack_require__(77),getMinutes:__webpack_require__(78),getMonth:__webpack_require__(79),getOverlappingDaysInRanges:__webpack_require__(80),getQuarter:__webpack_require__(30),getSeconds:__webpack_require__(81),getTime:__webpack_require__(82),getYear:__webpack_require__(83),isAfter:__webpack_require__(84),isBefore:__webpack_require__(85),isDate:__webpack_require__(3),isEqual:__webpack_require__(86),isFirstDayOfMonth:__webpack_require__(87),isFriday:__webpack_require__(88),isFuture:__webpack_require__(89),isLastDayOfMonth:__webpack_require__(90),isLeapYear:__webpack_require__(73),isMonday:__webpack_require__(91),isPast:__webpack_require__(92),isSameDay:__webpack_require__(93),isSameHour:__webpack_require__(94),isSameISOWeek:__webpack_require__(96),isSameISOYear:__webpack_require__(98),isSameMinute:__webpack_require__(99),isSameMonth:__webpack_require__(101),isSameQuarter:__webpack_require__(102),isSameSecond:__webpack_require__(104),isSameWeek:__webpack_require__(97),isSameYear:__webpack_require__(106),isSaturday:__webpack_require__(107),isSunday:__webpack_require__(108),isThisHour:__webpack_require__(109),isThisISOWeek:__webpack_require__(110),isThisISOYear:__webpack_require__(111),isThisMinute:__webpack_require__(112),isThisMonth:__webpack_require__(113),isThisQuarter:__webpack_require__(114),isThisSecond:__webpack_require__(115),isThisWeek:__webpack_require__(116),isThisYear:__webpack_require__(117),isThursday:__webpack_require__(118),isToday:__webpack_require__(119),isTomorrow:__webpack_require__(120),isTuesday:__webpack_require__(121),isValid:__webpack_require__(69),isWednesday:__webpack_require__(122),isWeekend:__webpack_require__(123),isWithinRange:__webpack_require__(124),isYesterday:__webpack_require__(125),lastDayOfISOWeek:__webpack_require__(126),lastDayOfISOYear:__webpack_require__(128),lastDayOfMonth:__webpack_require__(129),lastDayOfQuarter:__webpack_require__(130),lastDayOfWeek:__webpack_require__(127),lastDayOfYear:__webpack_require__(131),max:__webpack_require__(132),min:__webpack_require__(133),parse:__webpack_require__(2),setDate:__webpack_require__(134),setDay:__webpack_require__(135),setDayOfYear:__webpack_require__(136),setHours:__webpack_require__(137),setISODay:__webpack_require__(138),setISOWeek:__webpack_require__(139),setISOYear:__webpack_require__(10),setMilliseconds:__webpack_require__(140),setMinutes:__webpack_require__(141),setMonth:__webpack_require__(142),setQuarter:__webpack_require__(143),setSeconds:__webpack_require__(144),setYear:__webpack_require__(145),startOfDay:__webpack_require__(13),startOfHour:__webpack_require__(95),startOfISOWeek:__webpack_require__(8),startOfISOYear:__webpack_require__(11),startOfMinute:__webpack_require__(100),startOfMonth:__webpack_require__(146),startOfQuarter:__webpack_require__(103),startOfSecond:__webpack_require__(105),startOfToday:__webpack_require__(147),startOfTomorrow:__webpack_require__(148),startOfWeek:__webpack_require__(9),startOfYear:__webpack_require__(67),startOfYesterday:__webpack_require__(149),subDays:__webpack_require__(150),subHours:__webpack_require__(151),subISOYears:__webpack_require__(37),subMilliseconds:__webpack_require__(152),subMinutes:__webpack_require__(153),subMonths:__webpack_require__(154),subQuarters:__webpack_require__(155),subSeconds:__webpack_require__(156),subWeeks:__webpack_require__(157),subYears:__webpack_require__(158)}},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function addDays(dirtyDate,dirtyAmount){var date=parse(dirtyDate);var amount=Number(dirtyAmount);date.setDate(date.getDate()+amount);return date}module.exports=addDays},function(module,exports,__webpack_require__){var isDate=__webpack_require__(3);var MILLISECONDS_IN_HOUR=36e5;var MILLISECONDS_IN_MINUTE=6e4;var DEFAULT_ADDITIONAL_DIGITS=2;var parseTokenDateTimeDelimeter=/[T ]/;var parseTokenPlainTime=/:/;var parseTokenYY=/^(\d{2})$/;var parseTokensYYY=[/^([+-]\d{2})$/,/^([+-]\d{3})$/,/^([+-]\d{4})$/];var parseTokenYYYY=/^(\d{4})/;var parseTokensYYYYY=[/^([+-]\d{4})/,/^([+-]\d{5})/,/^([+-]\d{6})/];var parseTokenMM=/^-(\d{2})$/;var parseTokenDDD=/^-?(\d{3})$/;var parseTokenMMDD=/^-?(\d{2})-?(\d{2})$/;var parseTokenWww=/^-?W(\d{2})$/;var parseTokenWwwD=/^-?W(\d{2})-?(\d{1})$/;var parseTokenHH=/^(\d{2}([.,]\d*)?)$/;var parseTokenHHMM=/^(\d{2}):?(\d{2}([.,]\d*)?)$/;var parseTokenHHMMSS=/^(\d{2}):?(\d{2}):?(\d{2}([.,]\d*)?)$/;var parseTokenTimezone=/([Z+-].*)$/;var parseTokenTimezoneZ=/^(Z)$/;var parseTokenTimezoneHH=/^([+-])(\d{2})$/;var parseTokenTimezoneHHMM=/^([+-])(\d{2}):?(\d{2})$/;function parse(argument,dirtyOptions){if(isDate(argument)){return new Date(argument.getTime())}else if(typeof argument!=="string"){return new Date(argument)}var options=dirtyOptions||{};var additionalDigits=options.additionalDigits;if(additionalDigits==null){additionalDigits=DEFAULT_ADDITIONAL_DIGITS}else{additionalDigits=Number(additionalDigits)}var dateStrings=splitDateString(argument);var parseYearResult=parseYear(dateStrings.date,additionalDigits);var year=parseYearResult.year;var restDateString=parseYearResult.restDateString;var date=parseDate(restDateString,year);if(date){var timestamp=date.getTime();var time=0;var offset;if(dateStrings.time){time=parseTime(dateStrings.time)}if(dateStrings.timezone){offset=parseTimezone(dateStrings.timezone)}else{offset=new Date(timestamp+time).getTimezoneOffset();offset=new Date(timestamp+time+offset*MILLISECONDS_IN_MINUTE).getTimezoneOffset()}return new Date(timestamp+time+offset*MILLISECONDS_IN_MINUTE)}else{return new Date(argument)}}function splitDateString(dateString){var dateStrings={};var array=dateString.split(parseTokenDateTimeDelimeter);var timeString;if(parseTokenPlainTime.test(array[0])){dateStrings.date=null;timeString=array[0]}else{dateStrings.date=array[0];timeString=array[1]}if(timeString){var token=parseTokenTimezone.exec(timeString);if(token){dateStrings.time=timeString.replace(token[1],"");dateStrings.timezone=token[1]}else{dateStrings.time=timeString}}return dateStrings}function parseYear(dateString,additionalDigits){var parseTokenYYY=parseTokensYYY[additionalDigits];var parseTokenYYYYY=parseTokensYYYYY[additionalDigits];var token;token=parseTokenYYYY.exec(dateString)||parseTokenYYYYY.exec(dateString);if(token){var yearString=token[1];return{year:parseInt(yearString,10),restDateString:dateString.slice(yearString.length)}}token=parseTokenYY.exec(dateString)||parseTokenYYY.exec(dateString);if(token){var centuryString=token[1];return{year:parseInt(centuryString,10)*100,restDateString:dateString.slice(centuryString.length)}}return{year:null}}function parseDate(dateString,year){if(year===null){return null}var token;var date;var month;var week;if(dateString.length===0){date=new Date(0);date.setUTCFullYear(year);return date}token=parseTokenMM.exec(dateString);if(token){date=new Date(0);month=parseInt(token[1],10)-1;date.setUTCFullYear(year,month);return date}token=parseTokenDDD.exec(dateString);if(token){date=new Date(0);var dayOfYear=parseInt(token[1],10);date.setUTCFullYear(year,0,dayOfYear);return date}token=parseTokenMMDD.exec(dateString);if(token){date=new Date(0);month=parseInt(token[1],10)-1;var day=parseInt(token[2],10);date.setUTCFullYear(year,month,day);return date}token=parseTokenWww.exec(dateString);if(token){week=parseInt(token[1],10)-1;return dayOfISOYear(year,week)}token=parseTokenWwwD.exec(dateString);if(token){week=parseInt(token[1],10)-1;var dayOfWeek=parseInt(token[2],10)-1;return dayOfISOYear(year,week,dayOfWeek)}return null}function parseTime(timeString){var token;var hours;var minutes;token=parseTokenHH.exec(timeString);if(token){hours=parseFloat(token[1].replace(",","."));return hours%24*MILLISECONDS_IN_HOUR}token=parseTokenHHMM.exec(timeString);if(token){hours=parseInt(token[1],10);minutes=parseFloat(token[2].replace(",","."));return hours%24*MILLISECONDS_IN_HOUR+minutes*MILLISECONDS_IN_MINUTE}token=parseTokenHHMMSS.exec(timeString);if(token){hours=parseInt(token[1],10);minutes=parseInt(token[2],10);var seconds=parseFloat(token[3].replace(",","."));return hours%24*MILLISECONDS_IN_HOUR+minutes*MILLISECONDS_IN_MINUTE+seconds*1e3}return null}function parseTimezone(timezoneString){var token;var absoluteOffset;token=parseTokenTimezoneZ.exec(timezoneString);if(token){return 0}token=parseTokenTimezoneHH.exec(timezoneString);if(token){absoluteOffset=parseInt(token[2],10)*60;return token[1]==="+"?-absoluteOffset:absoluteOffset}token=parseTokenTimezoneHHMM.exec(timezoneString);if(token){absoluteOffset=parseInt(token[2],10)*60+parseInt(token[3],10);return token[1]==="+"?-absoluteOffset:absoluteOffset}return 0}function dayOfISOYear(isoYear,week,day){week=week||0;day=day||0;var date=new Date(0);date.setUTCFullYear(isoYear,0,4);var fourthOfJanuaryDay=date.getUTCDay()||7;var diff=week*7+day+1-fourthOfJanuaryDay;date.setUTCDate(date.getUTCDate()+diff);return date}module.exports=parse},function(module,exports){function isDate(argument){return argument instanceof Date}module.exports=isDate},function(module,exports,__webpack_require__){var addMilliseconds=__webpack_require__(5);var MILLISECONDS_IN_HOUR=36e5;function addHours(dirtyDate,dirtyAmount){var amount=Number(dirtyAmount);return addMilliseconds(dirtyDate,amount*MILLISECONDS_IN_HOUR)}module.exports=addHours},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function addMilliseconds(dirtyDate,dirtyAmount){var timestamp=parse(dirtyDate).getTime();var amount=Number(dirtyAmount);return new Date(timestamp+amount)}module.exports=addMilliseconds},function(module,exports,__webpack_require__){var getISOYear=__webpack_require__(7);var setISOYear=__webpack_require__(10);function addISOYears(dirtyDate,dirtyAmount){var amount=Number(dirtyAmount);return setISOYear(dirtyDate,getISOYear(dirtyDate)+amount)}module.exports=addISOYears},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);var startOfISOWeek=__webpack_require__(8);function getISOYear(dirtyDate){var date=parse(dirtyDate);var year=date.getFullYear();var fourthOfJanuaryOfNextYear=new Date(0);fourthOfJanuaryOfNextYear.setFullYear(year+1,0,4);fourthOfJanuaryOfNextYear.setHours(0,0,0,0);var startOfNextYear=startOfISOWeek(fourthOfJanuaryOfNextYear);var fourthOfJanuaryOfThisYear=new Date(0);fourthOfJanuaryOfThisYear.setFullYear(year,0,4);fourthOfJanuaryOfThisYear.setHours(0,0,0,0);var startOfThisYear=startOfISOWeek(fourthOfJanuaryOfThisYear);if(date.getTime()>=startOfNextYear.getTime()){return year+1}else if(date.getTime()>=startOfThisYear.getTime()){return year}else{return year-1}}module.exports=getISOYear},function(module,exports,__webpack_require__){var startOfWeek=__webpack_require__(9);function startOfISOWeek(dirtyDate){return startOfWeek(dirtyDate,{weekStartsOn:1})}module.exports=startOfISOWeek},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function startOfWeek(dirtyDate,dirtyOptions){var weekStartsOn=dirtyOptions?Number(dirtyOptions.weekStartsOn)||0:0;var date=parse(dirtyDate);var day=date.getDay();var diff=(dayinitialEndTime||comparedStartTime>comparedEndTime){throw new Error("The start of the range cannot be after the end of the range")}return initialStartTimetimeRight){return 1}else{return 0}}module.exports=compareAsc},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function compareDesc(dirtyDateLeft,dirtyDateRight){var dateLeft=parse(dirtyDateLeft);var timeLeft=dateLeft.getTime();var dateRight=parse(dirtyDateRight);var timeRight=dateRight.getTime();if(timeLeft>timeRight){return-1}else if(timeLeft0?Math.floor(diff):Math.ceil(diff)}module.exports=differenceInHours},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function differenceInMilliseconds(dirtyDateLeft,dirtyDateRight){var dateLeft=parse(dirtyDateLeft);var dateRight=parse(dirtyDateRight);return dateLeft.getTime()-dateRight.getTime()}module.exports=differenceInMilliseconds},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);var differenceInCalendarISOYears=__webpack_require__(27);var compareAsc=__webpack_require__(24);var subISOYears=__webpack_require__(37);function differenceInISOYears(dirtyDateLeft,dirtyDateRight){var dateLeft=parse(dirtyDateLeft);var dateRight=parse(dirtyDateRight);var sign=compareAsc(dateLeft,dateRight);var difference=Math.abs(differenceInCalendarISOYears(dateLeft,dateRight));dateLeft=subISOYears(dateLeft,sign*difference);var isLastISOYearNotFull=compareAsc(dateLeft,dateRight)===-sign;return sign*(difference-isLastISOYearNotFull)}module.exports=differenceInISOYears},function(module,exports,__webpack_require__){var addISOYears=__webpack_require__(6);function subISOYears(dirtyDate,dirtyAmount){var amount=Number(dirtyAmount);return addISOYears(dirtyDate,-amount)}module.exports=subISOYears},function(module,exports,__webpack_require__){var differenceInMilliseconds=__webpack_require__(35);var MILLISECONDS_IN_MINUTE=6e4;function differenceInMinutes(dirtyDateLeft,dirtyDateRight){var diff=differenceInMilliseconds(dirtyDateLeft,dirtyDateRight)/MILLISECONDS_IN_MINUTE;return diff>0?Math.floor(diff):Math.ceil(diff)}module.exports=differenceInMinutes},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);var differenceInCalendarMonths=__webpack_require__(28);var compareAsc=__webpack_require__(24);function differenceInMonths(dirtyDateLeft,dirtyDateRight){var dateLeft=parse(dirtyDateLeft);var dateRight=parse(dirtyDateRight);var sign=compareAsc(dateLeft,dateRight);var difference=Math.abs(differenceInCalendarMonths(dateLeft,dateRight));dateLeft.setMonth(dateLeft.getMonth()-sign*difference);var isLastMonthNotFull=compareAsc(dateLeft,dateRight)===-sign;return sign*(difference-isLastMonthNotFull)}module.exports=differenceInMonths},function(module,exports,__webpack_require__){var differenceInMonths=__webpack_require__(39);function differenceInQuarters(dirtyDateLeft,dirtyDateRight){var diff=differenceInMonths(dirtyDateLeft,dirtyDateRight)/3;return diff>0?Math.floor(diff):Math.ceil(diff)}module.exports=differenceInQuarters},function(module,exports,__webpack_require__){var differenceInMilliseconds=__webpack_require__(35);function differenceInSeconds(dirtyDateLeft,dirtyDateRight){var diff=differenceInMilliseconds(dirtyDateLeft,dirtyDateRight)/1e3;return diff>0?Math.floor(diff):Math.ceil(diff)}module.exports=differenceInSeconds},function(module,exports,__webpack_require__){var differenceInDays=__webpack_require__(33);function differenceInWeeks(dirtyDateLeft,dirtyDateRight){var diff=differenceInDays(dirtyDateLeft,dirtyDateRight)/7;return diff>0?Math.floor(diff):Math.ceil(diff)}module.exports=differenceInWeeks},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);var differenceInCalendarYears=__webpack_require__(32);var compareAsc=__webpack_require__(24);function differenceInYears(dirtyDateLeft,dirtyDateRight){var dateLeft=parse(dirtyDateLeft);var dateRight=parse(dirtyDateRight);var sign=compareAsc(dateLeft,dateRight);var difference=Math.abs(differenceInCalendarYears(dateLeft,dateRight));dateLeft.setFullYear(dateLeft.getFullYear()-sign*difference);var isLastYearNotFull=compareAsc(dateLeft,dateRight)===-sign;return sign*(difference-isLastYearNotFull)}module.exports=differenceInYears},function(module,exports,__webpack_require__){var compareDesc=__webpack_require__(25);var parse=__webpack_require__(2);var differenceInSeconds=__webpack_require__(41);var differenceInMonths=__webpack_require__(39);var enLocale=__webpack_require__(45);var MINUTES_IN_DAY=1440;var MINUTES_IN_ALMOST_TWO_DAYS=2520;var MINUTES_IN_MONTH=43200;var MINUTES_IN_TWO_MONTHS=86400;function distanceInWords(dirtyDateToCompare,dirtyDate,dirtyOptions){var options=dirtyOptions||{};var comparison=compareDesc(dirtyDateToCompare,dirtyDate);var locale=options.locale;var localize=enLocale.distanceInWords.localize;if(locale&&locale.distanceInWords&&locale.distanceInWords.localize){localize=locale.distanceInWords.localize}var localizeOptions={addSuffix:Boolean(options.addSuffix),comparison:comparison};var dateLeft,dateRight;if(comparison>0){dateLeft=parse(dirtyDateToCompare);dateRight=parse(dirtyDate)}else{dateLeft=parse(dirtyDate);dateRight=parse(dirtyDateToCompare)}var seconds=differenceInSeconds(dateRight,dateLeft);var offset=dateRight.getTimezoneOffset()-dateLeft.getTimezoneOffset();var minutes=Math.round(seconds/60)-offset;var months;if(minutes<2){if(options.includeSeconds){if(seconds<5){return localize("lessThanXSeconds",5,localizeOptions)}else if(seconds<10){return localize("lessThanXSeconds",10,localizeOptions)}else if(seconds<20){return localize("lessThanXSeconds",20,localizeOptions)}else if(seconds<40){return localize("halfAMinute",null,localizeOptions)}else if(seconds<60){return localize("lessThanXMinutes",1,localizeOptions)}else{return localize("xMinutes",1,localizeOptions)}}else{if(minutes===0){return localize("lessThanXMinutes",1,localizeOptions)}else{return localize("xMinutes",minutes,localizeOptions)}}}else if(minutes<45){return localize("xMinutes",minutes,localizeOptions)}else if(minutes<90){return localize("aboutXHours",1,localizeOptions)}else if(minutes0){return"in "+result}else{return result+" ago"}}return result}return{localize:localize}}module.exports=buildDistanceInWordsLocale},function(module,exports,__webpack_require__){var buildFormattingTokensRegExp=__webpack_require__(48);function buildFormatLocale(){var months3char=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];var monthsFull=["January","February","March","April","May","June","July","August","September","October","November","December"];var weekdays2char=["Su","Mo","Tu","We","Th","Fr","Sa"];var weekdays3char=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];var weekdaysFull=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var meridiemUppercase=["AM","PM"];var meridiemLowercase=["am","pm"];var meridiemFull=["a.m.","p.m."];var formatters={MMM:function(date){return months3char[date.getMonth()]},MMMM:function(date){return monthsFull[date.getMonth()]},dd:function(date){return weekdays2char[date.getDay()]},ddd:function(date){return weekdays3char[date.getDay()]},dddd:function(date){return weekdaysFull[date.getDay()]},A:function(date){return date.getHours()/12>=1?meridiemUppercase[1]:meridiemUppercase[0]},a:function(date){return date.getHours()/12>=1?meridiemLowercase[1]:meridiemLowercase[0]},aa:function(date){return date.getHours()/12>=1?meridiemFull[1]:meridiemFull[0]}};var ordinalFormatters=["M","D","DDD","d","Q","W"];ordinalFormatters.forEach(function(formatterToken){formatters[formatterToken+"o"]=function(date,formatters){return ordinal(formatters[formatterToken](date))}});return{formatters:formatters,formattingTokensRegExp:buildFormattingTokensRegExp(formatters)}}function ordinal(number){var rem100=number%100;if(rem100>20||rem100<10){switch(rem100%10){case 1:return number+"st";case 2:return number+"nd";case 3:return number+"rd"}}return number+"th"}module.exports=buildFormatLocale},function(module,exports){var commonFormatterKeys=["M","MM","Q","D","DD","DDD","DDDD","d","E","W","WW","YY","YYYY","GG","GGGG","H","HH","h","hh","m","mm","s","ss","S","SS","SSS","Z","ZZ","X","x"];function buildFormattingTokensRegExp(formatters){var formatterKeys=[];for(var key in formatters){if(formatters.hasOwnProperty(key)){formatterKeys.push(key)}}var formattingTokens=commonFormatterKeys.concat(formatterKeys).sort().reverse();var formattingTokensRegExp=new RegExp("(\\[[^\\[]*\\])|(\\\\)?"+"("+formattingTokens.join("|")+"|.)","g");return formattingTokensRegExp}module.exports=buildFormattingTokensRegExp},function(module,exports,__webpack_require__){var compareDesc=__webpack_require__(25);var parse=__webpack_require__(2);var differenceInSeconds=__webpack_require__(41);var enLocale=__webpack_require__(45);var MINUTES_IN_DAY=1440;var MINUTES_IN_MONTH=43200;var MINUTES_IN_YEAR=525600;function distanceInWordsStrict(dirtyDateToCompare,dirtyDate,dirtyOptions){var options=dirtyOptions||{};var comparison=compareDesc(dirtyDateToCompare,dirtyDate);var locale=options.locale;var localize=enLocale.distanceInWords.localize;if(locale&&locale.distanceInWords&&locale.distanceInWords.localize){localize=locale.distanceInWords.localize}var localizeOptions={addSuffix:Boolean(options.addSuffix),comparison:comparison};var dateLeft,dateRight;if(comparison>0){dateLeft=parse(dirtyDateToCompare);dateRight=parse(dirtyDate)}else{dateLeft=parse(dirtyDate);dateRight=parse(dirtyDateToCompare)}var unit;var mathPartial=Math[options.partialMethod?String(options.partialMethod):"floor"];var seconds=differenceInSeconds(dateRight,dateLeft);var offset=dateRight.getTimezoneOffset()-dateLeft.getTimezoneOffset();var minutes=mathPartial(seconds/60)-offset;var hours,days,months,years;if(options.unit){unit=String(options.unit)}else{if(minutes<1){unit="s"}else if(minutes<60){unit="m"}else if(minutesendTime){throw new Error("The first date cannot be after the second date")}var dates=[];var currentDate=startDate;currentDate.setHours(0,0,0,0);while(currentDate.getTime()<=endTime){dates.push(parse(currentDate));currentDate.setDate(currentDate.getDate()+1)}return dates}module.exports=eachDay},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function endOfDay(dirtyDate){var date=parse(dirtyDate);date.setHours(23,59,59,999);return date}module.exports=endOfDay},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function endOfHour(dirtyDate){var date=parse(dirtyDate);date.setMinutes(59,59,999);return date}module.exports=endOfHour},function(module,exports,__webpack_require__){var endOfWeek=__webpack_require__(55);function endOfISOWeek(dirtyDate){return endOfWeek(dirtyDate,{weekStartsOn:1})}module.exports=endOfISOWeek},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function endOfWeek(dirtyDate,dirtyOptions){var weekStartsOn=dirtyOptions?Number(dirtyOptions.weekStartsOn)||0:0;var date=parse(dirtyDate);var day=date.getDay();var diff=(day12){return hours%12}else{return hours}},hh:function(date){return addLeadingZeros(formatters["h"](date),2)},m:function(date){return date.getMinutes()},mm:function(date){return addLeadingZeros(date.getMinutes(),2)},s:function(date){return date.getSeconds()},ss:function(date){return addLeadingZeros(date.getSeconds(),2)},S:function(date){return Math.floor(date.getMilliseconds()/100)},SS:function(date){return addLeadingZeros(Math.floor(date.getMilliseconds()/10),2)},SSS:function(date){return addLeadingZeros(date.getMilliseconds(),3)},Z:function(date){return formatTimezone(date.getTimezoneOffset(),":")},ZZ:function(date){return formatTimezone(date.getTimezoneOffset())},X:function(date){return Math.floor(date.getTime()/1e3)},x:function(date){return date.getTime()}};function buildFormatFn(formatStr,localeFormatters,formattingTokensRegExp){var array=formatStr.match(formattingTokensRegExp);var length=array.length;var i;var formatter;for(i=0;i0?"-":"+";var absOffset=Math.abs(offset);var hours=Math.floor(absOffset/60);var minutes=absOffset%60;return sign+addLeadingZeros(hours,2)+delimeter+addLeadingZeros(minutes,2)}function addLeadingZeros(number,targetLength){var output=Math.abs(number).toString();while(output.lengthinitialEndTime||comparedStartTime>comparedEndTime){throw new Error("The start of the range cannot be after the end of the range")}var isOverlapping=initialStartTimeinitialEndTime?initialEndTime:comparedEndTime;var differenceInMs=overlapEndDate-overlapStartDate;return Math.ceil(differenceInMs/MILLISECONDS_IN_DAY)}module.exports=getOverlappingDaysInRanges},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function getSeconds(dirtyDate){var date=parse(dirtyDate);var seconds=date.getSeconds();return seconds}module.exports=getSeconds},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function getTime(dirtyDate){var date=parse(dirtyDate);var timestamp=date.getTime();return timestamp}module.exports=getTime},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function getYear(dirtyDate){var date=parse(dirtyDate);var year=date.getFullYear();return year}module.exports=getYear},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isAfter(dirtyDate,dirtyDateToCompare){var date=parse(dirtyDate);var dateToCompare=parse(dirtyDateToCompare);return date.getTime()>dateToCompare.getTime()}module.exports=isAfter},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isBefore(dirtyDate,dirtyDateToCompare){var date=parse(dirtyDate);var dateToCompare=parse(dirtyDateToCompare);return date.getTime()(new Date).getTime()}module.exports=isFuture},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);var endOfDay=__webpack_require__(52);var endOfMonth=__webpack_require__(58);function isLastDayOfMonth(dirtyDate){var date=parse(dirtyDate);return endOfDay(date).getTime()===endOfMonth(date).getTime()}module.exports=isLastDayOfMonth},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isMonday(dirtyDate){return parse(dirtyDate).getDay()===1}module.exports=isMonday},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isPast(dirtyDate){return parse(dirtyDate).getTime()<(new Date).getTime()}module.exports=isPast},function(module,exports,__webpack_require__){var startOfDay=__webpack_require__(13);function isSameDay(dirtyDateLeft,dirtyDateRight){var dateLeftStartOfDay=startOfDay(dirtyDateLeft);var dateRightStartOfDay=startOfDay(dirtyDateRight);return dateLeftStartOfDay.getTime()===dateRightStartOfDay.getTime()}module.exports=isSameDay},function(module,exports,__webpack_require__){var startOfHour=__webpack_require__(95);function isSameHour(dirtyDateLeft,dirtyDateRight){var dateLeftStartOfHour=startOfHour(dirtyDateLeft);var dateRightStartOfHour=startOfHour(dirtyDateRight);return dateLeftStartOfHour.getTime()===dateRightStartOfHour.getTime()}module.exports=isSameHour},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function startOfHour(dirtyDate){var date=parse(dirtyDate);date.setMinutes(0,0,0);return date}module.exports=startOfHour},function(module,exports,__webpack_require__){var isSameWeek=__webpack_require__(97);function isSameISOWeek(dirtyDateLeft,dirtyDateRight){return isSameWeek(dirtyDateLeft,dirtyDateRight,{weekStartsOn:1})}module.exports=isSameISOWeek},function(module,exports,__webpack_require__){var startOfWeek=__webpack_require__(9);function isSameWeek(dirtyDateLeft,dirtyDateRight,dirtyOptions){var dateLeftStartOfWeek=startOfWeek(dirtyDateLeft,dirtyOptions);var dateRightStartOfWeek=startOfWeek(dirtyDateRight,dirtyOptions);return dateLeftStartOfWeek.getTime()===dateRightStartOfWeek.getTime()}module.exports=isSameWeek},function(module,exports,__webpack_require__){var startOfISOYear=__webpack_require__(11);function isSameISOYear(dirtyDateLeft,dirtyDateRight){var dateLeftStartOfYear=startOfISOYear(dirtyDateLeft);var dateRightStartOfYear=startOfISOYear(dirtyDateRight);return dateLeftStartOfYear.getTime()===dateRightStartOfYear.getTime()}module.exports=isSameISOYear},function(module,exports,__webpack_require__){var startOfMinute=__webpack_require__(100);function isSameMinute(dirtyDateLeft,dirtyDateRight){var dateLeftStartOfMinute=startOfMinute(dirtyDateLeft);var dateRightStartOfMinute=startOfMinute(dirtyDateRight);return dateLeftStartOfMinute.getTime()===dateRightStartOfMinute.getTime()}module.exports=isSameMinute},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function startOfMinute(dirtyDate){var date=parse(dirtyDate);date.setSeconds(0,0);return date}module.exports=startOfMinute},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isSameMonth(dirtyDateLeft,dirtyDateRight){var dateLeft=parse(dirtyDateLeft);var dateRight=parse(dirtyDateRight);return dateLeft.getFullYear()===dateRight.getFullYear()&&dateLeft.getMonth()===dateRight.getMonth()}module.exports=isSameMonth},function(module,exports,__webpack_require__){var startOfQuarter=__webpack_require__(103);function isSameQuarter(dirtyDateLeft,dirtyDateRight){var dateLeftStartOfQuarter=startOfQuarter(dirtyDateLeft);var dateRightStartOfQuarter=startOfQuarter(dirtyDateRight);return dateLeftStartOfQuarter.getTime()===dateRightStartOfQuarter.getTime()}module.exports=isSameQuarter},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function startOfQuarter(dirtyDate){var date=parse(dirtyDate);var currentMonth=date.getMonth();var month=currentMonth-currentMonth%3;date.setMonth(month,1);date.setHours(0,0,0,0);return date}module.exports=startOfQuarter},function(module,exports,__webpack_require__){var startOfSecond=__webpack_require__(105);function isSameSecond(dirtyDateLeft,dirtyDateRight){var dateLeftStartOfSecond=startOfSecond(dirtyDateLeft);var dateRightStartOfSecond=startOfSecond(dirtyDateRight);return dateLeftStartOfSecond.getTime()===dateRightStartOfSecond.getTime()}module.exports=isSameSecond},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function startOfSecond(dirtyDate){var date=parse(dirtyDate);date.setMilliseconds(0);return date}module.exports=startOfSecond},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isSameYear(dirtyDateLeft,dirtyDateRight){var dateLeft=parse(dirtyDateLeft);var dateRight=parse(dirtyDateRight);return dateLeft.getFullYear()===dateRight.getFullYear()}module.exports=isSameYear},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isSaturday(dirtyDate){return parse(dirtyDate).getDay()===6}module.exports=isSaturday},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isSunday(dirtyDate){return parse(dirtyDate).getDay()===0}module.exports=isSunday},function(module,exports,__webpack_require__){var isSameHour=__webpack_require__(94);function isThisHour(dirtyDate){return isSameHour(new Date,dirtyDate)}module.exports=isThisHour},function(module,exports,__webpack_require__){var isSameISOWeek=__webpack_require__(96);function isThisISOWeek(dirtyDate){return isSameISOWeek(new Date,dirtyDate)}module.exports=isThisISOWeek},function(module,exports,__webpack_require__){var isSameISOYear=__webpack_require__(98);function isThisISOYear(dirtyDate){return isSameISOYear(new Date,dirtyDate)}module.exports=isThisISOYear},function(module,exports,__webpack_require__){var isSameMinute=__webpack_require__(99);function isThisMinute(dirtyDate){return isSameMinute(new Date,dirtyDate)}module.exports=isThisMinute},function(module,exports,__webpack_require__){var isSameMonth=__webpack_require__(101);function isThisMonth(dirtyDate){return isSameMonth(new Date,dirtyDate)}module.exports=isThisMonth},function(module,exports,__webpack_require__){var isSameQuarter=__webpack_require__(102);function isThisQuarter(dirtyDate){return isSameQuarter(new Date,dirtyDate)}module.exports=isThisQuarter},function(module,exports,__webpack_require__){var isSameSecond=__webpack_require__(104);function isThisSecond(dirtyDate){return isSameSecond(new Date,dirtyDate)}module.exports=isThisSecond},function(module,exports,__webpack_require__){var isSameWeek=__webpack_require__(97);function isThisWeek(dirtyDate,dirtyOptions){return isSameWeek(new Date,dirtyDate,dirtyOptions)}module.exports=isThisWeek},function(module,exports,__webpack_require__){var isSameYear=__webpack_require__(106);function isThisYear(dirtyDate){return isSameYear(new Date,dirtyDate)}module.exports=isThisYear},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isThursday(dirtyDate){return parse(dirtyDate).getDay()===4}module.exports=isThursday},function(module,exports,__webpack_require__){var startOfDay=__webpack_require__(13);function isToday(dirtyDate){return startOfDay(dirtyDate).getTime()===startOfDay(new Date).getTime()}module.exports=isToday},function(module,exports,__webpack_require__){var startOfDay=__webpack_require__(13);function isTomorrow(dirtyDate){var tomorrow=new Date;tomorrow.setDate(tomorrow.getDate()+1);return startOfDay(dirtyDate).getTime()===startOfDay(tomorrow).getTime()}module.exports=isTomorrow},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isTuesday(dirtyDate){return parse(dirtyDate).getDay()===2}module.exports=isTuesday},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isWednesday(dirtyDate){return parse(dirtyDate).getDay()===3}module.exports=isWednesday},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isWeekend(dirtyDate){var date=parse(dirtyDate);var day=date.getDay();return day===0||day===6}module.exports=isWeekend},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function isWithinRange(dirtyDate,dirtyStartDate,dirtyEndDate){var time=parse(dirtyDate).getTime();var startTime=parse(dirtyStartDate).getTime();var endTime=parse(dirtyEndDate).getTime();if(startTime>endTime){throw new Error("The start of the range cannot be after the end of the range")}return time>=startTime&&time<=endTime}module.exports=isWithinRange},function(module,exports,__webpack_require__){var startOfDay=__webpack_require__(13);function isYesterday(dirtyDate){var yesterday=new Date;yesterday.setDate(yesterday.getDate()-1);return startOfDay(dirtyDate).getTime()===startOfDay(yesterday).getTime()}module.exports=isYesterday},function(module,exports,__webpack_require__){var lastDayOfWeek=__webpack_require__(127);function lastDayOfISOWeek(dirtyDate){return lastDayOfWeek(dirtyDate,{weekStartsOn:1})}module.exports=lastDayOfISOWeek},function(module,exports,__webpack_require__){var parse=__webpack_require__(2);function lastDayOfWeek(dirtyDate,dirtyOptions){var weekStartsOn=dirtyOptions?Number(dirtyOptions.weekStartsOn)||0:0;var date=parse(dirtyDate);var day=date.getDay();var diff=(day").appendTo('#marquee-now'); + } else { + $span = $('#marquee-now>span#' + location.woeid); + } + + // display the current info + $span.text(location.name + ': ' + Math.round(parseInt(location.data.main.temp)) + ' ' + location.data.weather[0].description.toLowerCase()); + + + // set the expiration date/time + location.xdate = dateFns.addMinutes(location.data.lastBuildDate, location.data.ttl); + + }); + + } + + +} +var groupDataManager = new GroupDataManager; diff --git a/webroot/location.js b/webroot/location.js new file mode 100644 index 0000000..804b80f --- /dev/null +++ b/webroot/location.js @@ -0,0 +1,179 @@ +function Location() { // onReady, onRefresh, onAllComplete + + var that = this, + $this = $(this), + _forecastmgr, + _observations=[]; + + this.temperature = function() { + if (_observations[1]!=null && _observations[1].temperature.value) { + return C2F(_observations[1].temperature.value); + } else { + return Math.round( _observations[0].current.temp ); + } + } + + this.observations = function(i) { + return _observations[i]; + }; + + this.forecasts=function(type){return _forecastmgr.forecast(type)}; + + this.init = function(searchString){ + checkRefresh(searchString); + }; + + this.initForecasts = function() { + // start the forecast data pull + if (_observations[0] != undefined){ + _forecastmgr = new ForecastManager(_observations[0].lat, _observations[0].lon, function() { + $this.trigger('ready'); + }); + } + }; + + this.initNWSObservations = function(){ + stationObservations(); + }; + + + // check to see if data needs to be refreshed + function checkRefresh(location) { + + // check the expiration + if ( _observations[0]!=undefined && dateFns.isFuture( _observations[0].xdate ) ) { + setTimeout(checkRefresh, getRandom(5000, 10000)); + return; + } + + // woeid is the id for the location to pull data for + console.log(location); + if (location != undefined) { + var loclat = location.split(",")[0] + var loclong = location.split(",")[1] + var url = 'https://api.openweathermap.org/data/2.5/onecall?lat=' + loclat + '&lon=' + loclong + '&appid=putkeyhere&units=imperial' + + + // ajax the latest observation + $.getJSON(url, function(data) { + _observations[0] = json = data; + + $this.trigger('refresh'); + + // the following block only runs on init + if (that.woeid===undefined) { + + that.woeid = loclat + + that.lat = data.lat + that.long = data.lon; + + //that.city = data.query.results.channel.location.city; + + $this.trigger('init'); + + } + // set the expiration date/time + _observations[0].xdate = dateFns.addMinutes(json.lastBuildDate, json.ttl); + + setTimeout(checkRefresh, getRandom(5000, 10000)); + + }); + $.getJSON('http://api.openweathermap.org/geo/1.0/reverse?lat=' + loclat + '&lon=' + loclong + '&limit=1&appid=0cb279a98124446dd16dba02fbfb60ee', function(sloc) { + that.city = (sloc[0].name); + }); + +} + +} + + // pull observations from the location observation station + function stationObservations() { + + var url = that.stationUrl + '/observations/current'; + + // check the expiration + if ( _observations[1]!=undefined && dateFns.isFuture( _observations[1].xdate ) ) { + setTimeout(checkRefresh, getRandom(5000, 10000)); + return; + } + + // ajax the current conditions + $.getJSON(url, function(data) { + _observations[1] = data.properties; + + // set the expiration date/time + _observations[1].xdate = dateFns.addMinutes(data.properties.timestamp, 60); + setTimeout(stationObservations, getRandom(5000, 10000)); + + }); + } + + + + +function ForecastManager (latitude, longitude, readyCallback) { + var _forecasts = {}, + keys =['daily','hourly'], + key, + readycount = 0; + + for(key of keys) { + _forecasts[key] = new Forecast(key, latitude, longitude, count); + } + + + function count() { + // count up completed forecast pulls + readycount++; + if (readycount===keys.length) { + readyCallback(); + } + } + + this.forecast = function(type) { + try{ + return _forecasts[type].data; + } catch(err){} + } + +} + +function Forecast(type, lat, lon, readyCallback) { + + var that = this, + url = 'https://api.weather.gov/points/' + lat + ',' + lon + "/forecast/" + (type==='hourly' ? type : ''); + + this.data = {}; + + checkRefresh(); + + function checkRefresh() { + + // check the expiration + if ( that.data!={} && dateFns.isFuture( that.data.xdate ) ) { + setTimeout(checkRefresh, getRandom(5000, 10000)); + return; + } + + // ajax the forecast + $.getJSON(url, function(data) { + + that.data = data.properties.periods; + + // trigger ready callback on first data pull + if (readyCallback){ + readyCallback(); + } + + // set the expiration date/time + that.data.xdate = dateFns.addMinutes(data.properties.updated, 60); + that.data.xdate = dateFns.addMinutes(new Date(), 5); + setTimeout(checkRefresh, getRandom(5000, 10000)); + + }); + + } + +} +} diff --git a/webroot/loops.js b/webroot/loops.js new file mode 100644 index 0000000..79bd5f9 --- /dev/null +++ b/webroot/loops.js @@ -0,0 +1,522 @@ + +function Loops(bindDataManager) { + var //dataManager, + obsData, + foreDataDaily, + foreDataHourly; + + obsData = bindDataManager.observations; + foreDataDaily = bindDataManager.forecasts('daily'); + foreDataHourly = bindDataManager.forecasts('hourly'); + + + // init the display loops + displayAtmospheric(0); + displayForecast(0); + + function displayAtmospheric(idx) { + + var displays = { + + conditions() { + return (getCC(obsData(0).current.weather[0].id + obsData(0).current.weather[0].icon, obsData(0).current.wind_speed)).toLowerCase(); + }, + + wind(){ return 'wind ' + degToCompass(obsData(0).current.wind_deg) + ' ' + Math.round(parseInt(obsData(0).current.wind_speed)); }, + + gusts(){ + if ( obsData(1)!=undefined ) { + return obsData(1).windGust.value!=null ? 'gusts ' + mps2mph( obsData(1).windGust.value ) : ''; + } + }, + + humidity(){ return 'humidity ' + obsData(0).current.humidity + '%'; }, + + dewpoint(){ return 'dew point ' + dewPoint(obsData(0).current.temp, obsData(0).current.humidity ) + '°'; }, + + heatindex_windchill(){ + var windchill = 35.74 + (0.6215 * parseInt(obsData(0).current.temp)) + (0.4275 * parseInt(obsData(0).current.temp) - 35.75) * parseInt(obsData(0).current.wind_speed) ^ 0.16; + if (parseInt(obsData(0).current.temp)<80 && windchill < parseInt(obsData(0).current.temp)) { + + return 'wind chill ' + windchill + '°'; + } else if (parseInt(obsData(0).current.temp)>=80 && parseInt(obsData(0).current.humidity)>=40 ){ + return 'heat index ' + heatIndex(obsData(0).current.temp, obsData(0).current.humidity) + '°'; + } + else return ''; + }, + + pressure(){ return 'pressure ' + (obsData(0).current.pressure*0.0295301).toFixed(2) }, +//+ ['S','R','F'][obsData(0).current.rising]; + visibility() { return 'visibility ' + (parseInt(obsData(0).current.visibility) / 1000) + ' mile' + (obsData(0).current.visibility != 1 ? 's' : ''); }, + + uvindex() { return 'UV index ' + obsData(0).current.uvi; }, + + }, + keys = Object.keys(displays), + text = displays[ keys[idx] ](); + + // increment the pointer + idx = (++idx===keys.length ? 0 : idx); + + if (text) { + $('#current-info').html(text); + setTimeout(function(){ displayAtmospheric(idx) }, 6000); // 6 second increment loop + } else { + // nothing to display - skip to the next one + setTimeout(function(){ displayAtmospheric(idx) }, 0); + } + + } // end function + + + function displayForecast(idx) { + + var displays = { + + text1() { + $('#forecast-title').text( possessiveForecast(foreDataDaily[0].name) ); + resizeText(foreDataDaily[0].detailedForecast); + }, + text2() { + $('#forecast-title').text( possessiveForecast(foreDataDaily[1].name) ); + resizeText(foreDataDaily[1].detailedForecast); + }, + + fiveday() { + var newtile, weekend, icons, + startidx = (foreDataDaily[0].name==='Tonight' ? 1 : 2), + days = ['SUN','MON','TUE','WED','THU','FRI','SAT']; + + $('#forecast-title').text("5 DAY FORECAST"); + $('#forecast-tiles').empty(); + + for (var i=startidx; i<=10; i+=2 ) { + + weekend = ( dateFns.isWeekend(foreDataDaily[i].startTime) ? ' weekend' : ''); + newtile = $("
"); + + $("
") .appendTo(newtile) .text(days[ dateFns.getDay(foreDataDaily[i].startTime) ]); + + icons = mapNWSicons(foreDataDaily[i].icon); + for (x=icons.length-1; x>=0; x--){ + $("") .appendTo(newtile) .attr('src', icons[x]); + } + + $("
") .appendTo(newtile) .text(foreDataDaily[i].temperature); + $("
") .appendTo(newtile) .text(foreDataDaily[i+1].temperature); + + $('#forecast-tiles').append(newtile); + } + + $('#forecast-tiles').css('display','flex'); + }, + + hourly() { + var newtile, icons, sizer, highbar, + indexes = calcHourlyReport(foreDataHourly), + data, label, temps=[]; + + $('#forecast-title').text( buildHourlyHeaderTitle(foreDataHourly[indexes[0]].startTime) ); + $('#forecast-tiles').empty(); + + for (var i of indexes) { + data = foreDataHourly[i]; + + newtile = $("
"); + sizer = $("
").appendTo(newtile); + + icons = mapNWSicons(data.icon); + for (var x=icons.length-1; x>=0; x--){ + $("") .appendTo(sizer) .attr('src', icons[x]); + } + + $("") .appendTo(newtile) .text(buildHourlyTimeTitle(data.startTime)); + + highbar = $("
") .appendTo(sizer); + + $("
") .appendTo(highbar) .text(data.temperature); + temps.push(data.temperature); + + $("
") .appendTo(highbar); + + $('#forecast-tiles').append(newtile); + } + + $('#forecast-tiles').css('display','flex'); + + // animate grow and show temp + var min = Math.min(...temps), // 54 + max = Math.max(...temps), // 73 + range = (max-min), + prange = (95-78), // percent range for bar height + temp, value; + $('.forecast-tile').each(function(){ + temp = $(this).find('.high').first().text(); + value = ((temp-min)/range) * prange + 78; // find percentage of range and translate to percent and add that to the starting css % height number + $(this).find('.hourly-high').animate({height:value+"%"}, 1500,function(){ + $(this).find('.high').fadeTo('slow', 1); + }); + }) + }, + + dummy(){} + + }, + keys = Object.keys(displays); + + displays[ keys[idx] ](); + + // increment the pointer + idx = (++idx===keys.length ? 0 : idx); + + setTimeout(function(){ displayForecast(idx) }, 15000); // 15 second increment loop + + } + + function resizeText(text){ + var s = 38, + $test = $('
') .appendTo('#forecast-text') .css('font-size', s + 'px') .html(text); + $test.width($('#forecast-text').width() ); + //setTimeout(function() { + while ($test.outerHeight(true) >= ($('#forecast-text').height()) ) { + s -= 1; + $test.css('font-size', s + 'px'); + } + $('#forecast-text div') .text(text) .css('font-size', s + 'px'); + $test.remove(); + $('#forecast-tiles').hide(); + //},100); // delay is a workaround for Interstate font not updating display + } + + function possessiveForecast(text){ + return text + (text.toUpperCase() != 'OVERNIGHT' ? "'S" : '') + ' FORECAST'; + } + + +} // end Loops class + + +function buildHourlyHeaderTitle(time) { + var today = new Date(), + tomorrow = dateFns.addDays(today, 1), + sforecast = "'s Forecast"; + + // title based on the first hour reported + switch (dateFns.getHours(time)) { + + case 6: // 6 - Nextday's Forecast / Today's Forecast + // if 6am today + if (dateFns.isToday(time)) { + return dateFns.format(today, 'dddd') + sforecast; + } + case 0: // 0 - Nextday's Forecast + return dateFns.format(tomorrow, 'dddd') + sforecast; + + case 12: + return 'This Afternoon'; + + case 15: + return "Today's Forecast"; + + case 17: + return "Tonight's Forecast"; + + case 20: + return dateFns.format(today, 'ddd') + ' Night/' + dateFns.format(tomorrow, 'ddd'); + + } + +} + + +function buildHourlyTimeTitle(time){ + var hour=dateFns.getHours(time); + + if (hour===0) { + return 'midnight'; + } else if (hour===12){ + return 'noon'; + } + + return dateFns.format(time,'h a'); +} + + +// finds the intervals to report on the hourly forecast +function calcHourlyReport(data) { + var ret = [], + targets = [0, 6, 12, 15, 17, 20], // hours that we report + current = dateFns.getHours(new Date()), + now = new Date(), + //firsthour = targets[ getNextHighestIndex(targets, current) ], + start, + hour, i=0; + + switch (true) { + case (current < 3): + start = 6; + case (current < 9): + start = 12; break; + case (current < 12): + start = 15; break; + case (current < 15): + start = 17; break; + case (current < 17): + start = 20; break; + case (current < 20): + start = 0; break; + default: + start = 6; + } + + while(ret.length<4){ + + // hour must be equal or greater than current + hour = dateFns.getHours( data[i].startTime ); + if ( dateFns.isAfter(data[i].startTime, now) && (hour==start || ret.length>0) ) { + + if ( targets.indexOf(hour)>=0 ) { // it is in our target list so record its index + ret.push(i); + } + + } + i++; + } + return ret; +} + +function mapNWSicons(url){ + var map = { + skc:[26,25], + few:[28,27], + sct:[24,23], + bkn:[22,21], + ovc:[20,20], + wind_skc:[26,25,47], + wind_few:[28,27,47], + wind_sct:[24,23,47], + wind_bkn:[22,21,47], + wind_ovc:[20,20,47], + snow:[10,10], + rain_snow:[2,2], + rain_sleet:[38,38], + snow_sleet:[3,3], + fzra:[6,6], + rain_fzra:[6,6], + snow_fzra:[44,44], + sleet:[13,13], + rain:[8,8], + rain_showers:[7,7], + rain_showers_hi:[5,5], + tsra:[1,1], + tsra_sct:[29,37], + tsra_hi:[29,37], + tornado:[46,46], + hurr_warn:[45,45], + hurr_watch:[45,45], + ts_warn:[45,45], + ts_watch:[45,45], + ts_hurr_warn:[45,45], + dust:[14,14], + smoke:[16,16], + haze:[16,16], + hot:[16,16], + cold:[42,42], + blizzard:[11,11], + fog:[15,15] + }, + matches = url.match(/icons\/land\/(day|night)\/([a-z_]*)\/?([a-z_]*)/), // day or night followed by one or more condition codes + idx = {day:0, night:1}[matches[1]], + ret=[], match; + + for (i=2; i2) { + ret.push( match[2] ); + } + } + } + + // place word icons last so they render on top + if (ret.length>1 && [15,47,41,42, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 20, 31, 33, 34, 38, 39, 40, 44].indexOf( ret[1] )>-1) { + ret.swap(0,1); + } + + return ret.map(function(num){ + return 'images/icons/' + ('0'+num).slice(-2) + '.png'; + }); + +} + +/* + +wind E 14 +gusts 17 mph +humidity 58% +dew point 72(degree symbol) +heat index 95(degree symbol) / wind chill +pressure 30.02 S +visibility 10 miles +uv index High +partly cloudy + +*/ + +// sample data +/* + +https://query.yahooapis.com/v1/public/yql?format=json&q=select * from weather.forecast where woeid=2402292 + +"units":{ + "distance":"mi", + "pressure":"in", + "speed":"mph", + "temperature":"F" +}, +"title":"Yahoo! Weather - Fargo, ND, US", +"link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2402292/", +"description":"Yahoo! Weather for Fargo, ND, US", +"language":"en-us", +"lastBuildDate":"Thu, 12 Oct 2017 10:10 PM CDT", +"ttl":"60", +"location":{ + "city":"Fargo", + "country":"United States", + "region":" ND" +}, +"wind":{ + "chill":"52", + "direction":"295", + "speed":"18" +}, +"atmosphere":{ + "humidity":"54", + "pressure":"978.0", + "rising":"0", + "visibility":"16.1" +}, +"astronomy":{ + "sunrise":"7:41 am", + "sunset":"6:46 pm" +}, +"image":{ + "title":"Yahoo! Weather", + "width":"142", + "height":"18", + "link":"http://weather.yahoo.com", + "url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif" +}, +"item":{ + "title":"Conditions for Fargo, ND, US at 09:00 PM CDT", + "lat":"46.865089", + "long":"-96.829224", + "link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2402292/", + "pubDate":"Thu, 12 Oct 2017 09:00 PM CDT", + "condition":{ + "code":"27", + "date":"Thu, 12 Oct 2017 09:00 PM CDT", + "temp":"55", + "text":"Mostly Cloudy" + }, + "forecast":[ + { + "code":"30", + "date":"12 Oct 2017", + "day":"Thu", + "high":"70", + "low":"48", + "text":"Partly Cloudy" + }, + { + "code":"32", + "date":"13 Oct 2017", + "day":"Fri", + "high":"58", + "low":"37", + "text":"Sunny" + }, + { + "code":"39", + "date":"14 Oct 2017", + "day":"Sat", + "high":"49", + "low":"38", + "text":"Scattered Showers" + }, + { + "code":"34", + "date":"15 Oct 2017", + "day":"Sun", + "high":"56", + "low":"31", + "text":"Mostly Sunny" + }, + { + "code":"34", + "date":"16 Oct 2017", + "day":"Mon", + "high":"65", + "low":"35", + "text":"Mostly Sunny" + }, + { + "code":"34", + "date":"17 Oct 2017", + "day":"Tue", + "high":"65", + "low":"39", + "text":"Mostly Sunny" + }, + { + "code":"30", + "date":"18 Oct 2017", + "day":"Wed", + "high":"64", + "low":"48", + "text":"Partly Cloudy" + }, + { + "code":"30", + "date":"19 Oct 2017", + "day":"Thu", + "high":"65", + "low":"44", + "text":"Partly Cloudy" + }, + { + "code":"30", + "date":"20 Oct 2017", + "day":"Fri", + "high":"66", + "low":"49", + "text":"Partly Cloudy" + }, + { + "code":"28", + "date":"21 Oct 2017", + "day":"Sat", + "high":"61", + "low":"49", + "text":"Mostly Cloudy" + } + ], + "description":"\n
\nCurrent Conditions:\n
Mostly Cloudy\n
\n
\nForecast:\n
Thu - Partly Cloudy. High: 70Low: 48\n
Fri - Sunny. High: 58Low: 37\n
Sat - Scattered Showers. High: 49Low: 38\n
Sun - Mostly Sunny. High: 56Low: 31\n
Mon - Mostly Sunny. High: 65Low: 35\n
\n
\nFull Forecast at Yahoo! Weather\n
\n
\n
\n]]>", + "guid":{ + "isPermaLink":"false" + } + +} + + +Current Conditions:\n
Mostly Cloudy\n
\n
\n +Forecast:\n
Thu - Partly Cloudy. High: 70Low: 48\n
Fri - Sunny. High: 58Low: 37\n
Sat - Scattered Showers. High: 49Low: 38\n
Sun - Mostly Sunny. High: 56Low: 31\n
+Mon - Mostly Sunny. High: 65Low: 35\n
\n
\nFull Forecast at Yahoo! Weather\n
\n
\n
\n]]>", + "guid":{ + +*/ diff --git a/webroot/main.js b/webroot/main.js new file mode 100644 index 0000000..ec749c4 --- /dev/null +++ b/webroot/main.js @@ -0,0 +1,34 @@ + +$(function(){ + + var $main = $("#main"), + $window = $( window ), + mainHeight = $main.outerHeight(), + mainWidth = $main.outerWidth(), + mainAspect = 4/3, + resizeTimer; + + + $(window).resize( function(e) { + clearTimeout(resizeTimer); + resizeTimer = setTimeout(scaleWindow, 100); + }); + + function scaleWindow() { + var scale, windowAspect; + + windowAspect = $window.width() / $window.height(); + + if (windowAspect>=mainAspect) { + scale = $window.height() / mainHeight; + } else { + scale = $window.width() / mainWidth; + } + + $main.css({ + transform: "translate(-50%, -50%) " + "scale(" + scale + ")" + }); + } + scaleWindow(); // init + +}); \ No newline at end of file diff --git a/webroot/radar.js b/webroot/radar.js new file mode 100644 index 0000000..236f46a --- /dev/null +++ b/webroot/radar.js @@ -0,0 +1,188 @@ + +function Radar(divIDin, intervalHoursIn, zoomIn, latitudeIn, longitudeIn, withSat) { + + var map, + divID = divIDin, + intervalHours = intervalHoursIn, + zoom = zoomIn, + latitude = latitudeIn, + longitude = longitudeIn; + + this.setView = function(lat, long, zoomLevel){ + map.setView(L.latLng(lat, long), zoomLevel) + }; + + + startAnimation(); + setInterval(updatePeriod, 300000); + + function updatePeriod() { + var endDate = roundDate(new Date()), + startDate = dateFns.subHours(endDate, 3), + newAvailableTimes = L.TimeDimension.Util.explodeTimeRange(startDate, endDate, 'PT5M'); + + map.timeDimension.setAvailableTimes(newAvailableTimes, 'replace'); + map.timeDimension.setCurrentTime(startDate); + } + + // snap date to 5 minute intervals + function roundDate(date) { + date.setUTCMinutes( Math.round(date.getUTCMinutes() / 5) * 5); + date.setUTCSeconds(0); + return date; + } + + function startAnimation () { + + var endDate = roundDate(new Date()), + player; + + map = L.map(divID, { + zoom: zoom, + fullscreenControl: false, + timeDimension: true, + timeDimensionControl: true, + timeDimensionOptions:{ + timeInterval: "PT" + intervalHours + "H/" + endDate.toISOString(), + period: "PT5M", + currentTime: endDate + }, + + timeDimensionControlOptions: { + autoPlay: true, + playerOptions: { + buffer: 36, + transitionTime: 100, + loop: false, + startOver:true + } + }, + center: [latitude, longitude] // 31.205482,-82.4331197 test coordinates + }); + map.timeDimensionControl._player.on('stop', function(){ + setTimeout( function() { + map.timeDimensionControl._player.setLooped(true); + map.timeDimensionControl._player.start(); + setTimeout(function(){map.timeDimensionControl._player.setLooped(false)}, 1000); + }, 1000) + }); + + + // basemap + // streets cj9fqw1e88aag2rs2al6m3ko2 + // satellite streets cj8p1qym6976p2rqut8oo6vxr + // weatherscan green cj8owq50n926g2smvagdxg9t8 + // mapbox://styles/goldbblazez/ckgc7fwvr4qmn19pevtvhyabl + // https://api.mapbox.com/styles/v1/goldbblazez/ckgc8lzdz4lzh19qt7q9wbbr9.html?fresh=true&title=copy&access_token= + L.tileLayer('https://api.mapbox.com/styles/v1/goldbblazez/ckgc8lzdz4lzh19qt7q9wbbr9/tiles/{z}/{x}/{y}?access_token=putkeyhere', { + tileSize: 512, + zoomOffset: -1 + }).addTo(map); + + + var radarWMS = L.nonTiledLayer.wms("https://nowcoast.noaa.gov/arcgis/services/nowcoast/radar_meteo_imagery_nexrad_time/MapServer/WMSServer", { + layers: '1', + format: 'image/png', + transparent: true, + opacity: 0.8 + }); + + if (withSat) { + + var goes_visible_sat = L.nonTiledLayer.wms('https://nowcoast.noaa.gov/arcgis/services/nowcoast/sat_meteo_imagery_time/MapServer/WMSServer', { + layers: '9', // 9 for visible sat + format: 'image/png', + transparent: true, + opacity:0.7, + useCanvas:true + }), + satellitetimeLayer = L.timeDimension.layer.wms(goes_visible_sat, { + proxy: proxy, + updateTimeDimension: false, + cache:1 + }); + + satellitetimeLayer.addTo(map).on('timeload',function(t) { + var canvas, ctx, + imageData, data, + i, + layers = t.target._layers, + keys = Object.keys(layers); + + for (var key of keys) { + canvas = layers[key]._bufferCanvas; + + if (canvas.dataset.isAlpha){continue} + + ctx = canvas.getContext('2d'); + + imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + + var pixels = imageData.data, + brighten = 0, + contrast = 10; + for(var i = 0; i < pixels.length; i+=4){//loop through all data + + pixels[i] += brighten; + pixels[i+1] += brighten; + pixels[i+2] += brighten; + + var brightness = (pixels[i]+pixels[i+1]+pixels[i+2])/3; //get the brightness + + pixels[i] += brightness > 127 ? contrast : -contrast; + pixels[i+1] += brightness > 127 ? contrast : -contrast; + pixels[i+2] += brightness > 127 ? contrast : -contrast; + + var rgb = pixels[i] + pixels[i+1] + pixels[i+2]; + pixels[i] = pixels[i+1] = pixels[i+2] = 255; + pixels[i+3] = rgb / 3; + } + imageData.data = pixels; + + // overwrite original image + ctx.putImageData(imageData, 0, 0); + + canvas.dataset.isAlpha = true; + + } + + }); + } + + + var proxy = 'js/leaflet/proxy.php'; + var radarTimeLayer = L.timeDimension.layer.wms(radarWMS, { + proxy: proxy, + updateTimeDimension: false + }); + + radarTimeLayer.addTo(map); + + + } +} + + + + + +/* + * Workaround for 1px lines appearing in some browsers due to fractional transforms + * and resulting anti-aliasing. + * https://github.com/Leaflet/Leaflet/issues/3575 + */ + +(function(){ + //return; + var originalInitTile = L.GridLayer.prototype._initTile + L.GridLayer.include({ + _initTile: function (tile) { + originalInitTile.call(this, tile); + + var tileSize = this.getTileSize(); + + tile.style.width = tileSize.x + 1 + 'px'; + tile.style.height = tileSize.y + 1 + 'px'; + } + }); +})() diff --git a/webroot/slides-loop.js b/webroot/slides-loop.js new file mode 100644 index 0000000..a2a6bf0 --- /dev/null +++ b/webroot/slides-loop.js @@ -0,0 +1,599 @@ +/* + +headings: +RADAR < MAIN CITY < CITY 1 < CITY 2 +*/ + + // load slide data + function Slides(dataMan) { + var radarSlideDuration = 60000, + slideDelay = 10000; + // for later + var selectval = 0; + buildHeader(); + + setTimeout(nextCity, 5000); + + + // loop cities + function nextCity(){ + + advanceHeader(); + + var city = $('#info-slides-header .city.current'); + + // is radar or city? + if (city[0].dataset.woeid) { + // show slide deck for the current city + showCitySlides( dataMan.location(city[0].dataset.woeid), 0 ); + + } else { + + + // radar + showRadar(dataMan.locations[0].lat, dataMan.locations[0].long, 8); + + //setTimeout(function() { weatherAudio.playLocalRadar() }, 2000 ); + + // show for how long? + setTimeout(nextCity, 60000); + + } + + } + + + + function showRadar(lat, long, zoom) { + + weatherMan.mainMap.setView(lat, long, zoom); + + setTimeout(function() { + + // fade out info, fade in radar + $('.info-slide-content:visible').fadeOut(250, function(){ + $('.info-slide').fadeOut(250, function() { + $('.radar-slide').fadeIn(500); + }); + }); + + }, 1500); // give it time to load + + } + + + // show the set of slides for one city + function showCitySlides(location, idx) { + + var currentDisplay, + displays = { + + // Currently (10 sec) + currentConditions() { + $('.city-info-slide #subhead-title').text('Currently'); + $('.city-info-slide #subhead-city').text(location.city); + var obsData = location.observations, + strLabels = 'Humidity
Dew Point
Pressure
Wind
', + strData = + obsData(0).current.humidity + '%
' + dewPoint(parseInt(obsData(0).current.temp), parseInt(obsData(0).current.humidity)) + '
' + (obsData(0).current.pressure*0.0295301).toFixed(2) + '
' + degToCompass(obsData(0).current.wind_deg) + ' ' + Math.round(parseInt(obsData(0).current.wind_speed)) + '
'; + if (obsData(0).current.wind_gust!=undefined) { + strLabels+='Gusts
'; + strData+=obsData(0).current.wind_gust + '
'; + } else { + strLabels+='Gusts
'; + strData+='none
'; + } + var windchill = 35.74 + (0.6215 * parseInt(obsData(0).current.temp)) + (0.4275 * parseInt(obsData(0).current.temp) - 35.75) * parseInt(obsData(0).current.wind_speed) ^ 0.16; + if (windchill < parseInt(obsData(0).current.temp)) { + strLabels+='Wind Chill'; + strData+= windchill; + } else if (parseInt(obsData(0).current.temp)>=80 && parseInt(obsData(0).current.humidity)>=40 ){ + strLabels+='Heat Index'; + return 'heat index ' + heatIndex(obsData(0).current.temp, obsData(0).current.humidity) + '°'; + }; + + $('.city-info .frost-pane .labels').html(strLabels); + $('.city-info .frost-pane .data').html(strData); + + // right pane + $('.city-info .icon').css('background-image', 'url("' + getCCicon(+obsData(0).current.weather[0].id + obsData(0).current.weather[0].icon, obsData(0).current.wind_speed) + '")'); + $('.city-info .conditions').text(getCC(obsData(0).current.weather[0].id + obsData(0).current.weather[0].icon, obsData(0).current.wind_speed)); + $('.city-info .temp').text( Math.round(parseInt(obsData(0).current.temp)) ); + + fadeToContent('.city-info'); + wait(slideDelay); + + } + + // Local Doppler Radar or Radar/Satellite (15 sec, zoomed out with cloud cover) + ,localDoppler(){ + showRadar(location.lat, location.long, 8); + wait(slideDelay + 1500); + } + + // daypart / hourly + ,forecast(fidx) { + //pick between day part or local forecast + if (selectval === 0 || selectval === 1) { + var foreDataHourly = dataMan.locations[0].forecasts('hourly'); + var indexes = calcHourlyReport(foreDataHourly); + var i; + var temps=[]; + // reset tempbar animation + $('.info-slide-content.daypart .hour').each(function(){ + $('.info-slide-content.daypart .hour .tempbar').css("height", "0px") + $('.info-slide-content.daypart .hour .tempbar .temp').css("opacity", "0%"); + $('.info-slide-content.daypart .hour .tempbar .wind').css("opacity", "0%"); + i = i + 1 + }); + //hour title + $('.info-slide-content.daypart .hour.i .thing .thingtext').text(buildHourlyTimeTitle(foreDataHourly[indexes[0]].startTime)); + $('.info-slide-content.daypart .hour.ii .thing .thingtext').text(buildHourlyTimeTitle(foreDataHourly[indexes[1]].startTime)); + $('.info-slide-content.daypart .hour.iii .thing .thingtext').text(buildHourlyTimeTitle(foreDataHourly[indexes[2]].startTime)); + $('.info-slide-content.daypart .hour.iv .thing .thingtext').text(buildHourlyTimeTitle(foreDataHourly[indexes[3]].startTime)); + for (var i of indexes) { + var data = foreDataHourly[i]; + temps.push(data.temperature); + } + + $('.info-slide-content.daypart .hour.i .tempbar .temp').text(foreDataHourly[indexes[0]].temperature); + $('.info-slide-content.daypart .hour.ii .tempbar .temp').text(foreDataHourly[indexes[1]].temperature); + $('.info-slide-content.daypart .hour.iii .tempbar .temp').text(foreDataHourly[indexes[2]].temperature); + $('.info-slide-content.daypart .hour.iv .tempbar .temp').text(foreDataHourly[indexes[3]].temperature); + + $('.info-slide-content.daypart .hour.i .tempbar .wind').text(foreDataHourly[indexes[0]].windDirection + ' ' + (foreDataHourly[indexes[0]].windSpeed).replace(" mph", "")); + $('.info-slide-content.daypart .hour.ii .tempbar .wind').text(foreDataHourly[indexes[1]].windDirection + ' ' + (foreDataHourly[indexes[1]].windSpeed).replace(" mph", "")); + $('.info-slide-content.daypart .hour.iii .tempbar .wind').text(foreDataHourly[indexes[2]].windDirection + ' ' + (foreDataHourly[indexes[2]].windSpeed).replace(" mph", "")); + $('.info-slide-content.daypart .hour.iv .tempbar .wind').text(foreDataHourly[indexes[3]].windDirection + ' ' + (foreDataHourly[indexes[3]].windSpeed).replace(" mph", "")); + + $('.info-slide-content.daypart .hour.i .condition').text(buildConditions(foreDataHourly[indexes[0]].shortForecast)); + $('.info-slide-content.daypart .hour.ii .condition').text(buildConditions(foreDataHourly[indexes[1]].shortForecast)); + $('.info-slide-content.daypart .hour.iii .condition').text(buildConditions(foreDataHourly[indexes[2]].shortForecast)); + $('.info-slide-content.daypart .hour.iv .condition').text(buildConditions(foreDataHourly[indexes[3]].shortForecast)); + + $('.info-slide-content.daypart .hour.i .icon').css('background-image', 'url("' + mapNWSicons(foreDataHourly[indexes[0]].icon) + '")'); + $('.info-slide-content.daypart .hour.ii .icon').css('background-image', 'url("' + mapNWSicons(foreDataHourly[indexes[1]].icon) + '")'); + $('.info-slide-content.daypart .hour.iii .icon').css('background-image', 'url("' + mapNWSicons(foreDataHourly[indexes[2]].icon) + '")'); + $('.info-slide-content.daypart .hour.iv .icon').css('background-image', 'url("' + mapNWSicons(foreDataHourly[indexes[3]].icon) + '")'); + + function buildConditions(forecasttext) { + if (forecasttext.includes("Thunderstorms") === true) { + return forecasttext.replace(/Slight Chance/g,"Isolated").replace(/Chance/g,"Sct'd").replace(/Thunderstorms/g,"T'storms").replace(/Partly Sunny/g,"Partly Cloudy").replace(/Showers and Thunderstorms/g,"T'Storms") + } else { + return forecasttext.replace(/Slight Chance/g,"Few").replace(/Chance/g,"").replace(/Partly Sunny/g,"Partly Cloudy").replace(/Isolated/g,"Few") + } + } + function buildHourlyTimeTitle(time){ + var hour=dateFns.getHours(time); + + if (hour===0) { + return 'Midnight'; + } else if (hour===12){ + return 'Noon'; + } + return (dateFns.format(time,'h a')).replace(" ", ""); + } + //get reporting hours: 12am, 6am, 12pm, 3pm, 5pm, 8pm... + function calcHourlyReport(data) { + var ret = [], + targets = [0, 6, 12, 15, 17, 20], // hours that we report + current = dateFns.getHours(new Date()), + now = new Date(), + //firsthour = targets[ getNextHighestIndex(targets, current) ], + start, + hour, i=0; + + switch (true) { + case (current < 3): + start = 6; + case (current < 9): + start = 12; break; + case (current < 12): + start = 15; break; + case (current < 14): + start = 17; break; + case (current < 17): + start = 6; break; + case (current < 20): + start = 6; break; + default: + start = 6; + } + while(ret.length<4){ + + // hour must be equal or greater than current + hour = dateFns.getHours( data[i].startTime ); + if ( dateFns.isAfter(data[i].startTime, now) && (hour==start || ret.length>0) ) { + + if ( targets.indexOf(hour)>=0 ) { // it is in our target list so record its index + ret.push(i); + } + + } + i++; + } + return ret; + } + function buildHourlyHeaderTitle(time) { + var today = new Date(), + tomorrow = dateFns.addDays(today, 1); + + // title based on the first hour reported + switch (dateFns.getHours(time)) { + + case 6: // 6 - Nextday's Forecast / Today's Forecast + // if 6am today + if (dateFns.isToday(time)) { + return "Today's Forecast"; + } + case 0: // 0 - Nextday's Forecast + return "Tomorrow's Forecast"; + + case 12: + return "Today's Forecast"; + + case 15: + return "Today's Forecast"; + + case 17: + return "Tonight's Forecast"; + + case 20: + return "Tonight's Forecast" + + } + + } + // calculate height of tempbars + $('.city-info-slide #subhead-title').text(buildHourlyHeaderTitle(foreDataHourly[indexes[0]].startTime)); + fadeToContent('.info-slide-content.daypart') + var min = Math.min(...temps), // 54 + max = Math.max(...temps), // 73 + range = (max-min), + prange = (100-78), // percent range for bar height + hourlable = ['i', 'ii', 'iii', 'iv'], + temp, value, i = 0; + $('.info-slide-content.daypart .hour').each(function(){ + temp = foreDataHourly[indexes[i]].temperature + value = ((temp-min)/range) * prange + 78; // find percentage of range and translate to percent and add that to the starting css % height number + valueii = (value/100) * 165 // multiply percentage by max height + $('.info-slide-content.daypart .hour.' + hourlable[i] + ' .tempbar').animate({height:valueii+"px"}, 1500,function(){ + $('.info-slide-content.daypart .hour .tempbar .temp').fadeTo('slow', 1); + $('.info-slide-content.daypart .hour .tempbar .wind').fadeTo('slow', 1); + }); + i = i + 1 + }) + wait(slideDelay) + } else { + // Local Forecast -Today (10 sec) + var div = '.info-slide-content.forecast ', + forecasts = location.forecasts('daily'); + + function fillinfo() { + + fidx = (fidx===undefined ? 0 : fidx); + + $('.city-info-slide #subhead-title').text('Local Forecast'); + + // title + $(div + '.title').text( forecasts[fidx].name ); + + // content + resizeText( forecasts[fidx].detailedForecast ); + $(div + '.content').text( forecasts[fidx].detailedForecast ); + + } + + fadeToContent(div, fillinfo) + + setTimeout( function() { + + if (fidx<3) { + currentDisplay(++fidx); + } else { + wait(0); + } + + }, slideDelay) + } + selectval = selectval + 1 + if (selectval === 4) {selectval = 1} + } + + + + // Extended Forecast(5 day columns) + ,extendedForecast() { + $('.city-info-slide #subhead-title').text('Extended Forecast'); + + var foreDataDaily = dataMan.locations[0].forecasts('daily'); + var icons, weekend + startidx = (foreDataDaily[0].name==='Tonight' ? 1 : 2), + days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; + //days + $('.info-slide-content.extended-forecast .frost-pane.iw .thing').text(days[ dateFns.getDay(foreDataDaily[startidx].startTime) ]) + $('.info-slide-content.extended-forecast .frost-pane.iiw .thing').text(days[ dateFns.getDay(foreDataDaily[startidx+2].startTime) ]) + $('.info-slide-content.extended-forecast .frost-pane.iiiw .thing').text(days[ dateFns.getDay(foreDataDaily[startidx+4].startTime) ]) + $('.info-slide-content.extended-forecast .frost-pane.ivw .thing').text(days[ dateFns.getDay(foreDataDaily[startidx+6].startTime) ]) + $('.info-slide-content.extended-forecast .lfrost-pane.vw .thing .thingtext').text(days[ dateFns.getDay(foreDataDaily[startidx+8].startTime) ]) + + //icons + $('.info-slide-content.extended-forecast .frost-pane.iw .icon').css('background-image', 'url("' + mapNWSicons(foreDataDaily[startidx].icon)[0] + '")'); + $('.info-slide-content.extended-forecast .frost-pane.iiw .icon').css('background-image', 'url("' + mapNWSicons(foreDataDaily[startidx+2].icon) + '")'); + $('.info-slide-content.extended-forecast .frost-pane.iiiw .icon').css('background-image', 'url("' + mapNWSicons(foreDataDaily[startidx+4].icon) + '")'); + $('.info-slide-content.extended-forecast .frost-pane.ivw .icon').css('background-image', 'url("' + mapNWSicons(foreDataDaily[startidx+6].icon) + '")'); + $('.info-slide-content.extended-forecast .lfrost-pane.vw .icon').css('background-image', 'url("' + mapNWSicons(foreDataDaily[startidx+8].icon) + '")'); + + //conditions + $('.info-slide-content.extended-forecast .frost-pane.iw .conditions').text(builddailyconditions(foreDataDaily[startidx].shortForecast)); + $('.info-slide-content.extended-forecast .frost-pane.iiw .conditions').text(builddailyconditions(foreDataDaily[startidx+2].shortForecast)); + $('.info-slide-content.extended-forecast .frost-pane.iiiw .conditions').text(builddailyconditions(foreDataDaily[startidx+4].shortForecast)); + $('.info-slide-content.extended-forecast .frost-pane.ivw .conditions').text(builddailyconditions(foreDataDaily[startidx+6].shortForecast)); + $('.info-slide-content.extended-forecast .lfrost-pane.vw .conditions').text(builddailyconditions(foreDataDaily[startidx+8].shortForecast)); + + //high + $('.info-slide-content.extended-forecast .frost-pane.iw .temphigh').text(foreDataDaily[startidx].temperature) + $('.info-slide-content.extended-forecast .frost-pane.iiw .temphigh').text(foreDataDaily[startidx+2].temperature) + $('.info-slide-content.extended-forecast .frost-pane.iiiw .temphigh').text(foreDataDaily[startidx+4].temperature) + $('.info-slide-content.extended-forecast .frost-pane.ivw .temphigh').text(foreDataDaily[startidx+6].temperature) + $('.info-slide-content.extended-forecast .lfrost-pane.vw .temphigh .temphightext').text(foreDataDaily[startidx+8].temperature) + + //low + $('.info-slide-content.extended-forecast .frost-pane.iw .templow').text(foreDataDaily[startidx+1].temperature) + $('.info-slide-content.extended-forecast .frost-pane.iiw .templow').text(foreDataDaily[startidx+3].temperature) + $('.info-slide-content.extended-forecast .frost-pane.iiiw .templow').text(foreDataDaily[startidx+5].temperature) + $('.info-slide-content.extended-forecast .frost-pane.ivw .templow').text(foreDataDaily[startidx+7].temperature) + $('.info-slide-content.extended-forecast .lfrost-pane.vw .templow').text(foreDataDaily[startidx+9].temperature) + + function builddailyconditions(dailyconditiontext) { + if (dailyconditiontext.includes("then") === true){ + var splitdc = dailyconditiontext.split("then") + if (dailyconditiontext.includes("Thunderstorms") === true) { + splitdc[0] = splitdc[0].replace(/Slight Chance/g,"Isolated").replace(/Chance/g,"Sct'd").replace(/Thunderstorms/g,"T'storms").replace(/Partly Sunny/g,"Partly Cloudy").replace(/Showers and Thunderstorms/g,"T'Storms").replace(/Patchy/g,"").replace(/Cloudy/g,"Clouds").replace(/Sunny/g,"Sun") + splitdc[1] = splitdc[1].replace(/Slight Chance/g,"Isolated").replace(/Chance/g,"Sct'd").replace(/Thunderstorms/g,"T'storms").replace(/Partly Sunny/g,"Partly Cloudy").replace(/Showers and Thunderstorms/g,"T'Storms").replace(/Patchy/g,"").replace(/Cloudy/g,"Clouds").replace(/Sunny/g,"Sun") + return "AM" + splitdc[0] + ", PM" + splitdc[1] + } else { + splitdc[0] = splitdc[0].replace(/Slight Chance/g,"Few").replace(/Chance/g,"").replace(/Partly Sunny/g,"Partly Cloudy").replace(/Isolated/g,"Few").replace(/Partly Sunny/g,"Partly Cloudy").replace(/Showers and Thunderstorms/g,"T'Storms").replace(/Patchy/g,"").replace(/Cloudy/g,"Clouds").replace(/Sunny/g,"Sun") + splitdc[1] = splitdc[1].replace(/Slight Chance/g,"Few").replace(/Chance/g,"").replace(/Partly Sunny/g,"Partly Cloudy").replace(/Isolated/g,"Few").replace(/Patchy/g,"").replace(/Cloudy/g,"Clouds").replace(/Sunny/g,"Sun") + return "AM" + splitdc[0] + ", PM" + splitdc[1] + } + } else { + if (dailyconditiontext.includes("Thunderstorms") === true) {return dailyconditiontext.replace(/Slight Chance/g,"Isolated").replace(/Chance/g,"Sct'd").replace(/Thunderstorms/g,"T'storms").replace(/Partly Sunny/g,"Partly Cloudy").replace(/Showers and Thunderstorms/g,"T'Storms").replace(/Patchy/g,"")} else {return dailyconditiontext.replace(/Slight Chance/g,"Few").replace(/Chance/g,"").replace(/Partly Sunny/g,"Partly Cloudy").replace(/Isolated/g,"Few").replace(/Patchy/g,"")} + } + + } + fadeToContent('.info-slide-content.extended-forecast') + wait(slideDelay) + } + + }, + keys = Object.keys(displays); + + var daypart; + if (idx
') .appendTo($container) .css('font-size', s + 'px') .html(text); + + // have to display parent so we can get measurements + $container.closest('.info-slide-content').show(); + + $test.width($container.width() ); + while ($test.outerHeight(true) >= ($container.height()) ) { + s -= 1; + $test.css('font-size', s + 'px'); + } + $container.closest('.info-slide-content').hide(); + $container .text(text) .css('font-size', s + 'px'); + $test.remove(); + + } + + + function fadeToContent(to, callfirst) { + var $to = $(to), + $parent = $to.closest('.info-slide'); + + if ( $parent.is(":hidden") ) { + // hide other visible slide then show the parent + $to.hide(); + $('.info-slide:visible').fadeOut(250, function() { + //$to.hide(); + $parent.fadeIn(250, showMe); + }); + } else { + hideOldShowMe(); + } + + function hideOldShowMe() { + if ($('.info-slide-content:visible')) { + $('.info-slide-content:visible').fadeOut(500, showMe); + } else { + showMe(); + } + } + + function showMe() { + if (callfirst) { callfirst() }; + $to.fadeIn(500); + } + + } + + //doDisplay = displays[ keys[idx] ](); + + // increment the pointer + //idx = (++idx===keys.length ? 0 : idx); + + //if (text) { + // $('#current-info').html(text); + // setTimeout(function(){ displayAtmospheric(idx) }, 6000); // 6 second increment loop + //} else { + // nothing to display - skip to the next one + // setTimeout(function(){ displayAtmospheric(idx) }, 0); + //} + + /* + (Main City) + Currently (10 sec) + Local Doppler Radar or Radar/Satellite (15 sec, zoomed out with cloud cover) + + Local Forecast + -Today (10 sec) + -Tonight (10 sec) + -Tomorrow (name day) (10 sec) + -Tomorrow (name day) Night (10 sec) + + or + + Daypart + + Extended Forecast(5 day columns) + Almanac (to be made) + + (Per City) + Local Doppler Radar (center on city) + Currently + Local Doppler Radar + Today's Forecast + Extended Forecast(5 day columns) + */ + + + + //idx++; + //if (idx<=0){ + setTimeout(cityLoop, 3000); // change to 60000 for production + //} else { + + //} + + } + + + + function advanceHeader() { + + // swap current + var $cities = $('#info-slides-header .city'), + $scroller = $('#info-slides-header .hscroller'), + left; + + $($cities[0]).removeClass('current'); + $($cities[1]).addClass('current'); + + // animate move left + left = $scroller.position().left - $($cities[1]).position().left; + $scroller.animate({ 'left': left+'px' }, 700, + function(){ + // on completion, move the old one to the end + $scroller.css('left',''); + $($cities[0]).appendTo($scroller); + $('#info-slides-header span').first().appendTo($scroller); + }) + + + } + + function buildHeader(){ + var city, first, woeid, + cities='', + arrow='<', + radar='LOCAL RADAR'; + + for (var location of dataMan.locations) { + city = location.city; + cities += arrow+'' + city + ''; + } + + $('#info-slides-header .hscroller').append(cities + arrow + (radar + cities + arrow).repeat(4)); + } + + + + +} // end function +function mapNWSicons(url){ + var map = { + skc:[26,25], + few:[28,27], + sct:[24,23], + bkn:[22,21], + ovc:[20,20], + wind_skc:[26,25,47], + wind_few:[28,27,47], + wind_sct:[24,23,47], + wind_bkn:[22,21,47], + wind_ovc:[20,20,47], + snow:[10,10], + rain_snow:[2,2], + rain_sleet:[38,38], + snow_sleet:[3,3], + fzra:[6,6], + rain_fzra:[6,6], + snow_fzra:[44,44], + sleet:[13,13], + rain:[8,8], + rain_showers:[7,7], + rain_showers_hi:[5,5], + tsra:[1,1], + tsra_sct:[29,37], + tsra_hi:[29,37], + tornado:[46,46], + hurr_warn:[45,45], + hurr_watch:[45,45], + ts_warn:[45,45], + ts_watch:[45,45], + ts_hurr_warn:[45,45], + dust:[14,14], + smoke:[16,16], + haze:[16,16], + hot:[16,16], + cold:[42,42], + blizzard:[11,11], + fog:[15,15] + }, + matches = url.match(/icons\/land\/(day|night)\/([a-z_]*)\/?([a-z_]*)/), // day or night followed by one or more condition codes + idx = {day:0, night:1}[matches[1]], + ret=[], match; + + for (i=2; i2) { + ret.push( match[2] ); + } + } + } + + // place word icons last so they render on top + if (ret.length>1 && [15,47,41,42, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 20, 31, 33, 34, 38, 39, 40, 44].indexOf( ret[1] )>-1) { + ret.swap(0,1); + } + + return ret.map(function(num){ + return 'images/icons/' + ('0'+num).slice(-2) + '.png'; + }); + +} diff --git a/webroot/utils.js b/webroot/utils.js new file mode 100644 index 0000000..6dad8a0 --- /dev/null +++ b/webroot/utils.js @@ -0,0 +1,113 @@ +// Fisher-Yates shuffle +function shuffle (array) { + var i = 0, + j = 0, + temp = null; + + for (i = array.length - 1; i > 0; i -= 1) { + j = Math.floor(Math.random() * (i + 1)); + temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + + return array; +} + +function getRandom(min, max) { + return Math.random() * (max - min) + min; +} + + +function getNextHighestIndex(arr, value) { + var i = arr.length; + while (arr[--i] > value); + return ++i; +} + + +function getUrlParameter(e) { + return decodeURI((new RegExp(e + "=(.+?)(&|$)").exec(location.search) || [, null])[1]) +} + + + +// convert celsius to farenheight +function C2F(c){ + return Math.round( c * 9 / 5 + 32 ); +} + + +// meters per second to mph +function mps2mph(meters) { + return Math.round( parseFloat(meters) * 2.23694 ); +} + + +// array swap +Array.prototype.swap = function(a,b){ var tmp=this[a];this[a]=this[b];this[b]=tmp;}; + + +function degToCompass(deg){ + val = Math.round((deg/22.5)+.5); + arr=["N","NE","E","SE","S","SW","W","NW"]; + return arr[(val % 8)]; +} + + + +function distance(lat1, lon1, lat2, lon2) { + var radlat1 = Math.PI * lat1/180, + radlat2 = Math.PI * lat2/180, + theta = lon1-lon2, + radtheta = Math.PI * theta/180, + dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta); + dist = Math.acos(dist); + dist = dist * 180/Math.PI; + dist = dist * 60 * 1.1515; + return dist; +} + + +function dewPoint(tem, r){ + tem = -1.0*(tem-32)*5/9 ; + es = 6.112*Math.exp(-1.0*17.67*tem/(243.5 - tem)); + ed = r/100.0*es; + eln = Math.log(ed/6.112); + td = -243.5*eln/(eln - 17.67 ); + return Math.round( (td*9/5)+32 ); +} + +function heatIndex(T, R) { // T = temp, R = relative humidity + var T2 = T*T, R2= R*R, + c1 = -42.379, c2 = 2.04901523, c3 = 10.14333127, + c4 = -0.22475541, c5 = -6.83783*Math.pow(10,-3), c6 = -5.481717*Math.pow(10,-2), + c7 = 1.22874*Math.pow(10,-3), c8 = 8.5282*Math.pow(10,-4), c9 = -1.99*Math.pow(10,-6); + + return Math.round(c1 + c2*T + c3 *R + c4*T*R + c5*T2 + c6*R2 + c7*T2*R + c8*T*R2 + c9*T2*R2); +} + + +// maps current condition code to icon +function getCCicon(ccCode, windData){ + var icon = "images/icons/" + ( "0" + {"20011d":1,"20011n":1,"20111d":1,"20111n":1,"20211d":1,"20211n":1,"21011d":46,"21011n":46,"21111d":46,"21111n":46,"21211d":46,"21211n":46,"22111d":1,"22111n":1,"23011d":1,"23011n":1,"23111d":1,"23111n":1,"23211d":1,"23211n":1,"30009d":5,"30009n":5,"30109d":5,"30109n":5,"30209d":5,"30209n":5,"31009d":5,"31009n":5,"31109d":5,"31109n":5,"31209d":5,"31209n":5,"31309d":5,"31309n":5,"31409d":5,"31409n":5,"32109d":5,"32109n":5,"50010d":7,"50010n":7,"50110d":8,"50110n":8,"50210d":31,"50210n":31,"50310d":31,"50310n":31,"50410d":31,"50410d":31,"51110d":6,"51110n":6,"52010d":7,"52010n":7,"52110d":8,"52110n":8,"52210d":31,"52210n":31,"53110d":29,"53110n":37,"60013d":10,"60013n":10,"60113d":12,"60113n":12,"60213d":33,"60213n":33,"61113d":13,"61113n":13,"61213d":13,"61213n":13,"61313d":13,"61313n":13,"61513d":2,"61513n":2,"61613d":2,"61613n":2,"62013d":10,"62013n":10,"62113d":12,"62113n":12,"62213d":33,"62213n":33,"70150d":15,"70150n":15,"71150d":14,"71150n":14,"72150d":16,"72150n":16,"73150d":16,"73150n":16,"74150d":15,"74150n":15,"75150d":16,"75150n":16,"76150d":14,"76150n":14,"76250d":14,"76250n":14,"77150d":18,"77150n":18,"78150d":1,"78150n":1,"80001d":26,"80001n":25,"80102d":28,"80102n":27,"80203d":22,"80203n":21,"80304d":24,"80304n":23,"80404d":20,"80404n":20}[ccCode]).slice(-2) + ".png"; + if (parseInt(windData) >= 20) { + if (ccCode === "50110d" || "50110n" || "52110d" || "52110d") { + icon = "images/icons/45.png" + } + if (ccCode === "60113d" || "60113n" || "62113d" || "62113n") { + icon = "images/icons/34.png" + } + } + return icon +} +function getCC(ccCode, windData){ + var condition = {"20011d":"Light Thunderstorm","20011n":"Light Thunderstorm","20111d":"Thunderstorm","20111n":"Thunderstorm","20211d":"Heavy Thunderstorm","20211n":"Heavy Thunderstorm","21011d":"Thunder","21011n":"Thunder","21111d":"Thunder","21111n":"Thunder","21211d":"Thunder","21211n":"Thunder","22111d":"Scattered Thunderstorm","22111n":"Scattered Thunderstorm","23011d":"Light Thunderstorm","23011n":"Light Thunderstorm","23111d":"Light Thunderstorm","23111n":"Light Thunderstorm","23211d":"Light Thunderstorm","23211n":"Light Thunderstorm","30009d":"Drizzle","30009n":"Drizzle","30109d":"Drizzle","30109n":"Drizzle","30209d":"Drizzle","30209n":"Drizzle","31009d":"Drizzle","31009n":"Drizzle","31109d":"Drizzle","31109n":"Drizzle","31209d":"Drizzle","31209n":"Drizzle","31309d":"Drizzle","31309n":"Drizzle","31409d":"Drizzle","31409n":"Drizzle","32109d":"Drizzle","32109n":"Drizzle","50010d":"Light Rain","50010n":"Light Rain","50110d":"Rain","50110n":"Rain","50210d":"Heavy Rain","50210n":"Heavy Rain","50310d":"Heavy Rain","50310n":"Heavy Rain","50410d":"Heavy Rain","50410d":"Heavy Rain","51110d":"Freezing Rain","51110n":"Freezing Rain","52010d":"Light Rain Shower","52010n":"Light Rain Shower","52110d":"Rain Shower","52110n":"Rain Shower","52210d":"Heavy Rain Shower","52210n":"Heavy Rain Shower","53110d":"Scattered Rain Showers","53110n":"Scattered Rain Showers","60013d":"Light Snow","60013n":"Light snow","60113d":"Snow","60113n":"Snow","60213d":"Heavy Snow","60213n":"Heavy Snow","61113d":"Sleet","61113n":"Sleet","61213d":"Sleet","61213n":"Sleet","61313d":"Sleet","61313n":"Sleet","61513d":"Light Rain and Snow","61513n":"Light Rain and Snow","61613d":"Rain and Snow","61613n":"Rain and Snow","62013d":"Light Snow Shower","62013n":"Light Snow Shower","62113d":"Snow Shower","62113n":"Snow Shower","62213d":"Heavy Snow Shower","62213n":"Heavy Snow Shower","70150d":"Mist","70150n":"Mist","71150d":"Smoke","71150n":"Smoke","72150d":"Haze","72150n":"Haze","73150d":"Blowing Dust","73150n":"Blowing Dust","74150d":"Fog","74150n":"Fog","75150d":"Blowing Dust","75150n":"Blowing Dust","76150d":"Blowing Dust","76150n":"Blowing Dust","76250d":"Ash","76250n":"Ash","77150d":"Squalls","77150n":"Squalls","78150d":"Tornado","78150n":"Tornado","80001d":"Sunny","80001n":"Clear","80102d":"Fair","80102n":"Fair","80203d":"Partly Cloudy","80203n":"Partly Cloudy","80304d":"Mostly Cloudy","80304n":"Mostly Cloudy","80404d":"Cloudy","80404n":"Cloudy"}[ccCode] + if (parseInt(windData) >= 20) { + condition = condition + ", windy" + } + return condition + +} + +// https://date-fns.org/docs/Getting-Started diff --git a/webroot/weather.js b/webroot/weather.js new file mode 100644 index 0000000..2770937 --- /dev/null +++ b/webroot/weather.js @@ -0,0 +1,109 @@ + +function WeatherManager() { + + var mainloc + var mainMap, miniMap, slides, + dataMan, loops, // weatherAudio, + that = this; + + $(function(){ + + // init marquees + function refreshMarquee () { + + $('#marquee-container') + .marquee('destroy') + .marquee({speed: 200, pauseOnHover:true, delayBeforeStart:3000}) + .on('finished', refreshMarquee); + } + refreshMarquee(); + + + $('#marquee2').marquee({ + speed: 170, pauseOnHover: true + }); + + + weatherAudio.playCallback = function(tags) { + $('.track-info').text('playing "' + tags.title + '" by ' + tags.artist); + } + + // this little guy runs the date and time + setInterval( + function () { + var today = new Date(); + + $('#date').text( today.toString().slice(4,10).trimRight() ); + $('#time').text( today.toLocaleTimeString('en-US', { hour: 'numeric', hour12: true, minute: 'numeric', second: 'numeric' }).replace(/ /g,'') ); + } + , 1000); + + initDataPull(); + + }); + + + + function initDataPull() { + // get the main location data + // on initialization ready, init local forecast loop + // on return of fully ready, begin display loops + + // check the url for a specific location + var queryString = window.location.search; + + if (queryString) { + dataMan = createDataManager( queryString.split("?")[1] ); + } else { + + // get lat lon from user's ip + $.getJSON("http://ip-api.com/json/?callback=?", function(data) { + dataMan = createDataManager( data.lat+','+data.lon ); + mainloc = data.city + }); + + } + + function initDisplayLoops(){ + loops = new Loops(dataMan.locations[0]); + } + function initSlidesLoop() { + slides = new Slides(dataMan); + } + function createDataManager(searchString) { + var dataManager = new DataManager(); + + $(dataManager) + .on('refresh', refreshObservationDisplay) + .on('ready:main', initDisplayLoops) + .on('allinit', initSlidesLoop); + + dataManager.init(searchString); + + return dataManager; + + } + + } + + + function refreshObservationDisplay() { + var data = dataMan.locations[0].observations(0), + cond = data.current.weather[0]; + + if (mainMap===undefined) { + mainMap = that.mainMap = new Radar("radar-1", 3, 8, data.lat, data.lon, false); + miniMap = new Radar("minimap", 3, 5, data.lat, data.lon); + } + + $('#city').text(mainloc); + $('#forecast-city').text(mainloc + ':'); + $('#current-temp').text( dataMan.locations[0].temperature() ) ; + $('#conditions-icon').css('background-image', 'url("' + getCCicon(cond.id + cond.icon) + '")'); + + //weatherAudio.playCurrentConditions(cond); + + } + +} +var weatherMan = new WeatherManager();