Changeset 8680 in josm


Ignore:
Timestamp:
2015-08-22T21:32:45+02:00 (9 years ago)
Author:
simon04
Message:

fix #11755 - Update version of opening_hours.js to 3.3.0

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/data/validator/opening_hours.js

    r8223 r8680  
    1 /*
     1require=function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({1:[function(require,module,exports){if(require&&module){var i18n=require("i18next-client");module.exports=i18n}var opening_hours_resources={en:{opening_hours:{pretty:{off:"closed",SH:"school holidays",PH:"public holidays"}}},de:{opening_hours:{texts:{"unexpected token":'Unerwartetes Zeichen: "__token__" Das bedeutet, dass die Syntax an dieser Stelle nicht erkannt werden konnte.',"no string":"Der Wert (erster Parameter) ist kein String",nothing:"Der Wert enthält nichts, was ausgewertet werden könnte.","nothing useful":"Diese Regel enthält nichts nützliches. Bitte entferne diese leere Regel.","programmers joke":"Kann es sein, dass du ein Programmier bist und das Hinzufügen eines Semikolons nach jedem Statement ist zwanghaft ;) ?"+" Es ist so, dass das Semikolon in der opening_hours Syntax als Trenner für Regeln definiert ist."+" Bitte verzichte an dieser Stelle auf ein Semikolon.","interpreted as year":"Die Zahl __number__ wird als Jahr interpretiert."+' Vermutlich ist das nicht beabsichtigt. Uhrzeiten werden als "12:00" angegeben.',"rule before fallback empty":"Die Regel vor der Fallback-Regel enthält nichts nützliches","hour min seperator":'Bitte benutze ":" als Stunden/Minuten Trenner',"warnings severity":'Der Parameter optional_conf_parm["warnings_severity"] muss eine ganze Zahl zwischen (einschließlich) 0 und (einschließlich) 7 sein.'+" Gegeben: __severity__ "+", erwartet: Eine der Zahlen: __allowed__.","optional conf parm type":"Der optional_conf_parm Parameter hat einen unbekannten Typ."+" Gegeben: __given__","conf param tag key missing":'Der optional_conf_parm["tag_key"] fehlt, ist aber notwendig wegen optional_conf_parm["map_value"].',"conf param mode invalid":'Der optional_conf_parm["mode"] Parameter ist eine ungültige Zahl.'+" Gegeben: __given__"+", erwartet: Eine der Zahlen: __allowed__.","conf param unkown type":'Der optional_conf_parm["__key__"] Parameter hat einen unbekannten Typ.'+" Gegeben: __given__, erwartet: __expected__.","library bug":'Bei der Auswertung des Wertes "__value__" ist ein Fehler aufgetreten.'+" Bitte melde diesen Bug hier: __url__.__message__","use multi":'Du hast __count__ __part2__ Einzelne Regeln können mit ";" getrennt werden.',"selector multi 2a":"__what__ in einer Regel benutzt. Du kannst nur einen davon je Regel verwenden","selector multi 2b":"nicht verbundene __what__ in einer Regel benutzt. Das ist vermutlich ein Fehler."+" Gleiche Selektoren können (und sollten) immer zusammen und durch Kommas getrennt geschrieben werden."+' Beispiel für Zeitspannen "12:00-13:00,15:00-18:00".'+' Beispiel für Wochentage "Mo-We,Fr".',"selector state":"Status-Schlüsselwörter (offen, geschlossen)",comments:"Kommentare",months:"Monate",weekdays:"Wochentage",ranges:"Zeitspannen","default state":"Diese Regel, welche den Standard Status (d.h. geschlossen) für alle folgenden Regeln ändert, ist nicht die erste Regel."+" Diese Regel überschreibt alle vorherigen Regeln."+" Es kann legtim sein, den Standard Status z.B. auf geöffnet festzulegen"+" und dann nur die Zeiten, zu denen geschlossen ist, anzugeben.",vague:"Diese Regel ist nicht sehr aussagekräftig, da keine Zeit angegeben wurde."+" Bitte füge eine Zeitangabe oder einen Kommentar hinzu, um dies zu verbessern.","empty comment":"Du hast einen leeren Kommentar verwendet."+'" Bitte schreibe entweder einen Kommentar-Text oder benutze stattdessen das Schlüsselwort "unknown".',separator_for_readability:"Du hast das optionale Symbol <separator_for_readability> an der falschen Stelle benutzt."+" Bitte lies die Syntax Spezifikation um zu sehen wo es verwendet werden kann oder entferne es.","strange 24/7":'Du hast 24/7 in einer Art verwendet, welche wahrscheinlich nicht als "24 Stunden, 7 Tage die Woche" interpretiert wird.'+' Der Richtigkeit halber solltest du "open" oder "closed"'+" für diese Regel verwenden und dann die Ausnahmen angeben um das selbe Ziel zu erreichen. So ist es klarer –"+' zum Beispiel "open; Mo 12:00-14:00 off".',"public holiday":'Es wurde keine Regel für "PH" (feiertags) angegeben. Dies ist nicht sehr Aussagekräftig.__part2__'+' Bitte füge die Regel "PH off" an, wenn die Einrichtung an allen Feiertagen geschlossen ist'+' oder schreibe "Sa,Su,PH 12:00-16:00" um auszudrücken, dass Samstags, Sonntags und feiertags von 12:00-16:00 geöffnet ist.'+" Wenn du dir im Unklaren bist, versuche die Öffnungszeit zu klären. Falls das nicht möglich ist, lass die Angabe weg und ignoriere diese Warnung.","public holiday part2":' Leider ist der "tag key" (beispielsweise "opening_hours", or "lit") in opening_hours.js nicht bekannt.'+" Diese Warnung betrifft nur die Keys: __keys__. Falls deine Angabe nicht für einen dieser ist, ignoriere bitte folgenden Hinweis:",switched:'Der Selektor "__first__" wurde für eine bessere Lesbarkeit und der Vollständigkeit halber mit '+' "__second__" getauscht.',"no colon after":'Bitte Benutze kein ":" nach dem Token __token__.',"number -5 to 5":"Zahl zwischen -5 und 5 (außer 0) erwartet.","one weekday constraint":"Du kannst höchstens einen beschränkten Wochentag in einer Monats-Spanne verwenden","range contrainted weekdays":"Du kannst keine Wochentags-Spanne als Beschränkung in einer Monats-Spanne verwenden",expected:'"__symbol__" erwartet.',"range zero":'Du kannst keine __type__-Spanne mit Periode "0" verwenden.',"period one year+":'Bitte verwende keine __type__-Spannen mit Periode "1".'+' Wenn du ausdrücken willst, das eine Einrichtung ab einem bestimmten Jahr immer offen ist, benutze bitte "<year>+".',"period one":'Bitte verwende keine __type__-Spannen mit Periode "1".',"month 31":"Die Tagangabe für __month__ muss zwischen 1 und 31 liegen.","month 30":"Der Monat __month__ hat keine 31 Tage. Der letzte Tag von __month__ ist Tag 30.","month feb":'"Der Monat __month__ hat entwedet 28 oder 29 Tage (Schaltjahre)."',"point in time":"Erwarte Bindestrich (-) oder offenes Ende (+) in der Zeitspanne __calc__."+" Um mit Zeitpunkten zu arbeiten, muss der Modus für  __libraryname__ umgestellt werden."+" Vielleicht falscher OSM tag verwendet?",calculation:"Berechnung","time range continue":"Die Zeitspanne geht nicht wie erwartet weiter","period continue":'Die Zeitspannen-Periode geht nicht wie erwartet weiter. Beispiel "/01:30".',"time range mode":'__libraryname__ wurde im "Zeitspannen-Modus" aufgerufen. Zeitpunkt gefunden.',"point in time mode":'__libraryname__ wurde im "Zeitpunkt-Modus" aufgerufen. Zeitspanne gefunden.',"outside current day":"Zeitspanne beginnt außerhalb des aktuellen Tages","two midnights":"Zeitspanne welche mehrmals Mitternacht beinhaltet wird nicht untersützt","without minutes":"Zeitspanne ohne Minutenangabe angegeben. Das ist nicht sehr eindeutig!"+' Bitte verwende stattdessen folgende Syntax "__syntax__".',"outside day":"Die Zeitspanne beginnt außerhalb des aktuellen Tages","zero calculation":"Das Hinzufügen von 0 in einer variablen Zeitberechnung ändert die variable Zeit nicht."+' Bitte entferne die Zeitberechnung (Beispiel: "sunrise-(sunset-00:00)").',"calculation syntax":"Berechnung mit variabler Zeit hat nicht die korrekte Syntax",missing:'Fehlendes "__symbol__"',"(time)":"(Zeit)","bad range":"Ungültige Zeitspanne: __from__-__to__","] or more numbers":'"]" oder weitere Zahlen erwartet.',"additional rule no sense":'Eine weitere Regel an dieser Stelle ergibt keinen Sinn. Benutze einfach ";" als Trenner für Regeln.'+" Siehe https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification#explain:additional_rule_separator","unexpected token weekday range":"Unerwartes Token in Tages-Spanne: __token__","max differ":"Es sollte keinen Grund geben, mehr als __maxdiffer__ Tage von einem __name__ abzuweichen. Wenn nötig, teile uns dies bitte mit …","adding 0":"Addition von 0 verändert das Datum nicht. Bitte weglassen.","unexpected token holiday":"Unerwartes Token (in Feiertags-Auswertung): __token__","no SH defintion":"Für die Schulferien __name__ fehlen die Defintionen für das Jahr __year__"+" Du kannst diese hinzufügen: __repository_url__","no PH definition":"Der Feiertag __name__ ist für das Land __cc__ nicht definiert."+" Du kannst diese hinzufügen: __repository_url__","no PH definition state":"Der Feiertag __name__ ist für das Land __cc__ und Bundesland __state__ nicht definiert."+" Du kannst diese hinzufügen: __repository_url__","no country code":"Der Ländercode fehlt. Dieser wird benötigt um die korrekten Feiertage zu bestimmen (siehe in der README wie dieser anzugeben ist)","movable no formular":"Der bewegliche Feiertag __name__ kann nicht berechnet werden."+" Bitte füge eine entsprechende Formel hinzu.","movable not in year":"Der bewegliche Feiertag __name__ plus __days__"+" Tage befindet sich nicht mehr im selben Jahr. Aktuell nicht unterstüzt.","year range one year":"Eine Jahres-Spanne mit gleichem Jahr als Beginn und Ende ergibt keinen Sinn."+' Bitte entferne das Ende-Jahr. zum Beispiel: "__year__ May 23"',"year range reverse":"Eine Jahres-Spanne mit Beginn größer als Ende ergibt keinen Sinn."+" Bitte umdrehen.","year past":"Das Jahr liegt in der Vergangenheit.","unexpected token year range":"Unerwartetes Token in der Jahres-Spanne: __token__","week range reverse":"Du hast eine Wochen-Spanne in umgekehrter Reihenfolge oder mehrere Jahr umfassende angegeben. Dies ist aktuell nicht unterstützt.","week negative":"Du hast eine Wochennummer kleiner 1 angegeben. Korrekte Angaben sind 1-53.","week exceed":"Du hast eine Wochennummer größer als 53 angegeben. Korrekte Angaben sind 1-53.","week period less than 2":"Du hast eine Wochenperiode kleiner 2 angegeben."+' Wenn du die gesammte Spanne von __weekfrom__ bis __weekto__ angeben will, lasse "/__period__" einfach weg.',"week period greater than 26":"Du hast eine Wochen-Periode größer als 26 angegeben."+" 26.5 ist die Hälfte des Maximums von 53 Wochen pro Jahr. Damit würde eine Periode größer als 26 nur einmal pro Jahr auftreten."+' Bitte gibt den Wochen-Selektor als "week __weekfrom__" an, wenn es das ist, was du ausdrücken möchtest.',"unexpected token week range":"Unerwartetes Token in Wochen-Spanne: __token__","unexpected token month range":"Unerwartetes Token in Monats-Spanne: __token__","day range reverse":"Zeitspanne in falscher Reihenfolge. Begin ist größer als Ende.","open end":'Angegeben als "open end". Schließzeit wurde geraten.',"date parameter needed":"Datumsparameter nötig."},pretty:{off:"geschlossen",SH:"Schulferien",PH:"Feiertags"}}}};if(!i18n.isInitialized()){i18n.init({fallbackLng:"en",resStore:opening_hours_resources,getAsync:true,useCookie:true,debug:true})}else{for(lang in opening_hours_resources){i18n.addResourceBundle(lang,"opening_hours",opening_hours_resources[lang]["opening_hours"],true)}}},{"i18next-client":"i18next-client"}],2:[function(require,module,exports){/*
     2 Copyright (c) 2011-2013, Vladimir Agafonkin
     3 SunCalc is a JavaScript library for calculating sun position, sunlight phases, and moon position.
     4 https://github.com/mourner/suncalc
     5 */
     6(function(global){"use strict";var SunCalc;if(typeof exports!=="undefined"){SunCalc=exports}else{SunCalc=global.SunCalc={}}var PI=Math.PI,rad=PI/180,sin=Math.sin,cos=Math.cos,tan=Math.tan,asin=Math.asin,atan=Math.atan2,acos=Math.acos;var dayMs=1e3*60*60*24,J1970=2440588,J2000=2451545;function toJulian(date){return date.valueOf()/dayMs-.5+J1970}function fromJulian(j){return new Date((j+.5-J1970)*dayMs)}function toDays(date){return toJulian(date)-J2000}var e=rad*23.4397;function getRightAscension(l,b){return atan(sin(l)*cos(e)-tan(b)*sin(e),cos(l))}function getDeclination(l,b){return asin(sin(b)*cos(e)+cos(b)*sin(e)*sin(l))}function getAzimuth(H,phi,dec){return atan(sin(H),cos(H)*sin(phi)-tan(dec)*cos(phi))}function getAltitude(H,phi,dec){return asin(sin(phi)*sin(dec)+cos(phi)*cos(dec)*cos(H))}function getSiderealTime(d,lw){return rad*(280.16+360.9856235*d)-lw}function getSolarMeanAnomaly(d){return rad*(357.5291+.98560028*d)}function getEquationOfCenter(M){return rad*(1.9148*sin(M)+.02*sin(2*M)+3e-4*sin(3*M))}function getEclipticLongitude(M,C){var P=rad*102.9372;return M+C+P+PI}function getSunCoords(d){var M=getSolarMeanAnomaly(d),C=getEquationOfCenter(M),L=getEclipticLongitude(M,C);return{dec:getDeclination(L,0),ra:getRightAscension(L,0)}}SunCalc.getPosition=function(date,lat,lng){var lw=rad*-lng,phi=rad*lat,d=toDays(date),c=getSunCoords(d),th=getSiderealTime(d,lw),H=th-c.ra;return{azimuth:getAzimuth(H,phi,c.dec),altitude:getAltitude(H,phi,c.dec)}};var times=[[-.83,"sunrise","sunset"],[-.3,"sunriseEnd","sunsetStart"],[-6,"dawn","dusk"],[-12,"nauticalDawn","nauticalDusk"],[-18,"nightEnd","night"],[6,"goldenHourEnd","goldenHour"]];SunCalc.addTime=function(angle,riseName,setName){times.push([angle,riseName,setName])};var J0=9e-4;function getJulianCycle(d,lw){return Math.round(d-J0-lw/(2*PI))}function getApproxTransit(Ht,lw,n){return J0+(Ht+lw)/(2*PI)+n}function getSolarTransitJ(ds,M,L){return J2000+ds+.0053*sin(M)-.0069*sin(2*L)}function getHourAngle(h,phi,d){return acos((sin(h)-sin(phi)*sin(d))/(cos(phi)*cos(d)))}SunCalc.getTimes=function(date,lat,lng){var lw=rad*-lng,phi=rad*lat,d=toDays(date),n=getJulianCycle(d,lw),ds=getApproxTransit(0,lw,n),M=getSolarMeanAnomaly(ds),C=getEquationOfCenter(M),L=getEclipticLongitude(M,C),dec=getDeclination(L,0),Jnoon=getSolarTransitJ(ds,M,L);function getSetJ(h){var w=getHourAngle(h,phi,dec),a=getApproxTransit(w,lw,n);return getSolarTransitJ(a,M,L)}var result={solarNoon:fromJulian(Jnoon),nadir:fromJulian(Jnoon-.5)};var i,len,time,angle,morningName,eveningName,Jset,Jrise;for(i=0,len=times.length;i<len;i+=1){time=times[i];angle=time[0];morningName=time[1];eveningName=time[2];Jset=getSetJ(angle*rad);Jrise=Jnoon-(Jset-Jnoon);result[morningName]=fromJulian(Jrise);result[eveningName]=fromJulian(Jset)}return result};function getMoonCoords(d){var L=rad*(218.316+13.176396*d),M=rad*(134.963+13.064993*d),F=rad*(93.272+13.22935*d),l=L+rad*6.289*sin(M),b=rad*5.128*sin(F),dt=385001-20905*cos(M);return{ra:getRightAscension(l,b),dec:getDeclination(l,b),dist:dt}}SunCalc.getMoonPosition=function(date,lat,lng){var lw=rad*-lng,phi=rad*lat,d=toDays(date),c=getMoonCoords(d),H=getSiderealTime(d,lw)-c.ra,h=getAltitude(H,phi,c.dec);h=h+.017*rad/tan(h+10.26*rad/(h+5.1*rad));return{azimuth:getAzimuth(H,phi,c.dec),altitude:h,distance:c.dist}};SunCalc.getMoonFraction=function(date){var d=toDays(date),s=getSunCoords(d),m=getMoonCoords(d),sdist=149598e3,phi=acos(sin(s.dec)*sin(m.dec)+cos(s.dec)*cos(m.dec)*cos(s.ra-m.ra)),inc=atan(sdist*sin(phi),m.dist-sdist*cos(phi));return(1+cos(inc))/2}})(this)},{}],"i18next-client":[function(require,module,exports){(function(root){if(!Array.prototype.indexOf){Array.prototype.indexOf=function(searchElement){"use strict";if(this==null){throw new TypeError}var t=Object(this);var len=t.length>>>0;if(len===0){return-1}var n=0;if(arguments.length>0){n=Number(arguments[1]);if(n!=n){n=0}else if(n!=0&&n!=Infinity&&n!=-Infinity){n=(n>0||-1)*Math.floor(Math.abs(n))}}if(n>=len){return-1}var k=n>=0?n:Math.max(len-Math.abs(n),0);for(;k<len;k++){if(k in t&&t[k]===searchElement){return k}}return-1}}if(!Array.prototype.lastIndexOf){Array.prototype.lastIndexOf=function(searchElement){"use strict";if(this==null){throw new TypeError}var t=Object(this);var len=t.length>>>0;if(len===0){return-1}var n=len;if(arguments.length>1){n=Number(arguments[1]);if(n!=n){n=0}else if(n!=0&&n!=1/0&&n!=-(1/0)){n=(n>0||-1)*Math.floor(Math.abs(n))}}var k=n>=0?Math.min(n,len-1):len-Math.abs(n);for(;k>=0;k--){if(k in t&&t[k]===searchElement){return k}}return-1}}if(typeof String.prototype.trim!=="function"){String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}}var $=root.jQuery||root.Zepto,i18n={},resStore={},currentLng,replacementCounter=0,languages=[],initialized=false,sync={},conflictReference=null;if(typeof module!=="undefined"&&module.exports){module.exports=i18n}else{if($){$.i18n=$.i18n||i18n}if(root.i18n){conflictReference=root.i18n}root.i18n=i18n}sync={load:function(lngs,options,cb){if(options.useLocalStorage){sync._loadLocal(lngs,options,function(err,store){var missingLngs=[];for(var i=0,len=lngs.length;i<len;i++){if(!store[lngs[i]])missingLngs.push(lngs[i])}if(missingLngs.length>0){sync._fetch(missingLngs,options,function(err,fetched){f.extend(store,fetched);sync._storeLocal(fetched);cb(err,store)})}else{cb(err,store)}})}else{sync._fetch(lngs,options,function(err,store){cb(err,store)})}},_loadLocal:function(lngs,options,cb){var store={},nowMS=(new Date).getTime();if(window.localStorage){var todo=lngs.length;f.each(lngs,function(key,lng){var local=f.localStorage.getItem("res_"+lng);if(local){local=JSON.parse(local);if(local.i18nStamp&&local.i18nStamp+options.localStorageExpirationTime>nowMS){store[lng]=local}}todo--;if(todo===0)cb(null,store)})}},_storeLocal:function(store){if(window.localStorage){for(var m in store){store[m].i18nStamp=(new Date).getTime();f.localStorage.setItem("res_"+m,JSON.stringify(store[m]))}}return},_fetch:function(lngs,options,cb){var ns=options.ns,store={};if(!options.dynamicLoad){var todo=ns.namespaces.length*lngs.length,errors;f.each(ns.namespaces,function(nsIndex,nsValue){f.each(lngs,function(lngIndex,lngValue){var loadComplete=function(err,data){if(err){errors=errors||[];errors.push(err)}store[lngValue]=store[lngValue]||{};store[lngValue][nsValue]=data;todo--;if(todo===0)cb(errors,store)};if(typeof options.customLoad=="function"){options.customLoad(lngValue,nsValue,options,loadComplete)}else{sync._fetchOne(lngValue,nsValue,options,loadComplete)}})})}else{var loadComplete=function(err,data){cb(err,data)};if(typeof options.customLoad=="function"){options.customLoad(lngs,ns.namespaces,options,loadComplete)}else{var url=applyReplacement(options.resGetPath,{lng:lngs.join("+"),ns:ns.namespaces.join("+")});f.ajax({url:url,cache:options.cache,success:function(data,status,xhr){f.log("loaded: "+url);loadComplete(null,data)},error:function(xhr,status,error){f.log("failed loading: "+url);loadComplete("failed loading resource.json error: "+error)},dataType:"json",async:options.getAsync,timeout:options.ajaxTimeout})}}},_fetchOne:function(lng,ns,options,done){var url=applyReplacement(options.resGetPath,{lng:lng,ns:ns});f.ajax({url:url,cache:options.cache,success:function(data,status,xhr){f.log("loaded: "+url);done(null,data)},error:function(xhr,status,error){if(status&&status==200||xhr&&xhr.status&&xhr.status==200){f.error("There is a typo in: "+url)}else if(status&&status==404||xhr&&xhr.status&&xhr.status==404){f.log("Does not exist: "+url)}else{var theStatus=status?status:xhr&&xhr.status?xhr.status:null;f.log(theStatus+" when loading "+url)}done(error,{})},dataType:"json",async:options.getAsync,timeout:options.ajaxTimeout})},postMissing:function(lng,ns,key,defaultValue,lngs){var payload={};payload[key]=defaultValue;var urls=[];if(o.sendMissingTo==="fallback"&&o.fallbackLng[0]!==false){for(var i=0;i<o.fallbackLng.length;i++){urls.push({lng:o.fallbackLng[i],url:applyReplacement(o.resPostPath,{lng:o.fallbackLng[i],ns:ns})})}}else if(o.sendMissingTo==="current"||o.sendMissingTo==="fallback"&&o.fallbackLng[0]===false){urls.push({lng:lng,url:applyReplacement(o.resPostPath,{lng:lng,ns:ns})})}else if(o.sendMissingTo==="all"){for(var i=0,l=lngs.length;i<l;i++){urls.push({lng:lngs[i],url:applyReplacement(o.resPostPath,{lng:lngs[i],ns:ns})})}}for(var y=0,len=urls.length;y<len;y++){var item=urls[y];f.ajax({url:item.url,type:o.sendType,data:payload,success:function(data,status,xhr){f.log("posted missing key '"+key+"' to: "+item.url);var keys=key.split(".");var x=0;var value=resStore[item.lng][ns];while(keys[x]){if(x===keys.length-1){value=value[keys[x]]=defaultValue}else{value=value[keys[x]]=value[keys[x]]||{}}x++}},error:function(xhr,status,error){f.log("failed posting missing key '"+key+"' to: "+item.url)},dataType:"json",async:o.postAsync,timeout:o.ajaxTimeout})}},reload:reload};var o={lng:undefined,load:"all",preload:[],lowerCaseLng:false,returnObjectTrees:false,fallbackLng:["dev"],fallbackNS:[],detectLngQS:"setLng",detectLngFromLocalStorage:false,ns:{namespaces:["translation"],defaultNs:"translation"},fallbackOnNull:true,fallbackOnEmpty:false,fallbackToDefaultNS:false,showKeyIfEmpty:false,nsseparator:":",keyseparator:".",selectorAttr:"data-i18n",debug:false,resGetPath:"locales/__lng__/__ns__.json",resPostPath:"locales/add/__lng__/__ns__",getAsync:true,postAsync:true,resStore:undefined,useLocalStorage:false,localStorageExpirationTime:7*24*60*60*1e3,dynamicLoad:false,sendMissing:false,sendMissingTo:"fallback",sendType:"POST",interpolationPrefix:"__",interpolationSuffix:"__",defaultVariables:false,reusePrefix:"$t(",reuseSuffix:")",pluralSuffix:"_plural",pluralNotFound:["plural_not_found",Math.random()].join(""),contextNotFound:["context_not_found",Math.random()].join(""),escapeInterpolation:false,indefiniteSuffix:"_indefinite",indefiniteNotFound:["indefinite_not_found",Math.random()].join(""),setJqueryExt:true,defaultValueFromContent:true,useDataAttrOptions:false,cookieExpirationTime:undefined,useCookie:true,cookieName:"i18next",cookieDomain:undefined,objectTreeKeyHandler:undefined,postProcess:undefined,parseMissingKey:undefined,missingKeyHandler:sync.postMissing,ajaxTimeout:0,shortcutFunction:"sprintf"};function _extend(target,source){if(!source||typeof source==="function"){return target}for(var attr in source){target[attr]=source[attr]}return target}function _deepExtend(target,source){for(var prop in source)if(prop in target)_deepExtend(target[prop],source[prop]);else target[prop]=source[prop];return target}function _each(object,callback,args){var name,i=0,length=object.length,isObj=length===undefined||Object.prototype.toString.apply(object)!=="[object Array]"||typeof object==="function";if(args){if(isObj){for(name in object){if(callback.apply(object[name],args)===false){break}}}else{for(;i<length;){if(callback.apply(object[i++],args)===false){break}}}}else{if(isObj){for(name in object){if(callback.call(object[name],name,object[name])===false){break}}}else{for(;i<length;){if(callback.call(object[i],i,object[i++])===false){break}}}}return object}var _entityMap={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;","/":"&#x2F;"};function _escape(data){if(typeof data==="string"){return data.replace(/[&<>"'\/]/g,function(s){return _entityMap[s]})}else{return data}}function _ajax(options){
     7// v0.5.0 of https://github.com/goloroden/http.js
     8var getXhr=function(callback){if(window.XMLHttpRequest){return callback(null,new XMLHttpRequest)}else if(window.ActiveXObject){try{return callback(null,new ActiveXObject("Msxml2.XMLHTTP"))}catch(e){return callback(null,new ActiveXObject("Microsoft.XMLHTTP"))}}return callback(new Error)};var encodeUsingUrlEncoding=function(data){if(typeof data==="string"){return data}var result=[];for(var dataItem in data){if(data.hasOwnProperty(dataItem)){result.push(encodeURIComponent(dataItem)+"="+encodeURIComponent(data[dataItem]))}}return result.join("&")};var utf8=function(text){text=text.replace(/\r\n/g,"\n");var result="";for(var i=0;i<text.length;i++){var c=text.charCodeAt(i);if(c<128){result+=String.fromCharCode(c)}else if(c>127&&c<2048){result+=String.fromCharCode(c>>6|192);result+=String.fromCharCode(c&63|128)}else{result+=String.fromCharCode(c>>12|224);result+=String.fromCharCode(c>>6&63|128);result+=String.fromCharCode(c&63|128)}}return result};var base64=function(text){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";text=utf8(text);var result="",chr1,chr2,chr3,enc1,enc2,enc3,enc4,i=0;do{chr1=text.charCodeAt(i++);chr2=text.charCodeAt(i++);chr3=text.charCodeAt(i++);enc1=chr1>>2;enc2=(chr1&3)<<4|chr2>>4;enc3=(chr2&15)<<2|chr3>>6;enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64}else if(isNaN(chr3)){enc4=64}result+=keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4);chr1=chr2=chr3="";enc1=enc2=enc3=enc4=""}while(i<text.length);return result};var mergeHeaders=function(){var result=arguments[0];for(var i=1;i<arguments.length;i++){var currentHeaders=arguments[i];for(var header in currentHeaders){if(currentHeaders.hasOwnProperty(header)){result[header]=currentHeaders[header]}}}return result};var ajax=function(method,url,options,callback){if(typeof options==="function"){callback=options;options={}}options.cache=options.cache||false;options.data=options.data||{};options.headers=options.headers||{};options.jsonp=options.jsonp||false;options.async=options.async===undefined?true:options.async;var headers=mergeHeaders({accept:"*/*","content-type":"application/x-www-form-urlencoded;charset=UTF-8"},ajax.headers,options.headers);var payload;if(headers["content-type"]==="application/json"){payload=JSON.stringify(options.data)}else{payload=encodeUsingUrlEncoding(options.data)}if(method==="GET"){var queryString=[];if(payload){queryString.push(payload);payload=null}if(!options.cache){queryString.push("_="+(new Date).getTime())}if(options.jsonp){queryString.push("callback="+options.jsonp);queryString.push("jsonp="+options.jsonp)}queryString=queryString.join("&");if(queryString.length>1){if(url.indexOf("?")>-1){url+="&"+queryString}else{url+="?"+queryString}}if(options.jsonp){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.type="text/javascript";script.src=url;head.appendChild(script);return}}getXhr(function(err,xhr){if(err)return callback(err);xhr.open(method,url,options.async);for(var header in headers){if(headers.hasOwnProperty(header)){xhr.setRequestHeader(header,headers[header])}}xhr.onreadystatechange=function(){if(xhr.readyState===4){var data=xhr.responseText||"";if(!callback){return}callback(xhr.status,{text:function(){return data},json:function(){try{return JSON.parse(data)}catch(e){f.error("Can not parse JSON. URL: "+url);return{}}}})}};xhr.send(payload)})};var http={authBasic:function(username,password){ajax.headers["Authorization"]="Basic "+base64(username+":"+password)},connect:function(url,options,callback){return ajax("CONNECT",url,options,callback)},del:function(url,options,callback){return ajax("DELETE",url,options,callback)},get:function(url,options,callback){return ajax("GET",url,options,callback)},head:function(url,options,callback){return ajax("HEAD",url,options,callback)},headers:function(headers){ajax.headers=headers||{}},isAllowed:function(url,verb,callback){this.options(url,function(status,data){callback(data.text().indexOf(verb)!==-1)})},options:function(url,options,callback){return ajax("OPTIONS",url,options,callback)},patch:function(url,options,callback){return ajax("PATCH",url,options,callback)},post:function(url,options,callback){return ajax("POST",url,options,callback)},put:function(url,options,callback){return ajax("PUT",url,options,callback)},trace:function(url,options,callback){return ajax("TRACE",url,options,callback)}};var methode=options.type?options.type.toLowerCase():"get";http[methode](options.url,options,function(status,data){if(status===200||status===0&&data.text()){options.success(data.json(),status,null)}else{options.error(data.text(),status,null)}})}var _cookie={create:function(name,value,minutes,domain){var expires;if(minutes){var date=new Date;date.setTime(date.getTime()+minutes*60*1e3);expires="; expires="+date.toGMTString()}else expires="";domain=domain?"domain="+domain+";":"";document.cookie=name+"="+value+expires+";"+domain+"path=/"},read:function(name){var nameEQ=name+"=";var ca=document.cookie.split(";");for(var i=0;i<ca.length;i++){var c=ca[i];while(c.charAt(0)==" ")c=c.substring(1,c.length);if(c.indexOf(nameEQ)===0)return c.substring(nameEQ.length,c.length)}return null},remove:function(name){this.create(name,"",-1)}};var cookie_noop={create:function(name,value,minutes,domain){},read:function(name){return null},remove:function(name){}};var f={extend:$?$.extend:_extend,deepExtend:_deepExtend,each:$?$.each:_each,ajax:$?$.ajax:typeof document!=="undefined"?_ajax:function(){},cookie:typeof document!=="undefined"?_cookie:cookie_noop,detectLanguage:detectLanguage,escape:_escape,log:function(str){if(o.debug&&typeof console!=="undefined")console.log(str)},error:function(str){if(typeof console!=="undefined")console.error(str)},getCountyIndexOfLng:function(lng){var lng_index=0;if(lng==="nb-NO"||lng==="nn-NO"||lng==="nb-no"||lng==="nn-no")lng_index=1;return lng_index},toLanguages:function(lng,fallbackLng){var log=this.log;fallbackLng=fallbackLng||o.fallbackLng;if(typeof fallbackLng==="string")fallbackLng=[fallbackLng];function applyCase(l){var ret=l;if(typeof l==="string"&&l.indexOf("-")>-1){var parts=l.split("-");ret=o.lowerCaseLng?parts[0].toLowerCase()+"-"+parts[1].toLowerCase():parts[0].toLowerCase()+"-"+parts[1].toUpperCase()}else{ret=o.lowerCaseLng?l.toLowerCase():l}return ret}var languages=[];var whitelist=o.lngWhitelist||false;var addLanguage=function(language){if(!whitelist||whitelist.indexOf(language)>-1){languages.push(language)}else{log("rejecting non-whitelisted language: "+language)}};if(typeof lng==="string"&&lng.indexOf("-")>-1){var parts=lng.split("-");if(o.load!=="unspecific")addLanguage(applyCase(lng));if(o.load!=="current")addLanguage(applyCase(parts[this.getCountyIndexOfLng(lng)]))}else{addLanguage(applyCase(lng))}for(var i=0;i<fallbackLng.length;i++){if(languages.indexOf(fallbackLng[i])===-1&&fallbackLng[i])languages.push(applyCase(fallbackLng[i]))}return languages},regexEscape:function(str){return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},regexReplacementEscape:function(strOrFn){if(typeof strOrFn==="string"){return strOrFn.replace(/\$/g,"$$$$")}else{return strOrFn}},localStorage:{setItem:function(key,value){if(window.localStorage){try{window.localStorage.setItem(key,value)}catch(e){f.log('failed to set value for key "'+key+'" to localStorage.')}}},getItem:function(key,value){if(window.localStorage){try{return window.localStorage.getItem(key,value)}catch(e){f.log('failed to get value for key "'+key+'" from localStorage.');return undefined}}}}};function init(options,cb){if(typeof options==="function"){cb=options;options={}}options=options||{};f.extend(o,options);delete o.fixLng;if(o.functions){delete o.functions;f.extend(f,options.functions)}if(typeof o.ns=="string"){o.ns={namespaces:[o.ns],defaultNs:o.ns}}if(typeof o.fallbackNS=="string"){o.fallbackNS=[o.fallbackNS]}if(typeof o.fallbackLng=="string"||typeof o.fallbackLng=="boolean"){o.fallbackLng=[o.fallbackLng]}o.interpolationPrefixEscaped=f.regexEscape(o.interpolationPrefix);o.interpolationSuffixEscaped=f.regexEscape(o.interpolationSuffix);if(!o.lng)o.lng=f.detectLanguage();languages=f.toLanguages(o.lng);currentLng=languages[0];f.log("currentLng set to: "+currentLng);if(o.useCookie&&f.cookie.read(o.cookieName)!==currentLng){f.cookie.create(o.cookieName,currentLng,o.cookieExpirationTime,o.cookieDomain)}if(o.detectLngFromLocalStorage&&typeof document!=="undefined"&&window.localStorage){f.localStorage.setItem("i18next_lng",currentLng)}var lngTranslate=translate;if(options.fixLng){lngTranslate=function(key,options){options=options||{};options.lng=options.lng||lngTranslate.lng;return translate(key,options)};lngTranslate.lng=currentLng}pluralExtensions.setCurrentLng(currentLng);if($&&o.setJqueryExt){addJqueryFunct&&addJqueryFunct()}else{addJqueryLikeFunctionality&&addJqueryLikeFunctionality()}var deferred;if($&&$.Deferred){deferred=$.Deferred()}if(o.resStore){resStore=o.resStore;initialized=true;if(cb)cb(null,lngTranslate);if(deferred)deferred.resolve(lngTranslate);if(deferred)return deferred.promise();return}var lngsToLoad=f.toLanguages(o.lng);if(typeof o.preload==="string")o.preload=[o.preload];for(var i=0,l=o.preload.length;i<l;i++){var pres=f.toLanguages(o.preload[i]);for(var y=0,len=pres.length;y<len;y++){if(lngsToLoad.indexOf(pres[y])<0){lngsToLoad.push(pres[y])}}}i18n.sync.load(lngsToLoad,o,function(err,store){resStore=store;initialized=true;if(cb)cb(err,lngTranslate);if(deferred)(!err?deferred.resolve:deferred.reject)(err||lngTranslate)});if(deferred)return deferred.promise()}function isInitialized(){return initialized}function preload(lngs,cb){if(typeof lngs==="string")lngs=[lngs];for(var i=0,l=lngs.length;i<l;i++){if(o.preload.indexOf(lngs[i])<0){o.preload.push(lngs[i])}}return init(cb)}function addResourceBundle(lng,ns,resources,deep){if(typeof ns!=="string"){resources=ns;ns=o.ns.defaultNs}else if(o.ns.namespaces.indexOf(ns)<0){o.ns.namespaces.push(ns)}resStore[lng]=resStore[lng]||{};resStore[lng][ns]=resStore[lng][ns]||{};if(deep){f.deepExtend(resStore[lng][ns],resources)}else{f.extend(resStore[lng][ns],resources)}if(o.useLocalStorage){sync._storeLocal(resStore)}}function hasResourceBundle(lng,ns){if(typeof ns!=="string"){ns=o.ns.defaultNs}resStore[lng]=resStore[lng]||{};var res=resStore[lng][ns]||{};var hasValues=false;for(var prop in res){if(res.hasOwnProperty(prop)){hasValues=true}}return hasValues}function getResourceBundle(lng,ns){if(typeof ns!=="string"){ns=o.ns.defaultNs}resStore[lng]=resStore[lng]||{};return f.extend({},resStore[lng][ns])}function removeResourceBundle(lng,ns){if(typeof ns!=="string"){ns=o.ns.defaultNs}resStore[lng]=resStore[lng]||{};resStore[lng][ns]={};if(o.useLocalStorage){sync._storeLocal(resStore)}}function addResource(lng,ns,key,value){if(typeof ns!=="string"){resource=ns;ns=o.ns.defaultNs}else if(o.ns.namespaces.indexOf(ns)<0){o.ns.namespaces.push(ns)}resStore[lng]=resStore[lng]||{};resStore[lng][ns]=resStore[lng][ns]||{};var keys=key.split(o.keyseparator);var x=0;var node=resStore[lng][ns];var origRef=node;while(keys[x]){if(x==keys.length-1)node[keys[x]]=value;else{if(node[keys[x]]==null)node[keys[x]]={};node=node[keys[x]]}x++}if(o.useLocalStorage){sync._storeLocal(resStore)}}function addResources(lng,ns,resources){if(typeof ns!=="string"){resource=ns;ns=o.ns.defaultNs}else if(o.ns.namespaces.indexOf(ns)<0){o.ns.namespaces.push(ns)}for(var m in resources){if(typeof resources[m]==="string")addResource(lng,ns,m,resources[m])}}function setDefaultNamespace(ns){o.ns.defaultNs=ns}function loadNamespace(namespace,cb){loadNamespaces([namespace],cb)}function loadNamespaces(namespaces,cb){var opts={dynamicLoad:o.dynamicLoad,resGetPath:o.resGetPath,getAsync:o.getAsync,customLoad:o.customLoad,ns:{namespaces:namespaces,defaultNs:""}};var lngsToLoad=f.toLanguages(o.lng);if(typeof o.preload==="string")o.preload=[o.preload];for(var i=0,l=o.preload.length;i<l;i++){var pres=f.toLanguages(o.preload[i]);for(var y=0,len=pres.length;y<len;y++){if(lngsToLoad.indexOf(pres[y])<0){lngsToLoad.push(pres[y])}}}var lngNeedLoad=[];for(var a=0,lenA=lngsToLoad.length;a<lenA;a++){var needLoad=false;var resSet=resStore[lngsToLoad[a]];if(resSet){for(var b=0,lenB=namespaces.length;b<lenB;b++){if(!resSet[namespaces[b]])needLoad=true}}else{needLoad=true}if(needLoad)lngNeedLoad.push(lngsToLoad[a])}if(lngNeedLoad.length){i18n.sync._fetch(lngNeedLoad,opts,function(err,store){var todo=namespaces.length*lngNeedLoad.length;f.each(namespaces,function(nsIndex,nsValue){if(o.ns.namespaces.indexOf(nsValue)<0){o.ns.namespaces.push(nsValue)}f.each(lngNeedLoad,function(lngIndex,lngValue){resStore[lngValue]=resStore[lngValue]||{};resStore[lngValue][nsValue]=store[lngValue][nsValue];todo--;if(todo===0&&cb){if(o.useLocalStorage)i18n.sync._storeLocal(resStore);cb()}})})})}else{if(cb)cb()}}function setLng(lng,options,cb){if(typeof options==="function"){cb=options;options={}}else if(!options){options={}}options.lng=lng;return init(options,cb)}function lng(){return currentLng}function reload(cb){resStore={};setLng(currentLng,cb)}function noConflict(){window.i18next=window.i18n;if(conflictReference){window.i18n=conflictReference}else{delete window.i18n}}function addJqueryFunct(){$.t=$.t||translate;function parse(ele,key,options){if(key.length===0)return;var attr="text";if(key.indexOf("[")===0){var parts=key.split("]");key=parts[1];attr=parts[0].substr(1,parts[0].length-1)}if(key.indexOf(";")===key.length-1){key=key.substr(0,key.length-2)}var optionsToUse;if(attr==="html"){optionsToUse=o.defaultValueFromContent?$.extend({defaultValue:ele.html()},options):options;ele.html($.t(key,optionsToUse))}else if(attr==="text"){optionsToUse=o.defaultValueFromContent?$.extend({defaultValue:ele.text()},options):options;ele.text($.t(key,optionsToUse))}else if(attr==="prepend"){optionsToUse=o.defaultValueFromContent?$.extend({defaultValue:ele.html()},options):options;ele.prepend($.t(key,optionsToUse))}else if(attr==="append"){optionsToUse=o.defaultValueFromContent?$.extend({defaultValue:ele.html()},options):options;ele.append($.t(key,optionsToUse))}else if(attr.indexOf("data-")===0){var dataAttr=attr.substr("data-".length);optionsToUse=o.defaultValueFromContent?$.extend({defaultValue:ele.data(dataAttr)},options):options;var translated=$.t(key,optionsToUse);ele.data(dataAttr,translated);ele.attr(attr,translated)}else{optionsToUse=o.defaultValueFromContent?$.extend({defaultValue:ele.attr(attr)},options):options;ele.attr(attr,$.t(key,optionsToUse))}}function localize(ele,options){var key=ele.attr(o.selectorAttr);if(!key&&typeof key!=="undefined"&&key!==false)key=ele.text()||ele.val();if(!key)return;var target=ele,targetSelector=ele.data("i18n-target");if(targetSelector){target=ele.find(targetSelector)||ele}if(!options&&o.useDataAttrOptions===true){options=ele.data("i18n-options")}options=options||{};if(key.indexOf(";")>=0){var keys=key.split(";");$.each(keys,function(m,k){if(k!=="")parse(target,k,options)})}else{parse(target,key,options)}if(o.useDataAttrOptions===true)ele.data("i18n-options",options)}$.fn.i18n=function(options){return this.each(function(){localize($(this),options);var elements=$(this).find("["+o.selectorAttr+"]");elements.each(function(){localize($(this),options)})})}}function addJqueryLikeFunctionality(){function parse(ele,key,options){if(key.length===0)return;var attr="text";if(key.indexOf("[")===0){var parts=key.split("]");key=parts[1];attr=parts[0].substr(1,parts[0].length-1)}if(key.indexOf(";")===key.length-1){key=key.substr(0,key.length-2)}if(attr==="html"){ele.innerHTML=translate(key,options)}else if(attr==="text"){ele.textContent=translate(key,options)}else if(attr==="prepend"){ele.insertAdjacentHTML(translate(key,options),"afterbegin")}else if(attr==="append"){ele.insertAdjacentHTML(translate(key,options),"beforeend")}else{ele.setAttribute(attr,translate(key,options))}}function localize(ele,options){var key=ele.getAttribute(o.selectorAttr);if(!key&&typeof key!=="undefined"&&key!==false)key=ele.textContent||ele.value;if(!key)return;var target=ele,targetSelector=ele.getAttribute("i18n-target");if(targetSelector){target=ele.querySelector(targetSelector)||ele}if(key.indexOf(";")>=0){var keys=key.split(";"),index=0,length=keys.length;for(;index<length;index++){if(keys[index]!=="")parse(target,keys[index],options)}}else{parse(target,key,options)}}i18n.translateObject=function(object,options){var elements=object.querySelectorAll("["+o.selectorAttr+"]");var index=0,length=elements.length;for(;index<length;index++){localize(elements[index],options)}}}function applyReplacement(str,replacementHash,nestedKey,options){if(!str)return str;options=options||replacementHash;if(str.indexOf(options.interpolationPrefix||o.interpolationPrefix)<0)return str;var prefix=options.interpolationPrefix?f.regexEscape(options.interpolationPrefix):o.interpolationPrefixEscaped,suffix=options.interpolationSuffix?f.regexEscape(options.interpolationSuffix):o.interpolationSuffixEscaped,unEscapingSuffix="HTML"+suffix;var hash=replacementHash.replace&&typeof replacementHash.replace==="object"?replacementHash.replace:replacementHash;f.each(hash,function(key,value){var nextKey=nestedKey?nestedKey+o.keyseparator+key:key;if(typeof value==="object"&&value!==null){str=applyReplacement(str,value,nextKey,options)}else{if(options.escapeInterpolation||o.escapeInterpolation){str=str.replace(new RegExp([prefix,nextKey,unEscapingSuffix].join(""),"g"),f.regexReplacementEscape(value));str=str.replace(new RegExp([prefix,nextKey,suffix].join(""),"g"),f.regexReplacementEscape(f.escape(value)))}else{str=str.replace(new RegExp([prefix,nextKey,suffix].join(""),"g"),f.regexReplacementEscape(value))}}});return str}f.applyReplacement=applyReplacement;function applyReuse(translated,options){var comma=",";var options_open="{";var options_close="}";var opts=f.extend({},options);delete opts.postProcess;while(translated.indexOf(o.reusePrefix)!=-1){replacementCounter++;if(replacementCounter>o.maxRecursion){break}var index_of_opening=translated.lastIndexOf(o.reusePrefix);var index_of_end_of_closing=translated.indexOf(o.reuseSuffix,index_of_opening)+o.reuseSuffix.length;var token=translated.substring(index_of_opening,index_of_end_of_closing);var token_without_symbols=token.replace(o.reusePrefix,"").replace(o.reuseSuffix,"");if(index_of_end_of_closing<=index_of_opening){f.error("there is an missing closing in following translation value",translated);return""}if(token_without_symbols.indexOf(comma)!=-1){var index_of_token_end_of_closing=token_without_symbols.indexOf(comma);if(token_without_symbols.indexOf(options_open,index_of_token_end_of_closing)!=-1&&token_without_symbols.indexOf(options_close,index_of_token_end_of_closing)!=-1){var index_of_opts_opening=token_without_symbols.indexOf(options_open,index_of_token_end_of_closing);var index_of_opts_end_of_closing=token_without_symbols.indexOf(options_close,index_of_opts_opening)+options_close.length;try{opts=f.extend(opts,JSON.parse(token_without_symbols.substring(index_of_opts_opening,index_of_opts_end_of_closing)));token_without_symbols=token_without_symbols.substring(0,index_of_token_end_of_closing)}catch(e){}}}var translated_token=_translate(token_without_symbols,opts);translated=translated.replace(token,f.regexReplacementEscape(translated_token))}return translated}function hasContext(options){return options.context&&(typeof options.context=="string"||typeof options.context=="number")}function needsPlural(options,lng){return options.count!==undefined&&typeof options.count!="string"}function needsIndefiniteArticle(options){return options.indefinite_article!==undefined&&typeof options.indefinite_article!="string"&&options.indefinite_article}function exists(key,options){options=options||{};var notFound=_getDefaultValue(key,options),found=_find(key,options);return found!==undefined||found===notFound}function translate(key,options){options=options||{};if(!initialized){f.log("i18next not finished initialization. you might have called t function before loading resources finished.");return options.defaultValue||""}replacementCounter=0;return _translate.apply(null,arguments)}function _getDefaultValue(key,options){return options.defaultValue!==undefined?options.defaultValue:key}function _injectSprintfProcessor(){var values=[];for(var i=1;i<arguments.length;i++){values.push(arguments[i])}return{postProcess:"sprintf",sprintf:values}}function _translate(potentialKeys,options){if(options&&typeof options!=="object"){if(o.shortcutFunction==="sprintf"){options=_injectSprintfProcessor.apply(null,arguments)}else if(o.shortcutFunction==="defaultValue"){options={defaultValue:options}}}else{options=options||{}}if(typeof o.defaultVariables==="object"){options=f.extend({},o.defaultVariables,options)}if(potentialKeys===undefined||potentialKeys===null||potentialKeys==="")return"";if(typeof potentialKeys==="number"){potentialKeys=String(potentialKeys)}if(typeof potentialKeys==="string"){potentialKeys=[potentialKeys]}var key=potentialKeys[0];if(potentialKeys.length>1){for(var i=0;i<potentialKeys.length;i++){key=potentialKeys[i];if(exists(key,options)){break}}}var notFound=_getDefaultValue(key,options),found=_find(key,options),lngs=options.lng?f.toLanguages(options.lng,options.fallbackLng):languages,ns=options.ns||o.ns.defaultNs,parts;if(key.indexOf(o.nsseparator)>-1){parts=key.split(o.nsseparator);ns=parts[0];key=parts[1]}if(found===undefined&&o.sendMissing&&typeof o.missingKeyHandler==="function"){if(options.lng){o.missingKeyHandler(lngs[0],ns,key,notFound,lngs)}else{o.missingKeyHandler(o.lng,ns,key,notFound,lngs)}}var postProcessorsToApply;if(typeof o.postProcess==="string"&&o.postProcess!==""){postProcessorsToApply=[o.postProcess]}else if(typeof o.postProcess==="array"||typeof o.postProcess==="object"){postProcessorsToApply=o.postProcess}else{postProcessorsToApply=[]}if(typeof options.postProcess==="string"&&options.postProcess!==""){postProcessorsToApply=postProcessorsToApply.concat([options.postProcess])}else if(typeof options.postProcess==="array"||typeof options.postProcess==="object"){postProcessorsToApply=postProcessorsToApply.concat(options.postProcess)}if(found!==undefined&&postProcessorsToApply.length){postProcessorsToApply.forEach(function(postProcessor){if(postProcessors[postProcessor]){found=postProcessors[postProcessor](found,key,options)}})}var splitNotFound=notFound;if(notFound.indexOf(o.nsseparator)>-1){parts=notFound.split(o.nsseparator);splitNotFound=parts[1]}if(splitNotFound===key&&o.parseMissingKey){notFound=o.parseMissingKey(notFound)}if(found===undefined){notFound=applyReplacement(notFound,options);notFound=applyReuse(notFound,options);if(postProcessorsToApply.length){var val=_getDefaultValue(key,options);postProcessorsToApply.forEach(function(postProcessor){if(postProcessors[postProcessor]){found=postProcessors[postProcessor](val,key,options)}})}}return found!==undefined?found:notFound}function _find(key,options){options=options||{};var optionWithoutCount,translated,notFound=_getDefaultValue(key,options),lngs=languages;if(!resStore){return notFound}if(lngs[0].toLowerCase()==="cimode")return notFound;if(options.lngs)lngs=options.lngs;if(options.lng){lngs=f.toLanguages(options.lng,options.fallbackLng);if(!resStore[lngs[0]]){var oldAsync=o.getAsync;o.getAsync=false;i18n.sync.load(lngs,o,function(err,store){f.extend(resStore,store);o.getAsync=oldAsync})}}var ns=options.ns||o.ns.defaultNs;if(key.indexOf(o.nsseparator)>-1){var parts=key.split(o.nsseparator);ns=parts[0];key=parts[1]}if(hasContext(options)){optionWithoutCount=f.extend({},options);delete optionWithoutCount.context;optionWithoutCount.defaultValue=o.contextNotFound;var contextKey=ns+o.nsseparator+key+"_"+options.context;translated=translate(contextKey,optionWithoutCount);if(translated!=o.contextNotFound){return applyReplacement(translated,{context:options.context})}}if(needsPlural(options,lngs[0])){optionWithoutCount=f.extend({lngs:[lngs[0]]},options);delete optionWithoutCount.count;optionWithoutCount._origLng=optionWithoutCount._origLng||optionWithoutCount.lng||lngs[0];delete optionWithoutCount.lng;optionWithoutCount.defaultValue=o.pluralNotFound;var pluralKey;if(!pluralExtensions.needsPlural(lngs[0],options.count)){pluralKey=ns+o.nsseparator+key}else{pluralKey=ns+o.nsseparator+key+o.pluralSuffix;var pluralExtension=pluralExtensions.get(lngs[0],options.count);if(pluralExtension>=0){pluralKey=pluralKey+"_"+pluralExtension}else if(pluralExtension===1){pluralKey=ns+o.nsseparator+key}}translated=translate(pluralKey,optionWithoutCount);if(translated!=o.pluralNotFound){return applyReplacement(translated,{count:options.count,interpolationPrefix:options.interpolationPrefix,interpolationSuffix:options.interpolationSuffix})}else if(lngs.length>1){var clone=lngs.slice();clone.shift();options=f.extend(options,{lngs:clone});options._origLng=optionWithoutCount._origLng;delete options.lng;translated=translate(ns+o.nsseparator+key,options);if(translated!=o.pluralNotFound)return translated}else{optionWithoutCount.lng=optionWithoutCount._origLng;delete optionWithoutCount._origLng;translated=translate(ns+o.nsseparator+key,optionWithoutCount);return applyReplacement(translated,{count:options.count,interpolationPrefix:options.interpolationPrefix,interpolationSuffix:options.interpolationSuffix})}}if(needsIndefiniteArticle(options)){var optionsWithoutIndef=f.extend({},options);delete optionsWithoutIndef.indefinite_article;optionsWithoutIndef.defaultValue=o.indefiniteNotFound;var indefiniteKey=ns+o.nsseparator+key+(options.count&&!needsPlural(options,lngs[0])||!options.count?o.indefiniteSuffix:"");translated=translate(indefiniteKey,optionsWithoutIndef);if(translated!=o.indefiniteNotFound){return translated}}var found;var keys=key.split(o.keyseparator);for(var i=0,len=lngs.length;i<len;i++){if(found!==undefined)break;var l=lngs[i];var x=0;var value=resStore[l]&&resStore[l][ns];while(keys[x]){value=value&&value[keys[x]];x++}if(value!==undefined&&(!o.showKeyIfEmpty||value!=="")){var valueType=Object.prototype.toString.apply(value);if(typeof value==="string"){value=applyReplacement(value,options);value=applyReuse(value,options)}else if(valueType==="[object Array]"&&!o.returnObjectTrees&&!options.returnObjectTrees){value=value.join("\n");value=applyReplacement(value,options);value=applyReuse(value,options)}else if(value===null&&o.fallbackOnNull===true){value=undefined}else if(value!==null){if(!o.returnObjectTrees&&!options.returnObjectTrees){if(o.objectTreeKeyHandler&&typeof o.objectTreeKeyHandler=="function"){value=o.objectTreeKeyHandler(key,value,l,ns,options)}else{value="key '"+ns+":"+key+" ("+l+")' "+"returned an object instead of string.";f.log(value)}}else if(valueType!=="[object Number]"&&valueType!=="[object Function]"&&valueType!=="[object RegExp]"){var copy=valueType==="[object Array]"?[]:{};f.each(value,function(m){copy[m]=_translate(ns+o.nsseparator+key+o.keyseparator+m,options)});value=copy}}if(typeof value==="string"&&value.trim()===""&&o.fallbackOnEmpty===true)value=undefined;found=value}}if(found===undefined&&!options.isFallbackLookup&&(o.fallbackToDefaultNS===true||o.fallbackNS&&o.fallbackNS.length>0)){options.isFallbackLookup=true;if(o.fallbackNS.length){for(var y=0,lenY=o.fallbackNS.length;y<lenY;y++){found=_find(o.fallbackNS[y]+o.nsseparator+key,options);if(found||found===""&&o.fallbackOnEmpty===false){var foundValue=found.indexOf(o.nsseparator)>-1?found.split(o.nsseparator)[1]:found,notFoundValue=notFound.indexOf(o.nsseparator)>-1?notFound.split(o.nsseparator)[1]:notFound;if(foundValue!==notFoundValue)break}}}else{options.ns=o.ns.defaultNs;found=_find(key,options)}options.isFallbackLookup=false}return found}function detectLanguage(){var detectedLng;var whitelist=o.lngWhitelist||[];var userLngChoices=[];var qsParm=[];if(typeof window!=="undefined"){(function(){var query=window.location.search.substring(1);var params=query.split("&");for(var i=0;i<params.length;i++){var pos=params[i].indexOf("=");if(pos>0){var key=params[i].substring(0,pos);if(key==o.detectLngQS){userLngChoices.push(params[i].substring(pos+1))}}}})()}if(o.useCookie&&typeof document!=="undefined"){var c=f.cookie.read(o.cookieName);if(c)userLngChoices.push(c)}if(o.detectLngFromLocalStorage&&typeof window!=="undefined"&&window.localStorage){var lang=f.localStorage.getItem("i18next_lng");if(lang){userLngChoices.push(lang)}}if(typeof navigator!=="undefined"){if(navigator.languages){for(var i=0;i<navigator.languages.length;i++){userLngChoices.push(navigator.languages[i])}}if(navigator.userLanguage){userLngChoices.push(navigator.userLanguage)}if(navigator.language){userLngChoices.push(navigator.language)}}(function(){for(var i=0;i<userLngChoices.length;i++){var lng=userLngChoices[i];if(lng.indexOf("-")>-1){var parts=lng.split("-");lng=o.lowerCaseLng?parts[0].toLowerCase()+"-"+parts[1].toLowerCase():parts[0].toLowerCase()+"-"+parts[1].toUpperCase()}if(whitelist.length===0||whitelist.indexOf(lng)>-1){detectedLng=lng;break}}})();if(!detectedLng){detectedLng=o.fallbackLng[0]}return detectedLng}var _rules=[["ach","Acholi",[1,2],1],["af","Afrikaans",[1,2],2],["ak","Akan",[1,2],1],["am","Amharic",[1,2],1],["an","Aragonese",[1,2],2],["ar","Arabic",[0,1,2,3,11,100],5],["arn","Mapudungun",[1,2],1],["ast","Asturian",[1,2],2],["ay","Aymará",[1],3],["az","Azerbaijani",[1,2],2],["be","Belarusian",[1,2,5],4],["bg","Bulgarian",[1,2],2],["bn","Bengali",[1,2],2],["bo","Tibetan",[1],3],["br","Breton",[1,2],1],["bs","Bosnian",[1,2,5],4],["ca","Catalan",[1,2],2],["cgg","Chiga",[1],3],["cs","Czech",[1,2,5],6],["csb","Kashubian",[1,2,5],7],["cy","Welsh",[1,2,3,8],8],["da","Danish",[1,2],2],["de","German",[1,2],2],["dev","Development Fallback",[1,2],2],["dz","Dzongkha",[1],3],["el","Greek",[1,2],2],["en","English",[1,2],2],["eo","Esperanto",[1,2],2],["es","Spanish",[1,2],2],["es_ar","Argentinean Spanish",[1,2],2],["et","Estonian",[1,2],2],["eu","Basque",[1,2],2],["fa","Persian",[1],3],["fi","Finnish",[1,2],2],["fil","Filipino",[1,2],1],["fo","Faroese",[1,2],2],["fr","French",[1,2],9],["fur","Friulian",[1,2],2],["fy","Frisian",[1,2],2],["ga","Irish",[1,2,3,7,11],10],["gd","Scottish Gaelic",[1,2,3,20],11],["gl","Galician",[1,2],2],["gu","Gujarati",[1,2],2],["gun","Gun",[1,2],1],["ha","Hausa",[1,2],2],["he","Hebrew",[1,2],2],["hi","Hindi",[1,2],2],["hr","Croatian",[1,2,5],4],["hu","Hungarian",[1,2],2],["hy","Armenian",[1,2],2],["ia","Interlingua",[1,2],2],["id","Indonesian",[1],3],["is","Icelandic",[1,2],12],["it","Italian",[1,2],2],["ja","Japanese",[1],3],["jbo","Lojban",[1],3],["jv","Javanese",[0,1],13],["ka","Georgian",[1],3],["kk","Kazakh",[1],3],["km","Khmer",[1],3],["kn","Kannada",[1,2],2],["ko","Korean",[1],3],["ku","Kurdish",[1,2],2],["kw","Cornish",[1,2,3,4],14],["ky","Kyrgyz",[1],3],["lb","Letzeburgesch",[1,2],2],["ln","Lingala",[1,2],1],["lo","Lao",[1],3],["lt","Lithuanian",[1,2,10],15],["lv","Latvian",[1,2,0],16],["mai","Maithili",[1,2],2],["mfe","Mauritian Creole",[1,2],1],["mg","Malagasy",[1,2],1],["mi","Maori",[1,2],1],["mk","Macedonian",[1,2],17],["ml","Malayalam",[1,2],2],["mn","Mongolian",[1,2],2],["mnk","Mandinka",[0,1,2],18],["mr","Marathi",[1,2],2],["ms","Malay",[1],3],["mt","Maltese",[1,2,11,20],19],["nah","Nahuatl",[1,2],2],["nap","Neapolitan",[1,2],2],["nb","Norwegian Bokmal",[1,2],2],["ne","Nepali",[1,2],2],["nl","Dutch",[1,2],2],["nn","Norwegian Nynorsk",[1,2],2],["no","Norwegian",[1,2],2],["nso","Northern Sotho",[1,2],2],["oc","Occitan",[1,2],1],["or","Oriya",[2,1],2],["pa","Punjabi",[1,2],2],["pap","Papiamento",[1,2],2],["pl","Polish",[1,2,5],7],["pms","Piemontese",[1,2],2],["ps","Pashto",[1,2],2],["pt","Portuguese",[1,2],2],["pt_br","Brazilian Portuguese",[1,2],2],["rm","Romansh",[1,2],2],["ro","Romanian",[1,2,20],20],["ru","Russian",[1,2,5],4],["sah","Yakut",[1],3],["sco","Scots",[1,2],2],["se","Northern Sami",[1,2],2],["si","Sinhala",[1,2],2],["sk","Slovak",[1,2,5],6],["sl","Slovenian",[5,1,2,3],21],["so","Somali",[1,2],2],["son","Songhay",[1,2],2],["sq","Albanian",[1,2],2],["sr","Serbian",[1,2,5],4],["su","Sundanese",[1],3],["sv","Swedish",[1,2],2],["sw","Swahili",[1,2],2],["ta","Tamil",[1,2],2],["te","Telugu",[1,2],2],["tg","Tajik",[1,2],1],["th","Thai",[1],3],["ti","Tigrinya",[1,2],1],["tk","Turkmen",[1,2],2],["tr","Turkish",[1,2],1],["tt","Tatar",[1],3],["ug","Uyghur",[1],3],["uk","Ukrainian",[1,2,5],4],["ur","Urdu",[1,2],2],["uz","Uzbek",[1,2],1],["vi","Vietnamese",[1],3],["wa","Walloon",[1,2],1],["wo","Wolof",[1],3],["yo","Yoruba",[1,2],2],["zh","Chinese",[1],3]];
     9var _rulesPluralsTypes={1:function(n){return Number(n>1)},2:function(n){return Number(n!=1)},3:function(n){return 0},4:function(n){return Number(n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2)},5:function(n){return Number(n===0?0:n==1?1:n==2?2:n%100>=3&&n%100<=10?3:n%100>=11?4:5)},6:function(n){return Number(n==1?0:n>=2&&n<=4?1:2)},7:function(n){return Number(n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2)},8:function(n){return Number(n==1?0:n==2?1:n!=8&&n!=11?2:3)},9:function(n){return Number(n>=2)},10:function(n){return Number(n==1?0:n==2?1:n<7?2:n<11?3:4)},11:function(n){return Number(n==1||n==11?0:n==2||n==12?1:n>2&&n<20?2:3)},12:function(n){return Number(n%10!=1||n%100==11)},13:function(n){return Number(n!==0)},14:function(n){return Number(n==1?0:n==2?1:n==3?2:3)},15:function(n){return Number(n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?1:2)},16:function(n){return Number(n%10==1&&n%100!=11?0:n!==0?1:2)},17:function(n){return Number(n==1||n%10==1?0:1)},18:function(n){return Number(0?0:n==1?1:2)},19:function(n){return Number(n==1?0:n===0||n%100>1&&n%100<11?1:n%100>10&&n%100<20?2:3)},20:function(n){return Number(n==1?0:n===0||n%100>0&&n%100<20?1:2)},21:function(n){return Number(n%100==1?1:n%100==2?2:n%100==3||n%100==4?3:0)}};var pluralExtensions={rules:function(){var l,rules={};for(l=_rules.length;l--;){rules[_rules[l][0]]={name:_rules[l][1],numbers:_rules[l][2],plurals:_rulesPluralsTypes[_rules[l][3]]}}return rules}(),addRule:function(lng,obj){pluralExtensions.rules[lng]=obj},setCurrentLng:function(lng){if(!pluralExtensions.currentRule||pluralExtensions.currentRule.lng!==lng){var parts=lng.split("-");pluralExtensions.currentRule={lng:lng,rule:pluralExtensions.rules[parts[0]]}}},needsPlural:function(lng,count){var parts=lng.split("-");var ext;if(pluralExtensions.currentRule&&pluralExtensions.currentRule.lng===lng){ext=pluralExtensions.currentRule.rule}else{ext=pluralExtensions.rules[parts[f.getCountyIndexOfLng(lng)]]}if(ext&&ext.numbers.length<=1){return false}else{return this.get(lng,count)!==1}},get:function(lng,count){var parts=lng.split("-");function getResult(l,c){var ext;if(pluralExtensions.currentRule&&pluralExtensions.currentRule.lng===lng){ext=pluralExtensions.currentRule.rule}else{ext=pluralExtensions.rules[l]}if(ext){var i;if(ext.noAbs){i=ext.plurals(c)}else{i=ext.plurals(Math.abs(c))}var number=ext.numbers[i];if(ext.numbers.length===2&&ext.numbers[0]===1){if(number===2){number=-1}else if(number===1){number=1}}return number}else{return c===1?"1":"-1"}}return getResult(parts[f.getCountyIndexOfLng(lng)],count)}};var postProcessors={};var addPostProcessor=function(name,fc){postProcessors[name]=fc};var sprintf=function(){function get_type(variable){return Object.prototype.toString.call(variable).slice(8,-1).toLowerCase()}function str_repeat(input,multiplier){for(var output=[];multiplier>0;output[--multiplier]=input){}return output.join("")}var str_format=function(){if(!str_format.cache.hasOwnProperty(arguments[0])){str_format.cache[arguments[0]]=str_format.parse(arguments[0])}return str_format.format.call(null,str_format.cache[arguments[0]],arguments)};str_format.format=function(parse_tree,argv){var cursor=1,tree_length=parse_tree.length,node_type="",arg,output=[],i,k,match,pad,pad_character,pad_length;for(i=0;i<tree_length;i++){node_type=get_type(parse_tree[i]);if(node_type==="string"){output.push(parse_tree[i])}else if(node_type==="array"){match=parse_tree[i];if(match[2]){arg=argv[cursor];for(k=0;k<match[2].length;k++){if(!arg.hasOwnProperty(match[2][k])){throw sprintf('[sprintf] property "%s" does not exist',match[2][k])}arg=arg[match[2][k]]}}else if(match[1]){arg=argv[match[1]]}else{arg=argv[cursor++]}if(/[^s]/.test(match[8])&&get_type(arg)!="number"){throw sprintf("[sprintf] expecting number but found %s",get_type(arg))}switch(match[8]){case"b":arg=arg.toString(2);break;case"c":arg=String.fromCharCode(arg);break;case"d":arg=parseInt(arg,10);break;case"e":arg=match[7]?arg.toExponential(match[7]):arg.toExponential();break;case"f":arg=match[7]?parseFloat(arg).toFixed(match[7]):parseFloat(arg);break;case"o":arg=arg.toString(8);break;case"s":arg=(arg=String(arg))&&match[7]?arg.substring(0,match[7]):arg;break;case"u":arg=Math.abs(arg);break;case"x":arg=arg.toString(16);break;case"X":arg=arg.toString(16).toUpperCase();break}arg=/[def]/.test(match[8])&&match[3]&&arg>=0?"+"+arg:arg;pad_character=match[4]?match[4]=="0"?"0":match[4].charAt(1):" ";pad_length=match[6]-String(arg).length;pad=match[6]?str_repeat(pad_character,pad_length):"";output.push(match[5]?arg+pad:pad+arg)}}return output.join("")};str_format.cache={};str_format.parse=function(fmt){var _fmt=fmt,match=[],parse_tree=[],arg_names=0;while(_fmt){if((match=/^[^\x25]+/.exec(_fmt))!==null){parse_tree.push(match[0])}else if((match=/^\x25{2}/.exec(_fmt))!==null){parse_tree.push("%")}else if((match=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt))!==null){if(match[2]){arg_names|=1;var field_list=[],replacement_field=match[2],field_match=[];if((field_match=/^([a-z_][a-z_\d]*)/i.exec(replacement_field))!==null){field_list.push(field_match[1]);while((replacement_field=replacement_field.substring(field_match[0].length))!==""){if((field_match=/^\.([a-z_][a-z_\d]*)/i.exec(replacement_field))!==null){field_list.push(field_match[1])}else if((field_match=/^\[(\d+)\]/.exec(replacement_field))!==null){field_list.push(field_match[1])}else{throw"[sprintf] huh?"}}}else{throw"[sprintf] huh?"}match[2]=field_list}else{arg_names|=2}if(arg_names===3){throw"[sprintf] mixing positional and named placeholders is not (yet) supported"}parse_tree.push(match)}else{throw"[sprintf] huh?"}_fmt=_fmt.substring(match[0].length)}return parse_tree};return str_format}();var vsprintf=function(fmt,argv){argv.unshift(fmt);return sprintf.apply(null,argv)};addPostProcessor("sprintf",function(val,key,opts){if(!opts.sprintf)return val;if(Object.prototype.toString.apply(opts.sprintf)==="[object Array]"){return vsprintf(val,opts.sprintf)}else if(typeof opts.sprintf==="object"){return sprintf(val,opts.sprintf)}return val});i18n.init=init;i18n.isInitialized=isInitialized;i18n.setLng=setLng;i18n.preload=preload;i18n.addResourceBundle=addResourceBundle;i18n.hasResourceBundle=hasResourceBundle;i18n.getResourceBundle=getResourceBundle;i18n.addResource=addResource;i18n.addResources=addResources;i18n.removeResourceBundle=removeResourceBundle;i18n.loadNamespace=loadNamespace;i18n.loadNamespaces=loadNamespaces;i18n.setDefaultNamespace=setDefaultNamespace;i18n.t=translate;i18n.translate=translate;i18n.exists=exists;i18n.detectLanguage=f.detectLanguage;i18n.pluralExtensions=pluralExtensions;i18n.sync=sync;i18n.functions=f;i18n.lng=lng;i18n.addPostProcessor=addPostProcessor;i18n.applyReplacement=f.applyReplacement;i18n.options=o;i18n.noConflict=noConflict})(typeof exports==="undefined"?window:exports)},{}],moment:[function(require,module,exports){(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory():typeof define==="function"&&define.amd?define(factory):global.moment=factory()})(this,function(){"use strict";var hookCallback;function utils_hooks__hooks(){return hookCallback.apply(null,arguments)}function setHookCallback(callback){hookCallback=callback}function isArray(input){return Object.prototype.toString.call(input)==="[object Array]"}function isDate(input){return input instanceof Date||Object.prototype.toString.call(input)==="[object Date]"}function map(arr,fn){var res=[],i;for(i=0;i<arr.length;++i){res.push(fn(arr[i],i))}return res}function hasOwnProp(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function extend(a,b){for(var i in b){if(hasOwnProp(b,i)){a[i]=b[i]}}if(hasOwnProp(b,"toString")){a.toString=b.toString}if(hasOwnProp(b,"valueOf")){a.valueOf=b.valueOf}return a}function create_utc__createUTC(input,format,locale,strict){return createLocalOrUTC(input,format,locale,strict,true).utc()}function defaultParsingFlags(){return{empty:false,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:false,invalidMonth:null,invalidFormat:false,userInvalidated:false,iso:false}}function getParsingFlags(m){if(m._pf==null){m._pf=defaultParsingFlags()}return m._pf}function valid__isValid(m){if(m._isValid==null){var flags=getParsingFlags(m);m._isValid=!isNaN(m._d.getTime())&&flags.overflow<0&&!flags.empty&&!flags.invalidMonth&&!flags.nullInput&&!flags.invalidFormat&&!flags.userInvalidated;if(m._strict){m._isValid=m._isValid&&flags.charsLeftOver===0&&flags.unusedTokens.length===0&&flags.bigHour===undefined}}return m._isValid}function valid__createInvalid(flags){var m=create_utc__createUTC(NaN);if(flags!=null){extend(getParsingFlags(m),flags)}else{getParsingFlags(m).userInvalidated=true}return m}var momentProperties=utils_hooks__hooks.momentProperties=[];function copyConfig(to,from){var i,prop,val;if(typeof from._isAMomentObject!=="undefined"){to._isAMomentObject=from._isAMomentObject}if(typeof from._i!=="undefined"){to._i=from._i}if(typeof from._f!=="undefined"){to._f=from._f}if(typeof from._l!=="undefined"){to._l=from._l}if(typeof from._strict!=="undefined"){to._strict=from._strict}if(typeof from._tzm!=="undefined"){to._tzm=from._tzm}if(typeof from._isUTC!=="undefined"){to._isUTC=from._isUTC}if(typeof from._offset!=="undefined"){to._offset=from._offset}if(typeof from._pf!=="undefined"){to._pf=getParsingFlags(from)}if(typeof from._locale!=="undefined"){to._locale=from._locale}if(momentProperties.length>0){for(i in momentProperties){prop=momentProperties[i];val=from[prop];if(typeof val!=="undefined"){to[prop]=val}}}return to}var updateInProgress=false;function Moment(config){copyConfig(this,config);this._d=new Date(+config._d);if(updateInProgress===false){updateInProgress=true;utils_hooks__hooks.updateOffset(this);updateInProgress=false}}function isMoment(obj){return obj instanceof Moment||obj!=null&&obj._isAMomentObject!=null}function toInt(argumentForCoercion){var coercedNumber=+argumentForCoercion,value=0;if(coercedNumber!==0&&isFinite(coercedNumber)){if(coercedNumber>=0){value=Math.floor(coercedNumber)}else{value=Math.ceil(coercedNumber)}}return value}function compareArrays(array1,array2,dontConvert){var len=Math.min(array1.length,array2.length),lengthDiff=Math.abs(array1.length-array2.length),diffs=0,i;for(i=0;i<len;i++){if(dontConvert&&array1[i]!==array2[i]||!dontConvert&&toInt(array1[i])!==toInt(array2[i])){diffs++}}return diffs+lengthDiff}function Locale(){}var locales={};var globalLocale;function normalizeLocale(key){return key?key.toLowerCase().replace("_","-"):key}function chooseLocale(names){var i=0,j,next,locale,split;while(i<names.length){split=normalizeLocale(names[i]).split("-");j=split.length;next=normalizeLocale(names[i+1]);next=next?next.split("-"):null;while(j>0){locale=loadLocale(split.slice(0,j).join("-"));if(locale){return locale}if(next&&next.length>=j&&compareArrays(split,next,true)>=j-1){break}j--}i++}return null}function loadLocale(name){var oldLocale=null;if(!locales[name]&&typeof module!=="undefined"&&module&&module.exports){try{oldLocale=globalLocale._abbr;require("./locale/"+name);locale_locales__getSetGlobalLocale(oldLocale)}catch(e){}}return locales[name]}function locale_locales__getSetGlobalLocale(key,values){var data;if(key){if(typeof values==="undefined"){data=locale_locales__getLocale(key)}else{data=defineLocale(key,values)}if(data){globalLocale=data}}return globalLocale._abbr}function defineLocale(name,values){if(values!==null){values.abbr=name;if(!locales[name]){locales[name]=new Locale}locales[name].set(values);locale_locales__getSetGlobalLocale(name);return locales[name]}else{delete locales[name];return null}}function locale_locales__getLocale(key){var locale;if(key&&key._locale&&key._locale._abbr){key=key._locale._abbr}if(!key){return globalLocale}if(!isArray(key)){locale=loadLocale(key);if(locale){return locale}key=[key]}return chooseLocale(key)}var aliases={};function addUnitAlias(unit,shorthand){var lowerCase=unit.toLowerCase();aliases[lowerCase]=aliases[lowerCase+"s"]=aliases[shorthand]=unit}function normalizeUnits(units){return typeof units==="string"?aliases[units]||aliases[units.toLowerCase()]:undefined}function normalizeObjectUnits(inputObject){var normalizedInput={},normalizedProp,prop;for(prop in inputObject){if(hasOwnProp(inputObject,prop)){normalizedProp=normalizeUnits(prop);if(normalizedProp){normalizedInput[normalizedProp]=inputObject[prop]}}}return normalizedInput}function makeGetSet(unit,keepTime){return function(value){if(value!=null){get_set__set(this,unit,value);utils_hooks__hooks.updateOffset(this,keepTime);return this}else{return get_set__get(this,unit)}}}function get_set__get(mom,unit){return mom._d["get"+(mom._isUTC?"UTC":"")+unit]()}function get_set__set(mom,unit,value){return mom._d["set"+(mom._isUTC?"UTC":"")+unit](value)}function getSet(units,value){var unit;if(typeof units==="object"){for(unit in units){this.set(unit,units[unit])}}else{units=normalizeUnits(units);if(typeof this[units]==="function"){return this[units](value)}}return this}function zeroFill(number,targetLength,forceSign){var output=""+Math.abs(number),sign=number>=0;while(output.length<targetLength){output="0"+output}return(sign?forceSign?"+":"":"-")+output}var formattingTokens=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g;var localFormattingTokens=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;var formatFunctions={};var formatTokenFunctions={};function addFormatToken(token,padded,ordinal,callback){var func=callback;if(typeof callback==="string"){func=function(){return this[callback]()}}if(token){formatTokenFunctions[token]=func}if(padded){formatTokenFunctions[padded[0]]=function(){return zeroFill(func.apply(this,arguments),padded[1],padded[2])}}if(ordinal){formatTokenFunctions[ordinal]=function(){return this.localeData().ordinal(func.apply(this,arguments),token)}}}function removeFormattingTokens(input){if(input.match(/\[[\s\S]/)){return input.replace(/^\[|\]$/g,"")}return input.replace(/\\/g,"")}function makeFormatFunction(format){var array=format.match(formattingTokens),i,length;for(i=0,length=array.length;i<length;i++){if(formatTokenFunctions[array[i]]){array[i]=formatTokenFunctions[array[i]]}else{array[i]=removeFormattingTokens(array[i])}}return function(mom){var output="";for(i=0;i<length;i++){output+=array[i]instanceof Function?array[i].call(mom,format):array[i]}return output}}function formatMoment(m,format){if(!m.isValid()){return m.localeData().invalidDate()}format=expandFormat(format,m.localeData());if(!formatFunctions[format]){formatFunctions[format]=makeFormatFunction(format)}return formatFunctions[format](m)}function expandFormat(format,locale){var i=5;function replaceLongDateFormatTokens(input){return locale.longDateFormat(input)||input}localFormattingTokens.lastIndex=0;while(i>=0&&localFormattingTokens.test(format)){format=format.replace(localFormattingTokens,replaceLongDateFormatTokens);localFormattingTokens.lastIndex=0;i-=1}return format}var match1=/\d/;var match2=/\d\d/;var match3=/\d{3}/;var match4=/\d{4}/;var match6=/[+-]?\d{6}/;var match1to2=/\d\d?/;var match1to3=/\d{1,3}/;var match1to4=/\d{1,4}/;var match1to6=/[+-]?\d{1,6}/;var matchUnsigned=/\d+/;var matchSigned=/[+-]?\d+/;var matchOffset=/Z|[+-]\d\d:?\d\d/gi;var matchTimestamp=/[+-]?\d+(\.\d{1,3})?/;var matchWord=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;var regexes={};function addRegexToken(token,regex,strictRegex){regexes[token]=typeof regex==="function"?regex:function(isStrict){return isStrict&&strictRegex?strictRegex:regex}}function getParseRegexForToken(token,config){if(!hasOwnProp(regexes,token)){return new RegExp(unescapeFormat(token))}return regexes[token](config._strict,config._locale)}function unescapeFormat(s){return s.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(matched,p1,p2,p3,p4){return p1||p2||p3||p4}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}var tokens={};function addParseToken(token,callback){var i,func=callback;if(typeof token==="string"){token=[token]}if(typeof callback==="number"){func=function(input,array){array[callback]=toInt(input)}}for(i=0;i<token.length;i++){tokens[token[i]]=func}}function addWeekParseToken(token,callback){addParseToken(token,function(input,array,config,token){config._w=config._w||{};callback(input,config._w,config,token)})}function addTimeToArrayFromToken(token,input,config){if(input!=null&&hasOwnProp(tokens,token)){tokens[token](input,config._a,config,token)}}var YEAR=0;var MONTH=1;var DATE=2;var HOUR=3;var MINUTE=4;var SECOND=5;var MILLISECOND=6;function daysInMonth(year,month){return new Date(Date.UTC(year,month+1,0)).getUTCDate()}addFormatToken("M",["MM",2],"Mo",function(){return this.month()+1});addFormatToken("MMM",0,0,function(format){return this.localeData().monthsShort(this,format)});addFormatToken("MMMM",0,0,function(format){return this.localeData().months(this,format)});addUnitAlias("month","M");addRegexToken("M",match1to2);addRegexToken("MM",match1to2,match2);addRegexToken("MMM",matchWord);addRegexToken("MMMM",matchWord);addParseToken(["M","MM"],function(input,array){array[MONTH]=toInt(input)-1});addParseToken(["MMM","MMMM"],function(input,array,config,token){var month=config._locale.monthsParse(input,token,config._strict);if(month!=null){array[MONTH]=month}else{getParsingFlags(config).invalidMonth=input}});var defaultLocaleMonths="January_February_March_April_May_June_July_August_September_October_November_December".split("_");function localeMonths(m){return this._months[m.month()]}var defaultLocaleMonthsShort="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_");function localeMonthsShort(m){return this._monthsShort[m.month()]}function localeMonthsParse(monthName,format,strict){var i,mom,regex;if(!this._monthsParse){this._monthsParse=[];this._longMonthsParse=[];this._shortMonthsParse=[]}for(i=0;i<12;i++){mom=create_utc__createUTC([2e3,i]);if(strict&&!this._longMonthsParse[i]){this._longMonthsParse[i]=new RegExp("^"+this.months(mom,"").replace(".","")+"$","i");this._shortMonthsParse[i]=new RegExp("^"+this.monthsShort(mom,"").replace(".","")+"$","i")}if(!strict&&!this._monthsParse[i]){regex="^"+this.months(mom,"")+"|^"+this.monthsShort(mom,"");this._monthsParse[i]=new RegExp(regex.replace(".",""),"i")}if(strict&&format==="MMMM"&&this._longMonthsParse[i].test(monthName)){return i}else if(strict&&format==="MMM"&&this._shortMonthsParse[i].test(monthName)){return i}else if(!strict&&this._monthsParse[i].test(monthName)){return i}}}function setMonth(mom,value){var dayOfMonth;if(typeof value==="string"){value=mom.localeData().monthsParse(value);if(typeof value!=="number"){return mom}}dayOfMonth=Math.min(mom.date(),daysInMonth(mom.year(),value));mom._d["set"+(mom._isUTC?"UTC":"")+"Month"](value,dayOfMonth);return mom}function getSetMonth(value){if(value!=null){setMonth(this,value);utils_hooks__hooks.updateOffset(this,true);return this}else{return get_set__get(this,"Month")}}function getDaysInMonth(){return daysInMonth(this.year(),this.month())}function checkOverflow(m){var overflow;var a=m._a;if(a&&getParsingFlags(m).overflow===-2){overflow=a[MONTH]<0||a[MONTH]>11?MONTH:a[DATE]<1||a[DATE]>daysInMonth(a[YEAR],a[MONTH])?DATE:a[HOUR]<0||a[HOUR]>24||a[HOUR]===24&&(a[MINUTE]!==0||a[SECOND]!==0||a[MILLISECOND]!==0)?HOUR:a[MINUTE]<0||a[MINUTE]>59?MINUTE:a[SECOND]<0||a[SECOND]>59?SECOND:a[MILLISECOND]<0||a[MILLISECOND]>999?MILLISECOND:-1;if(getParsingFlags(m)._overflowDayOfYear&&(overflow<YEAR||overflow>DATE)){overflow=DATE}getParsingFlags(m).overflow=overflow}return m}function warn(msg){if(utils_hooks__hooks.suppressDeprecationWarnings===false&&typeof console!=="undefined"&&console.warn){console.warn("Deprecation warning: "+msg)}}function deprecate(msg,fn){var firstTime=true,msgWithStack=msg+"\n"+(new Error).stack;return extend(function(){if(firstTime){warn(msgWithStack);firstTime=false}return fn.apply(this,arguments)},fn)}var deprecations={};function deprecateSimple(name,msg){if(!deprecations[name]){warn(msg);deprecations[name]=true}}utils_hooks__hooks.suppressDeprecationWarnings=false;var from_string__isoRegex=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;var isoDates=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]];var isoTimes=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]];var aspNetJsonRegex=/^\/?Date\((\-?\d+)/i;function configFromISO(config){var i,l,string=config._i,match=from_string__isoRegex.exec(string);if(match){getParsingFlags(config).iso=true;for(i=0,l=isoDates.length;i<l;i++){if(isoDates[i][1].exec(string)){config._f=isoDates[i][0]+(match[6]||" ");break}}for(i=0,l=isoTimes.length;i<l;i++){if(isoTimes[i][1].exec(string)){config._f+=isoTimes[i][0];break}}if(string.match(matchOffset)){config._f+="Z"}configFromStringAndFormat(config)}else{config._isValid=false}}function configFromString(config){var matched=aspNetJsonRegex.exec(config._i);if(matched!==null){config._d=new Date(+matched[1]);return}configFromISO(config);if(config._isValid===false){delete config._isValid;utils_hooks__hooks.createFromInputFallback(config)}}utils_hooks__hooks.createFromInputFallback=deprecate("moment construction falls back to js Date. This is "+"discouraged and will be removed in upcoming major "+"release. Please refer to "+"https://github.com/moment/moment/issues/1407 for more info.",function(config){config._d=new Date(config._i+(config._useUTC?" UTC":""))});function createDate(y,m,d,h,M,s,ms){var date=new Date(y,m,d,h,M,s,ms);if(y<1970){date.setFullYear(y)}return date}function createUTCDate(y){var date=new Date(Date.UTC.apply(null,arguments));if(y<1970){date.setUTCFullYear(y)}return date}addFormatToken(0,["YY",2],0,function(){return this.year()%100});addFormatToken(0,["YYYY",4],0,"year");addFormatToken(0,["YYYYY",5],0,"year");addFormatToken(0,["YYYYYY",6,true],0,"year");addUnitAlias("year","y");addRegexToken("Y",matchSigned);addRegexToken("YY",match1to2,match2);addRegexToken("YYYY",match1to4,match4);addRegexToken("YYYYY",match1to6,match6);addRegexToken("YYYYYY",match1to6,match6);addParseToken(["YYYY","YYYYY","YYYYYY"],YEAR);addParseToken("YY",function(input,array){array[YEAR]=utils_hooks__hooks.parseTwoDigitYear(input)});function daysInYear(year){return isLeapYear(year)?366:365}function isLeapYear(year){return year%4===0&&year%100!==0||year%400===0}utils_hooks__hooks.parseTwoDigitYear=function(input){return toInt(input)+(toInt(input)>68?1900:2e3)};var getSetYear=makeGetSet("FullYear",false);function getIsLeapYear(){return isLeapYear(this.year())}addFormatToken("w",["ww",2],"wo","week");addFormatToken("W",["WW",2],"Wo","isoWeek");addUnitAlias("week","w");addUnitAlias("isoWeek","W");addRegexToken("w",match1to2);addRegexToken("ww",match1to2,match2);addRegexToken("W",match1to2);addRegexToken("WW",match1to2,match2);addWeekParseToken(["w","ww","W","WW"],function(input,week,config,token){week[token.substr(0,1)]=toInt(input)});function weekOfYear(mom,firstDayOfWeek,firstDayOfWeekOfYear){var end=firstDayOfWeekOfYear-firstDayOfWeek,daysToDayOfWeek=firstDayOfWeekOfYear-mom.day(),adjustedMoment;if(daysToDayOfWeek>end){daysToDayOfWeek-=7}if(daysToDayOfWeek<end-7){daysToDayOfWeek+=7}adjustedMoment=local__createLocal(mom).add(daysToDayOfWeek,"d");return{week:Math.ceil(adjustedMoment.dayOfYear()/7),year:adjustedMoment.year()}}function localeWeek(mom){return weekOfYear(mom,this._week.dow,this._week.doy).week}var defaultLocaleWeek={dow:0,doy:6};function localeFirstDayOfWeek(){return this._week.dow}function localeFirstDayOfYear(){return this._week.doy}function getSetWeek(input){var week=this.localeData().week(this);return input==null?week:this.add((input-week)*7,"d")}function getSetISOWeek(input){var week=weekOfYear(this,1,4).week;return input==null?week:this.add((input-week)*7,"d")}addFormatToken("DDD",["DDDD",3],"DDDo","dayOfYear");addUnitAlias("dayOfYear","DDD");addRegexToken("DDD",match1to3);addRegexToken("DDDD",match3);addParseToken(["DDD","DDDD"],function(input,array,config){config._dayOfYear=toInt(input)});function dayOfYearFromWeeks(year,week,weekday,firstDayOfWeekOfYear,firstDayOfWeek){var d=createUTCDate(year,0,1).getUTCDay();var daysToAdd;var dayOfYear;d=d===0?7:d;weekday=weekday!=null?weekday:firstDayOfWeek;daysToAdd=firstDayOfWeek-d+(d>firstDayOfWeekOfYear?7:0)-(d<firstDayOfWeek?7:0);dayOfYear=7*(week-1)+(weekday-firstDayOfWeek)+daysToAdd+1;return{year:dayOfYear>0?year:year-1,dayOfYear:dayOfYear>0?dayOfYear:daysInYear(year-1)+dayOfYear}}function getSetDayOfYear(input){var dayOfYear=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return input==null?dayOfYear:this.add(input-dayOfYear,"d")}function defaults(a,b,c){if(a!=null){return a}if(b!=null){return b}return c}function currentDateArray(config){var now=new Date;if(config._useUTC){return[now.getUTCFullYear(),now.getUTCMonth(),now.getUTCDate()]}return[now.getFullYear(),now.getMonth(),now.getDate()]}function configFromArray(config){var i,date,input=[],currentDate,yearToUse;if(config._d){return}currentDate=currentDateArray(config);if(config._w&&config._a[DATE]==null&&config._a[MONTH]==null){dayOfYearFromWeekInfo(config)}if(config._dayOfYear){yearToUse=defaults(config._a[YEAR],currentDate[YEAR]);if(config._dayOfYear>daysInYear(yearToUse)){getParsingFlags(config)._overflowDayOfYear=true}date=createUTCDate(yearToUse,0,config._dayOfYear);config._a[MONTH]=date.getUTCMonth();config._a[DATE]=date.getUTCDate()}for(i=0;i<3&&config._a[i]==null;++i){config._a[i]=input[i]=currentDate[i]}for(;i<7;i++){config._a[i]=input[i]=config._a[i]==null?i===2?1:0:config._a[i]}if(config._a[HOUR]===24&&config._a[MINUTE]===0&&config._a[SECOND]===0&&config._a[MILLISECOND]===0){config._nextDay=true;config._a[HOUR]=0}config._d=(config._useUTC?createUTCDate:createDate).apply(null,input);if(config._tzm!=null){config._d.setUTCMinutes(config._d.getUTCMinutes()-config._tzm)}if(config._nextDay){config._a[HOUR]=24}}function dayOfYearFromWeekInfo(config){var w,weekYear,week,weekday,dow,doy,temp;w=config._w;if(w.GG!=null||w.W!=null||w.E!=null){dow=1;doy=4;weekYear=defaults(w.GG,config._a[YEAR],weekOfYear(local__createLocal(),1,4).year);week=defaults(w.W,1);weekday=defaults(w.E,1)}else{dow=config._locale._week.dow;doy=config._locale._week.doy;weekYear=defaults(w.gg,config._a[YEAR],weekOfYear(local__createLocal(),dow,doy).year);week=defaults(w.w,1);if(w.d!=null){weekday=w.d;if(weekday<dow){++week}}else if(w.e!=null){weekday=w.e+dow}else{weekday=dow}}temp=dayOfYearFromWeeks(weekYear,week,weekday,doy,dow);config._a[YEAR]=temp.year;config._dayOfYear=temp.dayOfYear}utils_hooks__hooks.ISO_8601=function(){};function configFromStringAndFormat(config){if(config._f===utils_hooks__hooks.ISO_8601){configFromISO(config);return}config._a=[];getParsingFlags(config).empty=true;var string=""+config._i,i,parsedInput,tokens,token,skipped,stringLength=string.length,totalParsedInputLength=0;tokens=expandFormat(config._f,config._locale).match(formattingTokens)||[];for(i=0;i<tokens.length;i++){token=tokens[i];parsedInput=(string.match(getParseRegexForToken(token,config))||[])[0];if(parsedInput){skipped=string.substr(0,string.indexOf(parsedInput));if(skipped.length>0){getParsingFlags(config).unusedInput.push(skipped)}string=string.slice(string.indexOf(parsedInput)+parsedInput.length);totalParsedInputLength+=parsedInput.length}if(formatTokenFunctions[token]){if(parsedInput){getParsingFlags(config).empty=false}else{getParsingFlags(config).unusedTokens.push(token)}addTimeToArrayFromToken(token,parsedInput,config)}else if(config._strict&&!parsedInput){getParsingFlags(config).unusedTokens.push(token)}}getParsingFlags(config).charsLeftOver=stringLength-totalParsedInputLength;if(string.length>0){getParsingFlags(config).unusedInput.push(string)}if(getParsingFlags(config).bigHour===true&&config._a[HOUR]<=12&&config._a[HOUR]>0){getParsingFlags(config).bigHour=undefined}config._a[HOUR]=meridiemFixWrap(config._locale,config._a[HOUR],config._meridiem);configFromArray(config);checkOverflow(config)}function meridiemFixWrap(locale,hour,meridiem){var isPm;if(meridiem==null){return hour}if(locale.meridiemHour!=null){return locale.meridiemHour(hour,meridiem)}else if(locale.isPM!=null){isPm=locale.isPM(meridiem);if(isPm&&hour<12){hour+=12}if(!isPm&&hour===12){hour=0}return hour}else{return hour}}function configFromStringAndArray(config){var tempConfig,bestMoment,scoreToBeat,i,currentScore;if(config._f.length===0){getParsingFlags(config).invalidFormat=true;config._d=new Date(NaN);return}for(i=0;i<config._f.length;i++){currentScore=0;tempConfig=copyConfig({},config);if(config._useUTC!=null){tempConfig._useUTC=config._useUTC}tempConfig._f=config._f[i];configFromStringAndFormat(tempConfig);if(!valid__isValid(tempConfig)){continue}currentScore+=getParsingFlags(tempConfig).charsLeftOver;currentScore+=getParsingFlags(tempConfig).unusedTokens.length*10;getParsingFlags(tempConfig).score=currentScore;if(scoreToBeat==null||currentScore<scoreToBeat){scoreToBeat=currentScore;bestMoment=tempConfig}}extend(config,bestMoment||tempConfig)}function configFromObject(config){if(config._d){return}var i=normalizeObjectUnits(config._i);config._a=[i.year,i.month,i.day||i.date,i.hour,i.minute,i.second,i.millisecond];configFromArray(config)}function createFromConfig(config){var input=config._i,format=config._f,res;config._locale=config._locale||locale_locales__getLocale(config._l);if(input===null||format===undefined&&input===""){return valid__createInvalid({nullInput:true})}if(typeof input==="string"){config._i=input=config._locale.preparse(input)}if(isMoment(input)){return new Moment(checkOverflow(input))}else if(isArray(format)){configFromStringAndArray(config)}else if(format){configFromStringAndFormat(config)}else if(isDate(input)){config._d=input}else{configFromInput(config)}res=new Moment(checkOverflow(config));if(res._nextDay){res.add(1,"d");res._nextDay=undefined}return res}function configFromInput(config){var input=config._i;if(input===undefined){config._d=new Date}else if(isDate(input)){config._d=new Date(+input)}else if(typeof input==="string"){configFromString(config)}else if(isArray(input)){config._a=map(input.slice(0),function(obj){return parseInt(obj,10)});configFromArray(config)}else if(typeof input==="object"){configFromObject(config)}else if(typeof input==="number"){config._d=new Date(input)}else{utils_hooks__hooks.createFromInputFallback(config)}}function createLocalOrUTC(input,format,locale,strict,isUTC){var c={};if(typeof locale==="boolean"){strict=locale;locale=undefined}
     10// https://github.com/moment/moment/issues/1423
     11c._isAMomentObject=true;c._useUTC=c._isUTC=isUTC;c._l=locale;c._i=input;c._f=format;c._strict=strict;return createFromConfig(c)}function local__createLocal(input,format,locale,strict){return createLocalOrUTC(input,format,locale,strict,false)}var prototypeMin=deprecate("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var other=local__createLocal.apply(null,arguments);return other<this?this:other});var prototypeMax=deprecate("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var other=local__createLocal.apply(null,arguments);return other>this?this:other});function pickBy(fn,moments){var res,i;if(moments.length===1&&isArray(moments[0])){moments=moments[0]}if(!moments.length){return local__createLocal()}res=moments[0];for(i=1;i<moments.length;++i){if(moments[i][fn](res)){res=moments[i]}}return res}function min(){var args=[].slice.call(arguments,0);return pickBy("isBefore",args)}function max(){var args=[].slice.call(arguments,0);return pickBy("isAfter",args)}function Duration(duration){var normalizedInput=normalizeObjectUnits(duration),years=normalizedInput.year||0,quarters=normalizedInput.quarter||0,months=normalizedInput.month||0,weeks=normalizedInput.week||0,days=normalizedInput.day||0,hours=normalizedInput.hour||0,minutes=normalizedInput.minute||0,seconds=normalizedInput.second||0,milliseconds=normalizedInput.millisecond||0;this._milliseconds=+milliseconds+seconds*1e3+minutes*6e4+hours*36e5;this._days=+days+weeks*7;this._months=+months+quarters*3+years*12;this._data={};this._locale=locale_locales__getLocale();this._bubble()}function isDuration(obj){return obj instanceof Duration}function offset(token,separator){addFormatToken(token,0,0,function(){var offset=this.utcOffset();var sign="+";if(offset<0){offset=-offset;sign="-"}return sign+zeroFill(~~(offset/60),2)+separator+zeroFill(~~offset%60,2)})}offset("Z",":");offset("ZZ","");addRegexToken("Z",matchOffset);addRegexToken("ZZ",matchOffset);addParseToken(["Z","ZZ"],function(input,array,config){config._useUTC=true;config._tzm=offsetFromString(input)});var chunkOffset=/([\+\-]|\d\d)/gi;function offsetFromString(string){var matches=(string||"").match(matchOffset)||[];var chunk=matches[matches.length-1]||[];var parts=(chunk+"").match(chunkOffset)||["-",0,0];var minutes=+(parts[1]*60)+toInt(parts[2]);return parts[0]==="+"?minutes:-minutes}function cloneWithOffset(input,model){var res,diff;if(model._isUTC){res=model.clone();diff=(isMoment(input)||isDate(input)?+input:+local__createLocal(input))-+res;res._d.setTime(+res._d+diff);utils_hooks__hooks.updateOffset(res,false);return res}else{return local__createLocal(input).local()}return model._isUTC?local__createLocal(input).zone(model._offset||0):local__createLocal(input).local()}function getDateOffset(m){
     12// https://github.com/moment/moment/pull/1871
     13return-Math.round(m._d.getTimezoneOffset()/15)*15}utils_hooks__hooks.updateOffset=function(){};function getSetOffset(input,keepLocalTime){var offset=this._offset||0,localAdjust;if(input!=null){if(typeof input==="string"){input=offsetFromString(input)}if(Math.abs(input)<16){input=input*60}if(!this._isUTC&&keepLocalTime){localAdjust=getDateOffset(this)}this._offset=input;this._isUTC=true;if(localAdjust!=null){this.add(localAdjust,"m")}if(offset!==input){if(!keepLocalTime||this._changeInProgress){add_subtract__addSubtract(this,create__createDuration(input-offset,"m"),1,false)}else if(!this._changeInProgress){this._changeInProgress=true;utils_hooks__hooks.updateOffset(this,true);this._changeInProgress=null}}return this}else{return this._isUTC?offset:getDateOffset(this)}}function getSetZone(input,keepLocalTime){if(input!=null){if(typeof input!=="string"){input=-input}this.utcOffset(input,keepLocalTime);return this}else{return-this.utcOffset()}}function setOffsetToUTC(keepLocalTime){return this.utcOffset(0,keepLocalTime)}function setOffsetToLocal(keepLocalTime){if(this._isUTC){this.utcOffset(0,keepLocalTime);this._isUTC=false;if(keepLocalTime){this.subtract(getDateOffset(this),"m")}}return this}function setOffsetToParsedOffset(){if(this._tzm){this.utcOffset(this._tzm)}else if(typeof this._i==="string"){this.utcOffset(offsetFromString(this._i))}return this}function hasAlignedHourOffset(input){if(!input){input=0}else{input=local__createLocal(input).utcOffset()}return(this.utcOffset()-input)%60===0}function isDaylightSavingTime(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function isDaylightSavingTimeShifted(){if(this._a){var other=this._isUTC?create_utc__createUTC(this._a):local__createLocal(this._a);return this.isValid()&&compareArrays(this._a,other.toArray())>0}return false}function isLocal(){return!this._isUTC}function isUtcOffset(){return this._isUTC}function isUtc(){return this._isUTC&&this._offset===0}var aspNetRegex=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/;var create__isoRegex=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;function create__createDuration(input,key){var duration=input,match=null,sign,ret,diffRes;if(isDuration(input)){duration={ms:input._milliseconds,d:input._days,M:input._months}}else if(typeof input==="number"){duration={};if(key){duration[key]=input}else{duration.milliseconds=input}}else if(!!(match=aspNetRegex.exec(input))){sign=match[1]==="-"?-1:1;duration={y:0,d:toInt(match[DATE])*sign,h:toInt(match[HOUR])*sign,m:toInt(match[MINUTE])*sign,s:toInt(match[SECOND])*sign,ms:toInt(match[MILLISECOND])*sign}}else if(!!(match=create__isoRegex.exec(input))){sign=match[1]==="-"?-1:1;duration={y:parseIso(match[2],sign),M:parseIso(match[3],sign),d:parseIso(match[4],sign),h:parseIso(match[5],sign),m:parseIso(match[6],sign),s:parseIso(match[7],sign),w:parseIso(match[8],sign)}}else if(duration==null){duration={}}else if(typeof duration==="object"&&("from"in duration||"to"in duration)){diffRes=momentsDifference(local__createLocal(duration.from),local__createLocal(duration.to));duration={};duration.ms=diffRes.milliseconds;duration.M=diffRes.months}ret=new Duration(duration);if(isDuration(input)&&hasOwnProp(input,"_locale")){ret._locale=input._locale}return ret}create__createDuration.fn=Duration.prototype;function parseIso(inp,sign){var res=inp&&parseFloat(inp.replace(",","."));return(isNaN(res)?0:res)*sign}function positiveMomentsDifference(base,other){var res={milliseconds:0,months:0};res.months=other.month()-base.month()+(other.year()-base.year())*12;if(base.clone().add(res.months,"M").isAfter(other)){--res.months}res.milliseconds=+other-+base.clone().add(res.months,"M");return res}function momentsDifference(base,other){var res;other=cloneWithOffset(other,base);if(base.isBefore(other)){res=positiveMomentsDifference(base,other)}else{res=positiveMomentsDifference(other,base);res.milliseconds=-res.milliseconds;res.months=-res.months}return res}function createAdder(direction,name){return function(val,period){var dur,tmp;if(period!==null&&!isNaN(+period)){deprecateSimple(name,"moment()."+name+"(period, number) is deprecated. Please use moment()."+name+"(number, period).");tmp=val;val=period;period=tmp}val=typeof val==="string"?+val:val;dur=create__createDuration(val,period);add_subtract__addSubtract(this,dur,direction);return this}}function add_subtract__addSubtract(mom,duration,isAdding,updateOffset){var milliseconds=duration._milliseconds,days=duration._days,months=duration._months;updateOffset=updateOffset==null?true:updateOffset;if(milliseconds){mom._d.setTime(+mom._d+milliseconds*isAdding)}if(days){get_set__set(mom,"Date",get_set__get(mom,"Date")+days*isAdding)}if(months){setMonth(mom,get_set__get(mom,"Month")+months*isAdding)}if(updateOffset){utils_hooks__hooks.updateOffset(mom,days||months)}}var add_subtract__add=createAdder(1,"add");var add_subtract__subtract=createAdder(-1,"subtract");function moment_calendar__calendar(time){var now=time||local__createLocal(),sod=cloneWithOffset(now,this).startOf("day"),diff=this.diff(sod,"days",true),format=diff<-6?"sameElse":diff<-1?"lastWeek":diff<0?"lastDay":diff<1?"sameDay":diff<2?"nextDay":diff<7?"nextWeek":"sameElse";return this.format(this.localeData().calendar(format,this,local__createLocal(now)))}function clone(){return new Moment(this)}function isAfter(input,units){var inputMs;units=normalizeUnits(typeof units!=="undefined"?units:"millisecond");if(units==="millisecond"){input=isMoment(input)?input:local__createLocal(input);return+this>+input}else{inputMs=isMoment(input)?+input:+local__createLocal(input);return inputMs<+this.clone().startOf(units)}}function isBefore(input,units){var inputMs;units=normalizeUnits(typeof units!=="undefined"?units:"millisecond");if(units==="millisecond"){input=isMoment(input)?input:local__createLocal(input);return+this<+input}else{inputMs=isMoment(input)?+input:+local__createLocal(input);return+this.clone().endOf(units)<inputMs}}function isBetween(from,to,units){return this.isAfter(from,units)&&this.isBefore(to,units)}function isSame(input,units){var inputMs;units=normalizeUnits(units||"millisecond");if(units==="millisecond"){input=isMoment(input)?input:local__createLocal(input);return+this===+input}else{inputMs=+local__createLocal(input);return+this.clone().startOf(units)<=inputMs&&inputMs<=+this.clone().endOf(units)}}function absFloor(number){if(number<0){return Math.ceil(number)}else{return Math.floor(number)}}function diff(input,units,asFloat){var that=cloneWithOffset(input,this),zoneDelta=(that.utcOffset()-this.utcOffset())*6e4,delta,output;units=normalizeUnits(units);if(units==="year"||units==="month"||units==="quarter"){output=monthDiff(this,that);if(units==="quarter"){output=output/3}else if(units==="year"){output=output/12}}else{delta=this-that;output=units==="second"?delta/1e3:units==="minute"?delta/6e4:units==="hour"?delta/36e5:units==="day"?(delta-zoneDelta)/864e5:units==="week"?(delta-zoneDelta)/6048e5:delta}return asFloat?output:absFloor(output)}function monthDiff(a,b){var wholeMonthDiff=(b.year()-a.year())*12+(b.month()-a.month()),anchor=a.clone().add(wholeMonthDiff,"months"),anchor2,adjust;if(b-anchor<0){anchor2=a.clone().add(wholeMonthDiff-1,"months");adjust=(b-anchor)/(anchor-anchor2)}else{anchor2=a.clone().add(wholeMonthDiff+1,"months");adjust=(b-anchor)/(anchor2-anchor)}return-(wholeMonthDiff+adjust)}utils_hooks__hooks.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";function toString(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function moment_format__toISOString(){var m=this.clone().utc();if(0<m.year()&&m.year()<=9999){if("function"===typeof Date.prototype.toISOString){return this.toDate().toISOString()}else{return formatMoment(m,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}}else{return formatMoment(m,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")}}function format(inputString){var output=formatMoment(this,inputString||utils_hooks__hooks.defaultFormat);return this.localeData().postformat(output)}function from(time,withoutSuffix){if(!this.isValid()){return this.localeData().invalidDate()}return create__createDuration({to:this,from:time}).locale(this.locale()).humanize(!withoutSuffix)}function fromNow(withoutSuffix){return this.from(local__createLocal(),withoutSuffix)}function to(time,withoutSuffix){if(!this.isValid()){return this.localeData().invalidDate()}return create__createDuration({from:this,to:time}).locale(this.locale()).humanize(!withoutSuffix)}function toNow(withoutSuffix){return this.to(local__createLocal(),withoutSuffix)}function locale(key){var newLocaleData;if(key===undefined){return this._locale._abbr}else{newLocaleData=locale_locales__getLocale(key);if(newLocaleData!=null){this._locale=newLocaleData}return this}}var lang=deprecate("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(key){if(key===undefined){return this.localeData()}else{return this.locale(key)}});function localeData(){return this._locale}function startOf(units){units=normalizeUnits(units);switch(units){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}if(units==="week"){this.weekday(0)}if(units==="isoWeek"){this.isoWeekday(1)}if(units==="quarter"){this.month(Math.floor(this.month()/3)*3)}return this}function endOf(units){units=normalizeUnits(units);if(units===undefined||units==="millisecond"){return this}return this.startOf(units).add(1,units==="isoWeek"?"week":units).subtract(1,"ms")}function to_type__valueOf(){return+this._d-(this._offset||0)*6e4}function unix(){return Math.floor(+this/1e3)}function toDate(){return this._offset?new Date(+this):this._d}function toArray(){var m=this;return[m.year(),m.month(),m.date(),m.hour(),m.minute(),m.second(),m.millisecond()]}function moment_valid__isValid(){return valid__isValid(this)}function parsingFlags(){return extend({},getParsingFlags(this))}function invalidAt(){return getParsingFlags(this).overflow}addFormatToken(0,["gg",2],0,function(){return this.weekYear()%100});addFormatToken(0,["GG",2],0,function(){return this.isoWeekYear()%100});function addWeekYearFormatToken(token,getter){addFormatToken(0,[token,token.length],0,getter)}addWeekYearFormatToken("gggg","weekYear");addWeekYearFormatToken("ggggg","weekYear");addWeekYearFormatToken("GGGG","isoWeekYear");addWeekYearFormatToken("GGGGG","isoWeekYear");addUnitAlias("weekYear","gg");addUnitAlias("isoWeekYear","GG");addRegexToken("G",matchSigned);addRegexToken("g",matchSigned);addRegexToken("GG",match1to2,match2);addRegexToken("gg",match1to2,match2);addRegexToken("GGGG",match1to4,match4);addRegexToken("gggg",match1to4,match4);addRegexToken("GGGGG",match1to6,match6);addRegexToken("ggggg",match1to6,match6);addWeekParseToken(["gggg","ggggg","GGGG","GGGGG"],function(input,week,config,token){week[token.substr(0,2)]=toInt(input)});addWeekParseToken(["gg","GG"],function(input,week,config,token){week[token]=utils_hooks__hooks.parseTwoDigitYear(input)});function weeksInYear(year,dow,doy){return weekOfYear(local__createLocal([year,11,31+dow-doy]),dow,doy).week}function getSetWeekYear(input){var year=weekOfYear(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return input==null?year:this.add(input-year,"y")}function getSetISOWeekYear(input){var year=weekOfYear(this,1,4).year;return input==null?year:this.add(input-year,"y")}function getISOWeeksInYear(){return weeksInYear(this.year(),1,4)}function getWeeksInYear(){var weekInfo=this.localeData()._week;return weeksInYear(this.year(),weekInfo.dow,weekInfo.doy)}addFormatToken("Q",0,0,"quarter");addUnitAlias("quarter","Q");addRegexToken("Q",match1);addParseToken("Q",function(input,array){array[MONTH]=(toInt(input)-1)*3});function getSetQuarter(input){return input==null?Math.ceil((this.month()+1)/3):this.month((input-1)*3+this.month()%3)}addFormatToken("D",["DD",2],"Do","date");addUnitAlias("date","D");addRegexToken("D",match1to2);addRegexToken("DD",match1to2,match2);addRegexToken("Do",function(isStrict,locale){return isStrict?locale._ordinalParse:locale._ordinalParseLenient});addParseToken(["D","DD"],DATE);addParseToken("Do",function(input,array){array[DATE]=toInt(input.match(match1to2)[0],10)});var getSetDayOfMonth=makeGetSet("Date",true);addFormatToken("d",0,"do","day");addFormatToken("dd",0,0,function(format){return this.localeData().weekdaysMin(this,format)});addFormatToken("ddd",0,0,function(format){return this.localeData().weekdaysShort(this,format)});addFormatToken("dddd",0,0,function(format){return this.localeData().weekdays(this,format)});addFormatToken("e",0,0,"weekday");addFormatToken("E",0,0,"isoWeekday");addUnitAlias("day","d");addUnitAlias("weekday","e");addUnitAlias("isoWeekday","E");addRegexToken("d",match1to2);addRegexToken("e",match1to2);addRegexToken("E",match1to2);addRegexToken("dd",matchWord);addRegexToken("ddd",matchWord);addRegexToken("dddd",matchWord);addWeekParseToken(["dd","ddd","dddd"],function(input,week,config){var weekday=config._locale.weekdaysParse(input);if(weekday!=null){week.d=weekday}else{getParsingFlags(config).invalidWeekday=input}});addWeekParseToken(["d","e","E"],function(input,week,config,token){week[token]=toInt(input)});function parseWeekday(input,locale){if(typeof input==="string"){if(!isNaN(input)){input=parseInt(input,10)}else{input=locale.weekdaysParse(input);if(typeof input!=="number"){return null}}}return input}var defaultLocaleWeekdays="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_");function localeWeekdays(m){return this._weekdays[m.day()]}var defaultLocaleWeekdaysShort="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_");function localeWeekdaysShort(m){return this._weekdaysShort[m.day()]}var defaultLocaleWeekdaysMin="Su_Mo_Tu_We_Th_Fr_Sa".split("_");function localeWeekdaysMin(m){return this._weekdaysMin[m.day()]}function localeWeekdaysParse(weekdayName){var i,mom,regex;if(!this._weekdaysParse){this._weekdaysParse=[]}for(i=0;i<7;i++){if(!this._weekdaysParse[i]){mom=local__createLocal([2e3,1]).day(i);regex="^"+this.weekdays(mom,"")+"|^"+this.weekdaysShort(mom,"")+"|^"+this.weekdaysMin(mom,"");this._weekdaysParse[i]=new RegExp(regex.replace(".",""),"i")}if(this._weekdaysParse[i].test(weekdayName)){return i}}}function getSetDayOfWeek(input){var day=this._isUTC?this._d.getUTCDay():this._d.getDay();if(input!=null){input=parseWeekday(input,this.localeData());return this.add(input-day,"d")}else{return day}}function getSetLocaleDayOfWeek(input){var weekday=(this.day()+7-this.localeData()._week.dow)%7;return input==null?weekday:this.add(input-weekday,"d")}function getSetISODayOfWeek(input){return input==null?this.day()||7:this.day(this.day()%7?input:input-7)}addFormatToken("H",["HH",2],0,"hour");addFormatToken("h",["hh",2],0,function(){return this.hours()%12||12});function meridiem(token,lowercase){addFormatToken(token,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),lowercase)})}meridiem("a",true);meridiem("A",false);addUnitAlias("hour","h");function matchMeridiem(isStrict,locale){return locale._meridiemParse}addRegexToken("a",matchMeridiem);addRegexToken("A",matchMeridiem);addRegexToken("H",match1to2);addRegexToken("h",match1to2);addRegexToken("HH",match1to2,match2);addRegexToken("hh",match1to2,match2);addParseToken(["H","HH"],HOUR);addParseToken(["a","A"],function(input,array,config){config._isPm=config._locale.isPM(input);config._meridiem=input});addParseToken(["h","hh"],function(input,array,config){array[HOUR]=toInt(input);getParsingFlags(config).bigHour=true});function localeIsPM(input){return(input+"").toLowerCase().charAt(0)==="p"}var defaultLocaleMeridiemParse=/[ap]\.?m?\.?/i;function localeMeridiem(hours,minutes,isLower){if(hours>11){return isLower?"pm":"PM"}else{return isLower?"am":"AM"}}var getSetHour=makeGetSet("Hours",true);addFormatToken("m",["mm",2],0,"minute");addUnitAlias("minute","m");addRegexToken("m",match1to2);addRegexToken("mm",match1to2,match2);addParseToken(["m","mm"],MINUTE);var getSetMinute=makeGetSet("Minutes",false);addFormatToken("s",["ss",2],0,"second");addUnitAlias("second","s");addRegexToken("s",match1to2);addRegexToken("ss",match1to2,match2);addParseToken(["s","ss"],SECOND);var getSetSecond=makeGetSet("Seconds",false);addFormatToken("S",0,0,function(){return~~(this.millisecond()/100)});addFormatToken(0,["SS",2],0,function(){return~~(this.millisecond()/10)});function millisecond__milliseconds(token){addFormatToken(0,[token,3],0,"millisecond")}millisecond__milliseconds("SSS");millisecond__milliseconds("SSSS");addUnitAlias("millisecond","ms");addRegexToken("S",match1to3,match1);addRegexToken("SS",match1to3,match2);addRegexToken("SSS",match1to3,match3);addRegexToken("SSSS",matchUnsigned);addParseToken(["S","SS","SSS","SSSS"],function(input,array){array[MILLISECOND]=toInt(("0."+input)*1e3)});var getSetMillisecond=makeGetSet("Milliseconds",false);addFormatToken("z",0,0,"zoneAbbr");addFormatToken("zz",0,0,"zoneName");function getZoneAbbr(){return this._isUTC?"UTC":""}function getZoneName(){return this._isUTC?"Coordinated Universal Time":""}var momentPrototype__proto=Moment.prototype;momentPrototype__proto.add=add_subtract__add;momentPrototype__proto.calendar=moment_calendar__calendar;momentPrototype__proto.clone=clone;momentPrototype__proto.diff=diff;momentPrototype__proto.endOf=endOf;momentPrototype__proto.format=format;momentPrototype__proto.from=from;momentPrototype__proto.fromNow=fromNow;momentPrototype__proto.to=to;momentPrototype__proto.toNow=toNow;momentPrototype__proto.get=getSet;momentPrototype__proto.invalidAt=invalidAt;momentPrototype__proto.isAfter=isAfter;momentPrototype__proto.isBefore=isBefore;momentPrototype__proto.isBetween=isBetween;momentPrototype__proto.isSame=isSame;momentPrototype__proto.isValid=moment_valid__isValid;momentPrototype__proto.lang=lang;momentPrototype__proto.locale=locale;momentPrototype__proto.localeData=localeData;momentPrototype__proto.max=prototypeMax;momentPrototype__proto.min=prototypeMin;momentPrototype__proto.parsingFlags=parsingFlags;momentPrototype__proto.set=getSet;momentPrototype__proto.startOf=startOf;momentPrototype__proto.subtract=add_subtract__subtract;momentPrototype__proto.toArray=toArray;momentPrototype__proto.toDate=toDate;momentPrototype__proto.toISOString=moment_format__toISOString;momentPrototype__proto.toJSON=moment_format__toISOString;momentPrototype__proto.toString=toString;momentPrototype__proto.unix=unix;momentPrototype__proto.valueOf=to_type__valueOf;momentPrototype__proto.year=getSetYear;momentPrototype__proto.isLeapYear=getIsLeapYear;momentPrototype__proto.weekYear=getSetWeekYear;momentPrototype__proto.isoWeekYear=getSetISOWeekYear;momentPrototype__proto.quarter=momentPrototype__proto.quarters=getSetQuarter;momentPrototype__proto.month=getSetMonth;momentPrototype__proto.daysInMonth=getDaysInMonth;momentPrototype__proto.week=momentPrototype__proto.weeks=getSetWeek;momentPrototype__proto.isoWeek=momentPrototype__proto.isoWeeks=getSetISOWeek;momentPrototype__proto.weeksInYear=getWeeksInYear;momentPrototype__proto.isoWeeksInYear=getISOWeeksInYear;momentPrototype__proto.date=getSetDayOfMonth;momentPrototype__proto.day=momentPrototype__proto.days=getSetDayOfWeek;momentPrototype__proto.weekday=getSetLocaleDayOfWeek;momentPrototype__proto.isoWeekday=getSetISODayOfWeek;momentPrototype__proto.dayOfYear=getSetDayOfYear;momentPrototype__proto.hour=momentPrototype__proto.hours=getSetHour;momentPrototype__proto.minute=momentPrototype__proto.minutes=getSetMinute;momentPrototype__proto.second=momentPrototype__proto.seconds=getSetSecond;momentPrototype__proto.millisecond=momentPrototype__proto.milliseconds=getSetMillisecond;momentPrototype__proto.utcOffset=getSetOffset;momentPrototype__proto.utc=setOffsetToUTC;momentPrototype__proto.local=setOffsetToLocal;momentPrototype__proto.parseZone=setOffsetToParsedOffset;momentPrototype__proto.hasAlignedHourOffset=hasAlignedHourOffset;momentPrototype__proto.isDST=isDaylightSavingTime;momentPrototype__proto.isDSTShifted=isDaylightSavingTimeShifted;momentPrototype__proto.isLocal=isLocal;momentPrototype__proto.isUtcOffset=isUtcOffset;momentPrototype__proto.isUtc=isUtc;momentPrototype__proto.isUTC=isUtc;momentPrototype__proto.zoneAbbr=getZoneAbbr;momentPrototype__proto.zoneName=getZoneName;momentPrototype__proto.dates=deprecate("dates accessor is deprecated. Use date instead.",getSetDayOfMonth);momentPrototype__proto.months=deprecate("months accessor is deprecated. Use month instead",getSetMonth);momentPrototype__proto.years=deprecate("years accessor is deprecated. Use year instead",getSetYear);momentPrototype__proto.zone=deprecate("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",getSetZone);var momentPrototype=momentPrototype__proto;function moment__createUnix(input){return local__createLocal(input*1e3)}function moment__createInZone(){return local__createLocal.apply(null,arguments).parseZone()}var defaultCalendar={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"};function locale_calendar__calendar(key,mom,now){var output=this._calendar[key];return typeof output==="function"?output.call(mom,now):output}var defaultLongDateFormat={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"};function longDateFormat(key){var output=this._longDateFormat[key];if(!output&&this._longDateFormat[key.toUpperCase()]){output=this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(val){return val.slice(1)});this._longDateFormat[key]=output}return output}var defaultInvalidDate="Invalid date";function invalidDate(){return this._invalidDate}var defaultOrdinal="%d";var defaultOrdinalParse=/\d{1,2}/;function ordinal(number){return this._ordinal.replace("%d",number)}function preParsePostFormat(string){return string}var defaultRelativeTime={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function relative__relativeTime(number,withoutSuffix,string,isFuture){var output=this._relativeTime[string];return typeof output==="function"?output(number,withoutSuffix,string,isFuture):output.replace(/%d/i,number)}function pastFuture(diff,output){var format=this._relativeTime[diff>0?"future":"past"];return typeof format==="function"?format(output):format.replace(/%s/i,output)}function locale_set__set(config){var prop,i;for(i in config){prop=config[i];if(typeof prop==="function"){this[i]=prop}else{this["_"+i]=prop}}this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}var prototype__proto=Locale.prototype;prototype__proto._calendar=defaultCalendar;prototype__proto.calendar=locale_calendar__calendar;prototype__proto._longDateFormat=defaultLongDateFormat;prototype__proto.longDateFormat=longDateFormat;prototype__proto._invalidDate=defaultInvalidDate;prototype__proto.invalidDate=invalidDate;prototype__proto._ordinal=defaultOrdinal;prototype__proto.ordinal=ordinal;prototype__proto._ordinalParse=defaultOrdinalParse;prototype__proto.preparse=preParsePostFormat;prototype__proto.postformat=preParsePostFormat;prototype__proto._relativeTime=defaultRelativeTime;prototype__proto.relativeTime=relative__relativeTime;prototype__proto.pastFuture=pastFuture;prototype__proto.set=locale_set__set;prototype__proto.months=localeMonths;prototype__proto._months=defaultLocaleMonths;prototype__proto.monthsShort=localeMonthsShort;prototype__proto._monthsShort=defaultLocaleMonthsShort;prototype__proto.monthsParse=localeMonthsParse;prototype__proto.week=localeWeek;prototype__proto._week=defaultLocaleWeek;prototype__proto.firstDayOfYear=localeFirstDayOfYear;prototype__proto.firstDayOfWeek=localeFirstDayOfWeek;prototype__proto.weekdays=localeWeekdays;prototype__proto._weekdays=defaultLocaleWeekdays;prototype__proto.weekdaysMin=localeWeekdaysMin;prototype__proto._weekdaysMin=defaultLocaleWeekdaysMin;prototype__proto.weekdaysShort=localeWeekdaysShort;prototype__proto._weekdaysShort=defaultLocaleWeekdaysShort;prototype__proto.weekdaysParse=localeWeekdaysParse;prototype__proto.isPM=localeIsPM;prototype__proto._meridiemParse=defaultLocaleMeridiemParse;prototype__proto.meridiem=localeMeridiem;function lists__get(format,index,field,setter){var locale=locale_locales__getLocale();var utc=create_utc__createUTC().set(setter,index);return locale[field](utc,format)}function list(format,index,field,count,setter){if(typeof format==="number"){index=format;format=undefined}format=format||"";if(index!=null){return lists__get(format,index,field,setter)}var i;var out=[];for(i=0;i<count;i++){out[i]=lists__get(format,i,field,setter)}return out}function lists__listMonths(format,index){return list(format,index,"months",12,"month")}function lists__listMonthsShort(format,index){return list(format,index,"monthsShort",12,"month")}function lists__listWeekdays(format,index){return list(format,index,"weekdays",7,"day")}function lists__listWeekdaysShort(format,index){return list(format,index,"weekdaysShort",7,"day")}function lists__listWeekdaysMin(format,index){return list(format,index,"weekdaysMin",7,"day")}locale_locales__getSetGlobalLocale("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(number){var b=number%10,output=toInt(number%100/10)===1?"th":b===1?"st":b===2?"nd":b===3?"rd":"th";return number+output}});utils_hooks__hooks.lang=deprecate("moment.lang is deprecated. Use moment.locale instead.",locale_locales__getSetGlobalLocale);utils_hooks__hooks.langData=deprecate("moment.langData is deprecated. Use moment.localeData instead.",locale_locales__getLocale);var mathAbs=Math.abs;function duration_abs__abs(){var data=this._data;this._milliseconds=mathAbs(this._milliseconds);this._days=mathAbs(this._days);this._months=mathAbs(this._months);data.milliseconds=mathAbs(data.milliseconds);data.seconds=mathAbs(data.seconds);data.minutes=mathAbs(data.minutes);data.hours=mathAbs(data.hours);data.months=mathAbs(data.months);data.years=mathAbs(data.years);return this}function duration_add_subtract__addSubtract(duration,input,value,direction){var other=create__createDuration(input,value);duration._milliseconds+=direction*other._milliseconds;duration._days+=direction*other._days;duration._months+=direction*other._months;return duration._bubble()}function duration_add_subtract__add(input,value){return duration_add_subtract__addSubtract(this,input,value,1)}function duration_add_subtract__subtract(input,value){return duration_add_subtract__addSubtract(this,input,value,-1)}function bubble(){var milliseconds=this._milliseconds;var days=this._days;var months=this._months;var data=this._data;var seconds,minutes,hours,years=0;data.milliseconds=milliseconds%1e3;seconds=absFloor(milliseconds/1e3);data.seconds=seconds%60;minutes=absFloor(seconds/60);data.minutes=minutes%60;hours=absFloor(minutes/60);data.hours=hours%24;days+=absFloor(hours/24);years=absFloor(daysToYears(days));days-=absFloor(yearsToDays(years));months+=absFloor(days/30);days%=30;years+=absFloor(months/12);months%=12;data.days=days;data.months=months;data.years=years;return this}function daysToYears(days){return days*400/146097}function yearsToDays(years){return years*146097/400}function as(units){var days;var months;var milliseconds=this._milliseconds;units=normalizeUnits(units);if(units==="month"||units==="year"){days=this._days+milliseconds/864e5;months=this._months+daysToYears(days)*12;return units==="month"?months:months/12}else{days=this._days+Math.round(yearsToDays(this._months/12));switch(units){case"week":return days/7+milliseconds/6048e5;case"day":return days+milliseconds/864e5;case"hour":return days*24+milliseconds/36e5;case"minute":return days*1440+milliseconds/6e4;case"second":return days*86400+milliseconds/1e3;case"millisecond":return Math.floor(days*864e5)+milliseconds;default:throw new Error("Unknown unit "+units)}}}function duration_as__valueOf(){return this._milliseconds+this._days*864e5+this._months%12*2592e6+toInt(this._months/12)*31536e6}function makeAs(alias){return function(){return this.as(alias)}}var asMilliseconds=makeAs("ms");var asSeconds=makeAs("s");var asMinutes=makeAs("m");var asHours=makeAs("h");var asDays=makeAs("d");var asWeeks=makeAs("w");var asMonths=makeAs("M");var asYears=makeAs("y");function duration_get__get(units){units=normalizeUnits(units);return this[units+"s"]()}function makeGetter(name){return function(){return this._data[name]}}var duration_get__milliseconds=makeGetter("milliseconds");var seconds=makeGetter("seconds");var minutes=makeGetter("minutes");var hours=makeGetter("hours");var days=makeGetter("days");var months=makeGetter("months");var years=makeGetter("years");function weeks(){return absFloor(this.days()/7)}var round=Math.round;var thresholds={s:45,m:45,h:22,d:26,M:11};function substituteTimeAgo(string,number,withoutSuffix,isFuture,locale){return locale.relativeTime(number||1,!!withoutSuffix,string,isFuture)}function duration_humanize__relativeTime(posNegDuration,withoutSuffix,locale){var duration=create__createDuration(posNegDuration).abs();var seconds=round(duration.as("s"));var minutes=round(duration.as("m"));var hours=round(duration.as("h"));var days=round(duration.as("d"));var months=round(duration.as("M"));var years=round(duration.as("y"));var a=seconds<thresholds.s&&["s",seconds]||minutes===1&&["m"]||minutes<thresholds.m&&["mm",minutes]||hours===1&&["h"]||hours<thresholds.h&&["hh",hours]||days===1&&["d"]||days<thresholds.d&&["dd",days]||months===1&&["M"]||months<thresholds.M&&["MM",months]||years===1&&["y"]||["yy",years];a[2]=withoutSuffix;a[3]=+posNegDuration>0;a[4]=locale;return substituteTimeAgo.apply(null,a)}function duration_humanize__getSetRelativeTimeThreshold(threshold,limit){if(thresholds[threshold]===undefined){return false}if(limit===undefined){return thresholds[threshold]}thresholds[threshold]=limit;return true}function humanize(withSuffix){var locale=this.localeData();var output=duration_humanize__relativeTime(this,!withSuffix,locale);if(withSuffix){output=locale.pastFuture(+this,output)}return locale.postformat(output)}var iso_string__abs=Math.abs;function iso_string__toISOString(){
     14// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
     15var Y=iso_string__abs(this.years());var M=iso_string__abs(this.months());var D=iso_string__abs(this.days());var h=iso_string__abs(this.hours());var m=iso_string__abs(this.minutes());var s=iso_string__abs(this.seconds()+this.milliseconds()/1e3);var total=this.asSeconds();if(!total){return"P0D"}return(total<0?"-":"")+"P"+(Y?Y+"Y":"")+(M?M+"M":"")+(D?D+"D":"")+(h||m||s?"T":"")+(h?h+"H":"")+(m?m+"M":"")+(s?s+"S":"")}var duration_prototype__proto=Duration.prototype;duration_prototype__proto.abs=duration_abs__abs;duration_prototype__proto.add=duration_add_subtract__add;duration_prototype__proto.subtract=duration_add_subtract__subtract;duration_prototype__proto.as=as;duration_prototype__proto.asMilliseconds=asMilliseconds;duration_prototype__proto.asSeconds=asSeconds;duration_prototype__proto.asMinutes=asMinutes;duration_prototype__proto.asHours=asHours;duration_prototype__proto.asDays=asDays;duration_prototype__proto.asWeeks=asWeeks;duration_prototype__proto.asMonths=asMonths;duration_prototype__proto.asYears=asYears;duration_prototype__proto.valueOf=duration_as__valueOf;duration_prototype__proto._bubble=bubble;duration_prototype__proto.get=duration_get__get;duration_prototype__proto.milliseconds=duration_get__milliseconds;duration_prototype__proto.seconds=seconds;duration_prototype__proto.minutes=minutes;duration_prototype__proto.hours=hours;duration_prototype__proto.days=days;duration_prototype__proto.weeks=weeks;duration_prototype__proto.months=months;duration_prototype__proto.years=years;duration_prototype__proto.humanize=humanize;duration_prototype__proto.toISOString=iso_string__toISOString;duration_prototype__proto.toString=iso_string__toISOString;duration_prototype__proto.toJSON=iso_string__toISOString;duration_prototype__proto.locale=locale;duration_prototype__proto.localeData=localeData;duration_prototype__proto.toIsoString=deprecate("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",iso_string__toISOString);duration_prototype__proto.lang=lang;addFormatToken("X",0,0,"unix");addFormatToken("x",0,0,"valueOf");addRegexToken("x",matchSigned);addRegexToken("X",matchTimestamp);addParseToken("X",function(input,array,config){config._d=new Date(parseFloat(input,10)*1e3)});addParseToken("x",function(input,array,config){config._d=new Date(toInt(input))});utils_hooks__hooks.version="2.10.3";setHookCallback(local__createLocal);utils_hooks__hooks.fn=momentPrototype;utils_hooks__hooks.min=min;utils_hooks__hooks.max=max;utils_hooks__hooks.utc=create_utc__createUTC;utils_hooks__hooks.unix=moment__createUnix;utils_hooks__hooks.months=lists__listMonths;utils_hooks__hooks.isDate=isDate;utils_hooks__hooks.locale=locale_locales__getSetGlobalLocale;utils_hooks__hooks.invalid=valid__createInvalid;utils_hooks__hooks.duration=create__createDuration;utils_hooks__hooks.isMoment=isMoment;utils_hooks__hooks.weekdays=lists__listWeekdays;utils_hooks__hooks.parseZone=moment__createInZone;utils_hooks__hooks.localeData=locale_locales__getLocale;utils_hooks__hooks.isDuration=isDuration;utils_hooks__hooks.monthsShort=lists__listMonthsShort;utils_hooks__hooks.weekdaysMin=lists__listWeekdaysMin;utils_hooks__hooks.defineLocale=defineLocale;utils_hooks__hooks.weekdaysShort=lists__listWeekdaysShort;utils_hooks__hooks.normalizeUnits=normalizeUnits;utils_hooks__hooks.relativeTimeThreshold=duration_humanize__getSetRelativeTimeThreshold;var _moment=utils_hooks__hooks;return _moment})},{}],opening_hours:[function(require,module,exports){/*
    216 * For information see https://github.com/ypid/opening_hours.js
    3  * and the doc directory which contains internal documentation and design.
     17 * and the docs directory which contains internal documentation and design.
    418 */
    5 /* jshint laxbreak: true */
    6 /* jshint boss: true */
    7 /* jshint loopfunc: true */
    8 
    9 (function (root, factory) {
    10         /* constants (holidays, error correction) {{{ */
    11         /* holidays {{{ */
    12         /*
    13          * The country code keys and the PH, SH keys are surrounded by '':
    14          * :%s/^\s\+\zs"\([^"]\+\)"\(: {\)/'\1'\2/
    15          * Fixed the indention with Vim Marco:
    16          * /'PH'<cr>f{jVk%k,a:
    17          * Fixed spacing in parenthesis:
    18          * :%s/\[\zs\([^ ]\)/ \1/e | %s/\([^ ]\)\]/\1 \]/e | %s/,\([^ ]\)/, \1/e
    19          */
    20         var holidays = {
    21                 'fr': { // {{{
    22                         'PH': { // http://fr.wikipedia.org/wiki/F%C3%AAtes_et_jours_f%C3%A9ri%C3%A9s_en_France
    23                                 "Jour de l'an"                          : [  1,  1 ],
    24                                 "Vendredi saint"                        : [  'easter', -2, [ 'Moselle', 'Bas-Rhin', 'Haut-Rhin', 'Guadeloupe', 'Martinique', 'Polynésie française' ] ],
    25                                 "Lundi de Pâques"                       : [  'easter', 1 ],
    26                                 "Saint-Pierre-Chanel"                   : [  4, 28, [ 'Wallis-et-Futuna' ] ],
    27                                 "Fête du Travail"                       : [  5,  1 ],
    28                                 "Fête de la Victoire"                   : [  5,  8 ],
    29                                 "Abolition de l'esclavage (Martinique)" : [  5, 22, [ 'Martinique' ] ],
    30                                 "Abolition de l'esclavage (Guadeloupe)" : [  5, 27, [ 'Guadeloupe' ] ],
    31                                 "Jeudi de l'Ascension"                  : [  'easter', 39 ],
    32                                 "Lundi de Pentecôte"                    : [  'easter', 50 ],
    33                                 "Abolition de l'esclavage (Guyane)"     : [  6, 10, [ 'Guyane' ] ],
    34                                 "Fête de l'autonomie"                   : [  6, 29, [ 'Polynésie française' ] ],
    35                                 "Fête nationale"                        : [  7, 14 ],
    36                                 "Fête Victor Schoelcher"                : [  7, 21, [ 'Guadeloupe', 'Martinique' ] ],
    37                                 "Fête du Territoire"                    : [  7, 29, [ 'Wallis-et-Futuna' ] ],
    38                                 "Assomption"                            : [  8, 15 ],
    39                                 "Fête de la citoyenneté"                : [  9, 24, [ 'Nouvelle-Calédonie' ] ],
    40                                 "Toussaint"                             : [ 11,  1 ],
    41                                 "Armistice"                             : [ 11, 11 ],
    42                                 "Abolition de l'esclavage (Réunion)"    : [ 12, 20, [ 'Réunion' ] ],
    43                                 "Noël"                                  : [ 12, 25 ],
    44                                 "Saint-Étienne "                        : [ 12, 26, [ 'Moselle', 'Bas-Rhin', 'Haut-Rhin' ] ]
    45                         }
    46                 }, // }}}
    47                 'de': { // {{{
    48                         'PH': { // http://de.wikipedia.org/wiki/Feiertage_in_Deutschland
    49                                 'Neujahrstag'               : [  1,  1 ], // month 1, day 1, whole Germany
    50                                 'Heilige Drei Könige'       : [  1,  6, [ 'Baden-Württemberg', 'Bayern', 'Sachsen-Anhalt'] ], // only in the specified states
    51                                 'Tag der Arbeit'            : [  5,  1 ], // whole Germany
    52                                 'Karfreitag'                : [ 'easter', -2 ], // two days before easter
    53                                 'Ostersonntag'              : [ 'easter',  0, [ 'Brandenburg'] ],
    54                                 'Ostermontag'               : [ 'easter',  1 ],
    55                                 'Christi Himmelfahrt'       : [ 'easter', 39 ],
    56                                 'Pfingstsonntag'            : [ 'easter', 49, [ 'Brandenburg'] ],
    57                                 'Pfingstmontag'             : [ 'easter', 50 ],
    58                                 'Fronleichnam'              : [ 'easter', 60, [ 'Baden-Württemberg', 'Bayern', 'Hessen', 'Nordrhein-Westfalen', 'Rheinland-Pfalz', 'Saarland' ] ],
    59                                 'Mariä Himmelfahrt'         : [  8, 15, [ 'Saarland'] ],
    60                                 'Tag der Deutschen Einheit' : [ 10,  3 ],
    61                                 'Reformationstag'           : [ 10, 31, [ 'Brandenburg', 'Mecklenburg-Vorpommern', 'Sachsen', 'Sachsen-Anhalt', 'Thüringen'] ],
    62                                 'Allerheiligen'             : [ 11,  1, [ 'Baden-Württemberg', 'Bayern', 'Nordrhein-Westfalen', 'Rheinland-Pfalz', 'Saarland' ] ],
    63                                 '1. Weihnachtstag'          : [ 12, 25 ],
    64                                 '2. Weihnachtstag'          : [ 12, 26 ],
    65                                 // 'Silvester'              : [ 12, 31 ], // for testing
    66                         },
    67                         'Baden-Württemberg': { // does only apply in Baden-Württemberg
    68                                 // This more specific rule set overwrites the country wide one (they are just ignored).
    69                                 // You may use this instead of the country wide with some
    70                                 // additional holidays for some states, if one state
    71                                 // totally disagrees about how to do holidays …
    72                                 // 'PH': {
    73                                 //     '2. Weihnachtstag'          : [ 12, 26 ],
    74                                 // },
    75 
    76                                 // school holiday normally variate between states
    77                                 'SH': [ // generated by convert_ical_to_json
    78                                                 // You may can adjust this script to use other resources (for other countries) too.
    79                                         {
    80                                                 name: 'Osterferien',
    81                                                 2005: [  3, 24, /* to */  3, 24,   3, 29, /* to */  4,  2 ],
    82                                                 2006: [  4, 18, /* to */  4, 22 ],
    83                                                 2007: [  4,  2, /* to */  4, 14 ],
    84                                                 2008: [  3, 17, /* to */  3, 28 ],
    85                                                 2009: [  4,  9, /* to */  4,  9,   4, 14, /* to */  4, 17 ],
    86                                                 2010: [  4,  1, /* to */  4,  1,   4,  6, /* to */  4, 10 ],
    87                                                 2011: [  4, 21, /* to */  4, 21,   4, 26, /* to */  4, 30 ],
    88                                                 2012: [  4,  2, /* to */  4, 13 ],
    89                                                 2013: [  3, 25, /* to */  4,  5 ],
    90                                                 2014: [  4, 14, /* to */  4, 25 ],
    91                                                 2015: [  3, 30, /* to */  4, 10 ],
    92                                                 2016: [  3, 29, /* to */  4,  2 ],
    93                                                 2017: [  4, 10, /* to */  4, 21 ],
    94                                         },
    95                                         {
    96                                                 name: 'Pfingstferien',
    97                                                 2005: [  5, 17, /* to */  5, 28 ],
    98                                                 2006: [  5, 29, /* to */  6, 10 ],
    99                                                 2007: [  5, 29, /* to */  6,  9 ],
    100                                                 2008: [  5, 13, /* to */  5, 23 ],
    101                                                 2009: [  5, 25, /* to */  6,  6 ],
    102                                                 2010: [  5, 25, /* to */  6,  5 ],
    103                                                 2011: [  6, 14, /* to */  6, 25 ],
    104                                                 2012: [  5, 29, /* to */  6,  9 ],
    105                                                 2013: [  5, 21, /* to */  6,  1 ],
    106                                                 2014: [  6, 10, /* to */  6, 21 ],
    107                                                 2015: [  5, 26, /* to */  6,  6 ],
    108                                                 2016: [  5, 17, /* to */  5, 28 ],
    109                                                 2017: [  6,  6, /* to */  6, 16 ],
    110                                         },
    111                                         {
    112                                                 name: 'Sommerferien',
    113                                                 2005: [  7, 28, /* to */  9, 10 ],
    114                                                 2006: [  8,  3, /* to */  9, 16 ],
    115                                                 2007: [  7, 26, /* to */  9,  8 ],
    116                                                 2008: [  7, 24, /* to */  9,  6 ],
    117                                                 2009: [  7, 30, /* to */  9, 12 ],
    118                                                 2010: [  7, 29, /* to */  9, 11 ],
    119                                                 2011: [  7, 28, /* to */  9, 10 ],
    120                                                 2012: [  7, 26, /* to */  9,  8 ],
    121                                                 2013: [  7, 25, /* to */  9,  7 ],
    122                                                 2014: [  7, 31, /* to */  9, 13 ],
    123                                                 2015: [  7, 30, /* to */  9, 12 ],
    124                                                 2016: [  7, 28, /* to */  9, 10 ],
    125                                                 2017: [  7, 27, /* to */  9,  9 ],
    126                                         },
    127                                         {
    128                                                 name: 'Herbstferien',
    129                                                 2005: [ 11,  2, /* to */ 11,  4 ],
    130                                                 2006: [ 10, 30, /* to */ 11,  3 ],
    131                                                 2007: [ 10, 29, /* to */ 11,  3 ],
    132                                                 2008: [ 10, 27, /* to */ 10, 31 ],
    133                                                 2009: [ 10, 26, /* to */ 10, 31 ],
    134                                                 2010: [ 11,  2, /* to */ 11,  6 ],
    135                                                 2011: [ 10, 31, /* to */ 10, 31,  11,  2, /* to */ 11,  4 ],
    136                                                 2012: [ 10, 29, /* to */ 11,  2 ],
    137                                                 2013: [ 10, 28, /* to */ 10, 30 ],
    138                                                 2014: [ 10, 27, /* to */ 10, 30 ],
    139                                                 2015: [ 11,  2, /* to */ 11,  6 ],
    140                                                 2016: [ 11,  2, /* to */ 11,  4 ],
    141                                         },
    142                                         {
    143                                                 name: 'Weihnachtsferien',
    144                                                 2005: [ 12, 22, /* to */  1,  5 ],
    145                                                 2006: [ 12, 27, /* to */  1,  5 ],
    146                                                 2007: [ 12, 24, /* to */  1,  5 ],
    147                                                 2008: [ 12, 22, /* to */  1, 10 ],
    148                                                 2009: [ 12, 23, /* to */  1,  9 ],
    149                                                 2010: [ 12, 23, /* to */  1,  8 ],
    150                                                 2011: [ 12, 23, /* to */  1,  5 ],
    151                                                 2012: [ 12, 24, /* to */  1,  5 ],
    152                                                 2013: [ 12, 23, /* to */  1,  4 ],
    153                                                 2014: [ 12, 22, /* to */  1,  5 ],
    154                                                 2015: [ 12, 23, /* to */  1,  9 ],
    155                                                 2016: [ 12, 23, /* to */  1,  7 ],
    156                                         },
    157                                 ],
    158                         },
    159                         'Mecklenburg-Vorpommern': {
    160                                 'SH': [
    161                                         {
    162                                                 name: 'Winterferien',
    163                                                 2010: [  2,  6, /* to */  2, 20 ],
    164                                                 2011: [  2,  7, /* to */  2, 19 ],
    165                                                 2012: [  2,  6, /* to */  2, 17 ],
    166                                                 2013: [  2,  4, /* to */  2, 15 ],
    167                                                 2014: [  2,  3, /* to */  2, 15 ],
    168                                                 2015: [  2,  2, /* to */  2, 14 ],
    169                                                 2016: [  2,  1, /* to */  2, 13 ],
    170                                                 2017: [  2,  6, /* to */  2, 18 ],
    171                                         },
    172                                         {
    173                                                 name: 'Osterferien',
    174                                                 2010: [  3, 29, /* to */  4,  7 ],
    175                                                 2011: [  4, 16, /* to */  4, 27 ],
    176                                                 2012: [  4,  2, /* to */  4, 11 ],
    177                                                 2013: [  3, 25, /* to */  4,  3 ],
    178                                                 2014: [  4, 14, /* to */  4, 23 ],
    179                                                 2015: [  3, 30, /* to */  4,  8 ],
    180                                                 2016: [  3, 21, /* to */  3, 30 ],
    181                                                 2017: [  4, 10, /* to */  4, 19 ],
    182                                         },
    183                                         {
    184                                                 name: 'Pfingstferien',
    185                                                 2010: [  5, 21, /* to */  5, 22 ],
    186                                                 2011: [  6, 10, /* to */  6, 14 ],
    187                                                 2012: [  5, 25, /* to */  5, 29 ],
    188                                                 2013: [  5, 17, /* to */  5, 21 ],
    189                                                 2014: [  6,  6, /* to */  6, 10 ],
    190                                                 2015: [  5, 22, /* to */  5, 26 ],
    191                                                 2016: [  5, 14, /* to */  5, 17 ],
    192                                                 2017: [  6,  2, /* to */  6,  6 ],
    193                                         },
    194                                         {
    195                                                 name: 'Sommerferien',
    196                                                 2010: [  7, 12, /* to */  8, 21 ],
    197                                                 2011: [  7,  4, /* to */  8, 13 ],
    198                                                 2012: [  6, 23, /* to */  8,  4 ],
    199                                                 2013: [  6, 22, /* to */  8,  3 ],
    200                                                 2014: [  7, 14, /* to */  8, 23 ],
    201                                                 2015: [  7, 20, /* to */  8, 29 ],
    202                                                 2016: [  7, 25, /* to */  9,  3 ],
    203                                                 2017: [  7, 24, /* to */  9,  2 ],
    204                                         },
    205                                         {
    206                                                 name: 'Herbstferien',
    207                                                 2010: [ 10, 18, /* to */ 10, 23 ],
    208                                                 2011: [ 10, 17, /* to */ 10, 21 ],
    209                                                 2012: [ 10,  1, /* to */ 10,  5 ],
    210                                                 2013: [ 10, 14, /* to */ 10, 19 ],
    211                                                 2014: [ 10, 20, /* to */ 10, 25 ],
    212                                                 2015: [ 10, 24, /* to */ 10, 30 ],
    213                                                 2016: [ 10, 24, /* to */ 10, 28 ],
    214                                         },
    215                                         {
    216                                                 name: 'Weihnachtsferien',
    217                                                 2010: [ 12, 23, /* to */ 12, 31 ],
    218                                                 2011: [ 12, 23, /* to */  1,  3 ],
    219                                                 2012: [ 12, 21, /* to */  1,  4 ],
    220                                                 2013: [ 12, 23, /* to */  1,  3 ],
    221                                                 2014: [ 12, 22, /* to */  1,  2 ],
    222                                                 2015: [ 12, 21, /* to */  1,  2 ],
    223                                                 2016: [ 12, 22, /* to */  1,  2 ],
    224                                         },
    225                                 ],
    226                         },
    227                         'Hessen': {
    228                                 'SH': [
    229                                         {
    230                                                 name: 'Osterferien',
    231                                                 2010: [  3, 29, /* to */  4, 10 ],
    232                                                 2011: [  4, 18, /* to */  4, 30 ],
    233                                                 2012: [  4,  2, /* to */  4, 14 ],
    234                                                 2013: [  3, 25, /* to */  4,  6 ],
    235                                                 2014: [  4, 14, /* to */  4, 26 ],
    236                                                 2015: [  3, 30, /* to */  4, 11 ],
    237                                                 2016: [  3, 29, /* to */  4,  9 ],
    238                                                 2017: [  4,  3, /* to */  4, 15 ],
    239                                                 2018: [  3, 26, /* to */  4,  7 ],
    240                                         },
    241                                         {
    242                                                 name: 'Sommerferien',
    243                                                 2010: [  7,  5, /* to */  8, 14 ],
    244                                                 2011: [  6, 27, /* to */  8,  5 ],
    245                                                 2012: [  7,  2, /* to */  8, 10 ],
    246                                                 2013: [  7,  8, /* to */  8, 16 ],
    247                                                 2014: [  7, 28, /* to */  9,  5 ],
    248                                                 2015: [  7, 27, /* to */  9,  5 ],
    249                                                 2016: [  7, 18, /* to */  8, 26 ],
    250                                                 2017: [  7,  3, /* to */  8, 11 ],
    251                                         },
    252                                         {
    253                                                 name: 'Herbstferien',
    254                                                 2010: [ 10, 11, /* to */ 10, 22 ],
    255                                                 2011: [ 10, 10, /* to */ 10, 22 ],
    256                                                 2012: [ 10, 15, /* to */ 10, 27 ],
    257                                                 2013: [ 10, 14, /* to */ 10, 26 ],
    258                                                 2014: [ 10, 20, /* to */ 11,  1 ],
    259                                                 2015: [ 10, 19, /* to */ 10, 31 ],
    260                                                 2016: [ 10, 17, /* to */ 10, 29 ],
    261                                                 2017: [ 10,  9, /* to */ 10, 21 ],
    262                                         },
    263                                         {
    264                                                 name: 'Weihnachtsferien',
    265                                                 2010: [ 12, 20, /* to */  1,  7 ],
    266                                                 2011: [ 12, 21, /* to */  1,  6 ],
    267                                                 2012: [ 12, 24, /* to */  1, 12 ],
    268                                                 2013: [ 12, 23, /* to */  1, 11 ],
    269                                                 2014: [ 12, 22, /* to */  1, 10 ],
    270                                                 2015: [ 12, 23, /* to */  1,  9 ],
    271                                                 2016: [ 12, 22, /* to */  1,  7 ],
    272                                                 2017: [ 12, 24, /* to */  1, 13 ],
    273                                         },
    274                                 ],
    275                         },
    276                         'Schleswig-Holstein': {
    277                                 'SH': [
    278                                         {
    279                                                 name: 'Osterferien',
    280                                                 2010: [  4,  3, /* to */  4, 17 ],
    281                                                 2011: [  4, 15, /* to */  4, 30 ],
    282                                                 2012: [  3, 30, /* to */  4, 13 ],
    283                                                 2013: [  3, 25, /* to */  4,  9 ],
    284                                                 2014: [  4, 16, /* to */  5,  2 ],
    285                                                 2015: [  4,  1, /* to */  4, 17 ],
    286                                                 2016: [  3, 24, /* to */  4,  9 ],
    287                                                 2017: [  4,  7, /* to */  4, 21 ],
    288                                         },
    289                                         {
    290                                                 name: 'Sommerferien',
    291                                                 2010: [  7, 12, /* to */  8, 21 ],
    292                                                 2011: [  7,  4, /* to */  8, 13 ],
    293                                                 2012: [  6, 25, /* to */  8,  4 ],
    294                                                 2013: [  6, 24, /* to */  8,  3 ],
    295                                                 2014: [  7, 14, /* to */  8, 23 ],
    296                                                 2015: [  7, 20, /* to */  8, 29 ],
    297                                                 2016: [  7, 25, /* to */  9,  3 ],
    298                                                 2017: [  7, 24, /* to */  9,  2 ],
    299                                         },
    300                                         {
    301                                                 name: 'Pfingstferien',
    302                                                 2011: [  6,  3, /* to */  6,  4 ],
    303                                                 2012: [  5, 18, /* to */  5, 18 ],
    304                                                 2013: [  5, 10, /* to */  5, 10 ],
    305                                                 2014: [  5, 30, /* to */  5, 30 ],
    306                                                 2015: [  5, 15, /* to */  5, 15 ],
    307                                                 2016: [  5,  6, /* to */  5,  6 ],
    308                                                 2017: [  5, 26, /* to */  5, 26 ],
    309                                         },
    310                                         {
    311                                                 name: 'Herbstferien',
    312                                                 2010: [ 10, 11, /* to */ 10, 23 ],
    313                                                 2011: [ 10, 10, /* to */ 10, 22 ],
    314                                                 2012: [ 10,  4, /* to */ 10, 19 ],
    315                                                 2013: [ 10,  4, /* to */ 10, 18 ],
    316                                                 2014: [ 10, 13, /* to */ 10, 25 ],
    317                                                 2015: [ 10, 19, /* to */ 10, 31 ],
    318                                                 2016: [ 10, 17, /* to */ 10, 29 ],
    319                                         },
    320                                         {
    321                                                 name: 'Weihnachtsferien',
    322                                                 2010: [ 12, 23, /* to */  1,  7 ],
    323                                                 2011: [ 12, 23, /* to */  1,  6 ],
    324                                                 2012: [ 12, 24, /* to */  1,  5 ],
    325                                                 2013: [ 12, 23, /* to */  1,  6 ],
    326                                                 2014: [ 12, 22, /* to */  1,  6 ],
    327                                                 2015: [ 12, 21, /* to */  1,  6 ],
    328                                                 2016: [ 12, 23, /* to */  1,  6 ],
    329                                         },
    330                                 ],
    331                         },
    332                         'Berlin': {
    333                                 'SH': [
    334                                         {
    335                                                 name: 'Winterferien',
    336                                                 2010: [  2,  1, /* to */  2,  6 ],
    337                                                 2011: [  1, 31, /* to */  2,  5 ],
    338                                                 2012: [  1, 30, /* to */  2,  4 ],
    339                                                 2013: [  2,  4, /* to */  2,  9 ],
    340                                                 2014: [  2,  3, /* to */  2,  8 ],
    341                                                 2015: [  2,  2, /* to */  2,  7 ],
    342                                                 2016: [  2,  1, /* to */  2,  6 ],
    343                                                 2017: [  1, 30, /* to */  2,  4 ],
    344                                         },
    345                                         {
    346                                                 name: 'Osterferien',
    347                                                 2010: [  3, 31, /* to */  4, 10 ],
    348                                                 2011: [  4, 18, /* to */  4, 30 ],
    349                                                 2012: [  4,  2, /* to */  4, 14,   4, 30, /* to */  4, 30 ],
    350                                                 2013: [  3, 25, /* to */  4,  6 ],
    351                                                 2014: [  4, 14, /* to */  4, 26,   5,  2, /* to */  5,  2 ],
    352                                                 2015: [  3, 30, /* to */  4, 11 ],
    353                                                 2016: [  3, 21, /* to */  4,  2 ],
    354                                                 2017: [  4, 10, /* to */  4, 22 ],
    355                                         },
    356                                         {
    357                                                 name: 'Pfingstferien',
    358                                                 2010: [  5, 14, /* to */  5, 14,   5, 25, /* to */  5, 25 ],
    359                                                 2011: [  6,  3, /* to */  6,  3 ],
    360                                                 2012: [  5, 18, /* to */  5, 18 ],
    361                                                 2013: [  5, 10, /* to */  5, 10,   5, 21, /* to */  5, 21 ],
    362                                                 2014: [  5, 30, /* to */  5, 30 ],
    363                                                 2015: [  5, 15, /* to */  5, 15 ],
    364                                                 2016: [  5,  6, /* to */  5,  6,   5, 17, /* to */  5, 17 ],
    365                                                 2017: [  5, 26, /* to */  5, 26 ],
    366                                         },
    367                                         {
    368                                                 name: 'Sommerferien',
    369                                                 2010: [  7,  7, /* to */  8, 21 ],
    370                                                 2011: [  6, 29, /* to */  8, 12 ],
    371                                                 2012: [  6, 20, /* to */  8,  3 ],
    372                                                 2013: [  6, 19, /* to */  8,  2 ],
    373                                                 2014: [  7,  9, /* to */  8, 22 ],
    374                                                 2015: [  7, 15, /* to */  8, 28 ],
    375                                                 2016: [  7, 20, /* to */  9,  2 ],
    376                                                 2017: [  7, 19, /* to */  9,  1 ],
    377                                         },
    378                                         {
    379                                                 name: 'Herbstferien',
    380                                                 2010: [ 10, 11, /* to */ 10, 23 ],
    381                                                 2011: [ 10,  4, /* to */ 10, 14 ],
    382                                                 2012: [ 10,  1, /* to */ 10, 13 ],
    383                                                 2013: [  9, 30, /* to */ 10, 12 ],
    384                                                 2014: [ 10, 20, /* to */ 11,  1 ],
    385                                                 2015: [ 10, 19, /* to */ 10, 31 ],
    386                                                 2016: [ 10, 17, /* to */ 10, 28 ],
    387                                         },
    388                                         {
    389                                                 name: 'Weihnachtsferien',
    390                                                 2010: [ 12, 23, /* to */  1,  1 ],
    391                                                 2011: [ 12, 23, /* to */  1,  3 ],
    392                                                 2012: [ 12, 24, /* to */  1,  4 ],
    393                                                 2013: [ 12, 23, /* to */  1,  3 ],
    394                                                 2014: [ 12, 22, /* to */  1,  2 ],
    395                                                 2015: [ 12, 23, /* to */  1,  2 ],
    396                                                 2016: [ 12, 23, /* to */  1,  3 ],
    397                                         },
    398                                 ],
    399                         },
    400                         'Saarland': {
    401                                 'SH': [
    402                                         {
    403                                                 name: 'Winterferien',
    404                                                 2010: [  2, 15, /* to */  2, 20 ],
    405                                                 2011: [  3,  7, /* to */  3, 12 ],
    406                                                 2012: [  2, 20, /* to */  2, 25 ],
    407                                                 2013: [  2, 11, /* to */  2, 16 ],
    408                                                 2014: [  3,  3, /* to */  3,  8 ],
    409                                                 2015: [  2, 16, /* to */  2, 21 ],
    410                                         },
    411                                         {
    412                                                 name: 'Osterferien',
    413                                                 2010: [  3, 29, /* to */  4, 10 ],
    414                                                 2011: [  4, 18, /* to */  4, 30 ],
    415                                                 2012: [  4,  2, /* to */  4, 14 ],
    416                                                 2013: [  3, 25, /* to */  4,  6 ],
    417                                                 2014: [  4, 14, /* to */  4, 26 ],
    418                                                 2015: [  3, 30, /* to */  4, 11 ],
    419                                         },
    420                                         {
    421                                                 name: 'Sommerferien',
    422                                                 2010: [  7,  5, /* to */  8, 14 ],
    423                                                 2011: [  6, 24, /* to */  8,  6 ],
    424                                                 2012: [  7,  2, /* to */  8, 14 ],
    425                                                 2013: [  7,  8, /* to */  8, 17 ],
    426                                                 2014: [  7, 28, /* to */  9,  6 ],
    427                                                 2015: [  7, 27, /* to */  9,  4 ],
    428                                                 2016: [  7, 18, /* to */  8, 26 ],
    429                                                 2017: [  7,  3, /* to */  8, 14 ],
    430                                         },
    431                                         {
    432                                                 name: 'Herbstferien',
    433                                                 2010: [ 10, 11, /* to */ 10, 23 ],
    434                                                 2011: [ 10,  4, /* to */ 10, 15 ],
    435                                                 2012: [ 10, 22, /* to */ 11,  3 ],
    436                                                 2013: [ 10, 21, /* to */ 11,  2 ],
    437                                                 2014: [ 10, 20, /* to */ 10, 31 ],
    438                                         },
    439                                         {
    440                                                 name: 'Weihnachtsferien',
    441                                                 2010: [ 12, 20, /* to */  1,  1 ],
    442                                                 2011: [ 12, 23, /* to */  1,  4 ],
    443                                                 2012: [ 12, 24, /* to */  1,  5 ],
    444                                                 2013: [ 12, 20, /* to */  1,  4 ],
    445                                                 2014: [ 12, 22, /* to */  1,  7 ],
    446                                         },
    447                                 ],
    448                         },
    449                         'Bremen': {
    450                                 'SH': [
    451                                         {
    452                                                 name: 'Winterferien',
    453                                                 2010: [  2,  1, /* to */  2,  2 ],
    454                                                 2011: [  1, 31, /* to */  2,  1 ],
    455                                                 2012: [  1, 30, /* to */  1, 31 ],
    456                                                 2013: [  1, 31, /* to */  2,  1 ],
    457                                                 2014: [  1, 30, /* to */  1, 31 ],
    458                                                 2015: [  2,  2, /* to */  2,  3 ],
    459                                                 2016: [  1, 28, /* to */  1, 29 ],
    460                                                 2017: [  1, 30, /* to */  1, 31 ],
    461                                         },
    462                                         {
    463                                                 name: 'Osterferien',
    464                                                 2010: [  3, 19, /* to */  4,  6 ],
    465                                                 2011: [  4, 16, /* to */  4, 30 ],
    466                                                 2012: [  3, 26, /* to */  4, 11,   4, 30, /* to */  4, 30 ],
    467                                                 2013: [  3, 16, /* to */  4,  2 ],
    468                                                 2014: [  4,  3, /* to */  4, 22,   5,  2, /* to */  5,  2 ],
    469                                                 2015: [  3, 25, /* to */  4, 10 ],
    470                                                 2016: [  3, 18, /* to */  4,  2 ],
    471                                                 2017: [  4, 10, /* to */  4, 22 ],
    472                                         },
    473                                         {
    474                                                 name: 'Pfingstferien',
    475                                                 2010: [  5, 14, /* to */  5, 14,   5, 25, /* to */  5, 25 ],
    476                                                 2011: [  6,  3, /* to */  6,  3,   6, 14, /* to */  6, 14 ],
    477                                                 2012: [  5, 18, /* to */  5, 18,   5, 29, /* to */  5, 29 ],
    478                                                 2013: [  5, 10, /* to */  5, 10,   5, 21, /* to */  5, 21 ],
    479                                                 2014: [  5, 30, /* to */  5, 30,   6, 10, /* to */  6, 10 ],
    480                                                 2015: [  5, 15, /* to */  5, 15,   5, 26, /* to */  5, 26 ],
    481                                                 2016: [  5,  6, /* to */  5,  6,   5, 17, /* to */  5, 17 ],
    482                                                 2017: [  5, 26, /* to */  5, 26,   6,  6, /* to */  6,  6 ],
    483                                         },
    484                                         {
    485                                                 name: 'Sommerferien',
    486                                                 2010: [  6, 24, /* to */  8,  4 ],
    487                                                 2011: [  7,  7, /* to */  8, 17 ],
    488                                                 2012: [  7, 23, /* to */  8, 31 ],
    489                                                 2013: [  6, 27, /* to */  8,  7 ],
    490                                                 2014: [  7, 31, /* to */  9, 10 ],
    491                                                 2015: [  7, 23, /* to */  9,  2 ],
    492                                                 2016: [  6, 23, /* to */  8,  3 ],
    493                                                 2017: [  6, 22, /* to */  8,  2 ],
    494                                         },
    495                                         {
    496                                                 name: 'Herbstferien',
    497                                                 2010: [ 10,  9, /* to */ 10, 23 ],
    498                                                 2011: [ 10, 17, /* to */ 10, 29 ],
    499                                                 2012: [ 10, 22, /* to */ 11,  3 ],
    500                                                 2013: [ 10,  4, /* to */ 10, 18 ],
    501                                                 2014: [ 10, 27, /* to */ 11,  8 ],
    502                                                 2015: [ 10, 19, /* to */ 10, 31 ],
    503                                                 2016: [ 10,  4, /* to */ 10, 15 ],
    504                                         },
    505                                         {
    506                                                 name: 'Weihnachtsferien',
    507                                                 2010: [ 12, 22, /* to */  1,  5 ],
    508                                                 2011: [ 12, 23, /* to */  1,  4 ],
    509                                                 2012: [ 12, 24, /* to */  1,  5 ],
    510                                                 2013: [ 12, 23, /* to */  1,  3 ],
    511                                                 2014: [ 12, 22, /* to */  1,  5 ],
    512                                                 2015: [ 12, 23, /* to */  1,  6 ],
    513                                                 2016: [ 12, 21, /* to */  1,  6 ],
    514                                         },
    515                                 ],
    516                         },
    517                         'Bayern': {
    518                                 'SH': [
    519                                         {
    520                                                 name: 'Winterferien',
    521                                                 2010: [  2, 15, /* to */  2, 20 ],
    522                                                 2011: [  3,  7, /* to */  3, 11 ],
    523                                                 2012: [  2, 20, /* to */  2, 24 ],
    524                                                 2013: [  2, 11, /* to */  2, 15 ],
    525                                                 2014: [  3,  3, /* to */  3,  7 ],
    526                                                 2015: [  2, 16, /* to */  2, 20 ],
    527                                                 2016: [  2,  8, /* to */  2, 12 ],
    528                                                 2017: [  2, 27, /* to */  3,  3 ],
    529                                         },
    530                                         {
    531                                                 name: 'Osterferien',
    532                                                 2010: [  3, 29, /* to */  4, 10 ],
    533                                                 2011: [  4, 18, /* to */  4, 30 ],
    534                                                 2012: [  4,  2, /* to */  4, 14 ],
    535                                                 2013: [  3, 25, /* to */  4,  6 ],
    536                                                 2014: [  4, 14, /* to */  4, 26 ],
    537                                                 2015: [  3, 30, /* to */  4, 11 ],
    538                                                 2016: [  3, 21, /* to */  4,  1 ],
    539                                                 2017: [  4, 10, /* to */  4, 22 ],
    540                                         },
    541                                         {
    542                                                 name: 'Pfingstferien',
    543                                                 2010: [  5, 25, /* to */  6,  5 ],
    544                                                 2011: [  6, 14, /* to */  6, 25 ],
    545                                                 2012: [  5, 29, /* to */  6,  9 ],
    546                                                 2013: [  5, 21, /* to */  5, 31 ],
    547                                                 2014: [  6, 10, /* to */  6, 21 ],
    548                                                 2015: [  5, 26, /* to */  6,  5 ],
    549                                                 2016: [  5, 17, /* to */  5, 28 ],
    550                                                 2017: [  6,  6, /* to */  6, 16 ],
    551                                         },
    552                                         {
    553                                                 name: 'Sommerferien',
    554                                                 2010: [  8,  2, /* to */  9, 13 ],
    555                                                 2011: [  7, 30, /* to */  9, 12 ],
    556                                                 2012: [  8,  1, /* to */  9, 12 ],
    557                                                 2013: [  7, 31, /* to */  9, 11 ],
    558                                                 2014: [  7, 30, /* to */  9, 15 ],
    559                                                 2015: [  8,  1, /* to */  9, 14 ],
    560                                                 2016: [  7, 30, /* to */  9, 12 ],
    561                                                 2017: [  7, 29, /* to */  9, 11 ],
    562                                         },
    563                                         {
    564                                                 name: 'Herbstferien',
    565                                                 2010: [ 11,  2, /* to */ 11,  5 ],
    566                                                 2011: [ 10, 31, /* to */ 11,  5 ],
    567                                                 2012: [ 10, 29, /* to */ 11,  3 ],
    568                                                 2013: [ 10, 28, /* to */ 10, 31 ],
    569                                                 2014: [ 10, 27, /* to */ 10, 31 ],
    570                                                 2015: [ 11,  2, /* to */ 11,  7 ],
    571                                                 2016: [ 10, 31, /* to */ 11,  4 ],
    572                                         },
    573                                         {
    574                                                 name: 'Weihnachtsferien',
    575                                                 2010: [ 12, 24, /* to */  1,  7 ],
    576                                                 2011: [ 12, 27, /* to */  1,  5 ],
    577                                                 2012: [ 12, 24, /* to */  1,  5 ],
    578                                                 2013: [ 12, 23, /* to */  1,  4 ],
    579                                                 2014: [ 12, 24, /* to */  1,  5 ],
    580                                                 2015: [ 12, 24, /* to */  1,  5 ],
    581                                                 2016: [ 12, 24, /* to */  1,  5 ],
    582                                         },
    583                                 ],
    584                         },
    585                         'Niedersachsen': {
    586                                 'SH': [
    587                                         {
    588                                                 name: 'Winterferien',
    589                                                 2010: [  2,  1, /* to */  2,  2 ],
    590                                                 2011: [  1, 31, /* to */  2,  1 ],
    591                                                 2012: [  1, 30, /* to */  1, 31 ],
    592                                                 2013: [  1, 31, /* to */  2,  1 ],
    593                                                 2014: [  1, 30, /* to */  1, 31 ],
    594                                                 2015: [  2,  2, /* to */  2,  3 ],
    595                                                 2016: [  1, 28, /* to */  1, 29 ],
    596                                                 2017: [  1, 30, /* to */  1, 31 ],
    597                                         },
    598                                         {
    599                                                 name: 'Osterferien',
    600                                                 2010: [  3, 19, /* to */  4,  6 ],
    601                                                 2011: [  4, 16, /* to */  4, 30 ],
    602                                                 2012: [  3, 26, /* to */  4, 11,   4, 30, /* to */  4, 30 ],
    603                                                 2013: [  3, 16, /* to */  4,  2 ],
    604                                                 2014: [  4,  3, /* to */  4, 22,   5,  2, /* to */  5,  2 ],
    605                                                 2015: [  3, 25, /* to */  4, 10 ],
    606                                                 2016: [  3, 18, /* to */  4,  2 ],
    607                                                 2017: [  4, 10, /* to */  4, 22 ],
    608                                         },
    609                                         {
    610                                                 name: 'Pfingstferien',
    611                                                 2010: [  5, 14, /* to */  5, 14,   5, 25, /* to */  5, 25 ],
    612                                                 2011: [  6,  3, /* to */  6,  3,   6, 14, /* to */  6, 14 ],
    613                                                 2012: [  5, 18, /* to */  5, 18,   5, 29, /* to */  5, 29 ],
    614                                                 2013: [  5, 10, /* to */  5, 10,   5, 21, /* to */  5, 21 ],
    615                                                 2014: [  5, 30, /* to */  5, 30,   6, 10, /* to */  6, 10 ],
    616                                                 2015: [  5, 15, /* to */  5, 15,   5, 26, /* to */  5, 26 ],
    617                                                 2016: [  5,  6, /* to */  5,  6,   5, 17, /* to */  5, 17 ],
    618                                                 2017: [  5, 26, /* to */  5, 26,   6,  6, /* to */  6,  6 ],
    619                                         },
    620                                         {
    621                                                 name: 'Sommerferien',
    622                                                 2010: [  6, 24, /* to */  8,  4 ],
    623                                                 2011: [  7,  7, /* to */  8, 17 ],
    624                                                 2012: [  7, 23, /* to */  8, 31 ],
    625                                                 2013: [  6, 27, /* to */  8,  7 ],
    626                                                 2014: [  7, 31, /* to */  9, 10 ],
    627                                                 2015: [  7, 23, /* to */  9,  2 ],
    628                                                 2016: [  6, 23, /* to */  8,  3 ],
    629                                                 2017: [  6, 22, /* to */  8,  2 ],
    630                                         },
    631                                         {
    632                                                 name: 'Herbstferien',
    633                                                 2010: [ 10,  9, /* to */ 10, 23 ],
    634                                                 2011: [ 10, 17, /* to */ 10, 29 ],
    635                                                 2012: [ 10, 22, /* to */ 11,  3 ],
    636                                                 2013: [ 10,  4, /* to */ 10, 18 ],
    637                                                 2014: [ 10, 27, /* to */ 11,  8 ],
    638                                                 2015: [ 10, 19, /* to */ 10, 31 ],
    639                                                 2016: [ 10,  4, /* to */ 10, 15 ],
    640                                         },
    641                                         {
    642                                                 name: 'Weihnachtsferien',
    643                                                 2010: [ 12, 22, /* to */  1,  5 ],
    644                                                 2011: [ 12, 23, /* to */  1,  4 ],
    645                                                 2012: [ 12, 24, /* to */  1,  5 ],
    646                                                 2013: [ 12, 23, /* to */  1,  3 ],
    647                                                 2014: [ 12, 22, /* to */  1,  5 ],
    648                                                 2015: [ 12, 23, /* to */  1,  6 ],
    649                                                 2016: [ 12, 21, /* to */  1,  6 ],
    650                                         },
    651                                 ],
    652                         },
    653                         'Nordrhein-Westfalen': {
    654                                 'SH': [
    655                                         {
    656                                                 name: 'Osterferien',
    657                                                 2010: [  3, 27, /* to */  4, 10 ],
    658                                                 2011: [  4, 18, /* to */  4, 30 ],
    659                                                 2012: [  4,  2, /* to */  4, 14 ],
    660                                                 2013: [  3, 25, /* to */  4,  6 ],
    661                                                 2014: [  4, 14, /* to */  4, 26 ],
    662                                                 2015: [  3, 30, /* to */  4, 11 ],
    663                                                 2016: [  3, 21, /* to */  4,  2 ],
    664                                                 2017: [  4, 10, /* to */  4, 22 ],
    665                                         },
    666                                         {
    667                                                 name: 'Pfingstferien',
    668                                                 2010: [  5, 25, /* to */  5, 25 ],
    669                                                 2012: [  5, 29, /* to */  5, 29 ],
    670                                                 2013: [  5, 21, /* to */  5, 21 ],
    671                                                 2014: [  6, 10, /* to */  6, 10 ],
    672                                                 2015: [  5, 26, /* to */  5, 26 ],
    673                                                 2016: [  5, 17, /* to */  5, 17 ],
    674                                                 2017: [  6,  6, /* to */  6,  6 ],
    675                                         },
    676                                         {
    677                                                 name: 'Sommerferien',
    678                                                 2010: [  7, 15, /* to */  8, 27 ],
    679                                                 2011: [  7, 25, /* to */  9,  6 ],
    680                                                 2012: [  7,  9, /* to */  8, 21 ],
    681                                                 2013: [  7, 22, /* to */  9,  3 ],
    682                                                 2014: [  7,  7, /* to */  8, 19 ],
    683                                                 2015: [  6, 29, /* to */  8, 11 ],
    684                                                 2016: [  7, 11, /* to */  8, 23 ],
    685                                                 2017: [  7, 17, /* to */  8, 29 ],
    686                                         },
    687                                         {
    688                                                 name: 'Herbstferien',
    689                                                 2010: [ 10, 11, /* to */ 10, 23 ],
    690                                                 2011: [ 10, 24, /* to */ 11,  5 ],
    691                                                 2012: [ 10,  8, /* to */ 10, 20 ],
    692                                                 2013: [ 10, 21, /* to */ 11,  2 ],
    693                                                 2014: [ 10,  6, /* to */ 10, 18 ],
    694                                                 2015: [ 10,  5, /* to */ 10, 17 ],
    695                                                 2016: [ 10, 10, /* to */ 10, 21 ],
    696                                         },
    697                                         {
    698                                                 name: 'Weihnachtsferien',
    699                                                 2010: [ 12, 24, /* to */  1,  8 ],
    700                                                 2011: [ 12, 23, /* to */  1,  6 ],
    701                                                 2012: [ 12, 21, /* to */  1,  4 ],
    702                                                 2013: [ 12, 23, /* to */  1,  7 ],
    703                                                 2014: [ 12, 22, /* to */  1,  6 ],
    704                                                 2015: [ 12, 23, /* to */  1,  6 ],
    705                                                 2016: [ 12, 23, /* to */  1,  6 ],
    706                                         },
    707                                 ],
    708                         },
    709                         'Sachsen': {
    710                                 'SH': [
    711                                         {
    712                                                 name: 'Winterferien',
    713                                                 2010: [  2,  8, /* to */  2, 20 ],
    714                                                 2011: [  2, 12, /* to */  2, 26 ],
    715                                                 2012: [  2, 13, /* to */  2, 25 ],
    716                                                 2013: [  2,  4, /* to */  2, 15 ],
    717                                                 2014: [  2, 17, /* to */  3,  1 ],
    718                                                 2015: [  2,  9, /* to */  2, 21 ],
    719                                                 2016: [  2,  8, /* to */  2, 20 ],
    720                                                 2017: [  2, 13, /* to */  2, 24 ],
    721                                         },
    722                                         {
    723                                                 name: 'Osterferien',
    724                                                 2010: [  4,  1, /* to */  4, 10 ],
    725                                                 2011: [  4, 22, /* to */  4, 30 ],
    726                                                 2012: [  4,  6, /* to */  4, 14 ],
    727                                                 2013: [  3, 29, /* to */  4,  6 ],
    728                                                 2014: [  4, 18, /* to */  4, 26 ],
    729                                                 2015: [  4,  2, /* to */  4, 11 ],
    730                                                 2016: [  3, 25, /* to */  4,  2 ],
    731                                                 2017: [  4, 13, /* to */  4, 22 ],
    732                                         },
    733                                         {
    734                                                 name: 'Pfingstferien',
    735                                                 2010: [  5, 14, /* to */  5, 14 ],
    736                                                 2011: [  6,  3, /* to */  6,  3 ],
    737                                                 2012: [  5, 18, /* to */  5, 18 ],
    738                                                 2013: [  5, 10, /* to */  5, 10,   5, 18, /* to */  5, 22 ],
    739                                                 2014: [  5, 30, /* to */  5, 30 ],
    740                                                 2015: [  5, 15, /* to */  5, 15 ],
    741                                                 2016: [  5,  6, /* to */  5,  6 ],
    742                                                 2017: [  5, 26, /* to */  5, 26 ],
    743                                         },
    744                                         {
    745                                                 name: 'Sommerferien',
    746                                                 2010: [  6, 28, /* to */  8,  6 ],
    747                                                 2011: [  7, 11, /* to */  8, 19 ],
    748                                                 2012: [  7, 23, /* to */  8, 31 ],
    749                                                 2013: [  7, 15, /* to */  8, 23 ],
    750                                                 2014: [  7, 21, /* to */  8, 29 ],
    751                                                 2015: [  7, 13, /* to */  8, 21 ],
    752                                                 2016: [  6, 27, /* to */  8,  5 ],
    753                                                 2017: [  6, 26, /* to */  8,  4 ],
    754                                         },
    755                                         {
    756                                                 name: 'Herbstferien',
    757                                                 2010: [ 10,  4, /* to */ 10, 16 ],
    758                                                 2011: [ 10, 17, /* to */ 10, 28 ],
    759                                                 2012: [ 10, 22, /* to */ 11,  2 ],
    760                                                 2013: [ 10, 21, /* to */ 11,  1 ],
    761                                                 2014: [ 10, 20, /* to */ 10, 31 ],
    762                                                 2015: [ 10, 12, /* to */ 10, 24 ],
    763                                                 2016: [ 10,  3, /* to */ 10, 15 ],
    764                                         },
    765                                         {
    766                                                 name: 'Weihnachtsferien',
    767                                                 2010: [ 12, 23, /* to */  1,  1 ],
    768                                                 2011: [ 12, 23, /* to */  1,  2 ],
    769                                                 2012: [ 12, 22, /* to */  1,  2 ],
    770                                                 2013: [ 12, 21, /* to */  1,  3 ],
    771                                                 2014: [ 12, 22, /* to */  1,  3 ],
    772                                                 2015: [ 12, 21, /* to */  1,  2 ],
    773                                                 2016: [ 12, 23, /* to */  1,  2 ],
    774                                         },
    775                                 ],
    776                         },
    777                         'Thüringen': {
    778                                 'SH': [
    779                                         {
    780                                                 name: 'Winterferien',
    781                                                 2010: [  2,  1, /* to */  2,  6 ],
    782                                                 2011: [  1, 31, /* to */  2,  5 ],
    783                                                 2012: [  2,  6, /* to */  2, 11 ],
    784                                                 2013: [  2, 18, /* to */  2, 23 ],
    785                                                 2014: [  2, 17, /* to */  2, 22 ],
    786                                                 2015: [  2,  2, /* to */  2,  7 ],
    787                                                 2016: [  2,  1, /* to */  2,  6 ],
    788                                                 2017: [  2,  6, /* to */  2, 11 ],
    789                                         },
    790                                         {
    791                                                 name: 'Osterferien',
    792                                                 2010: [  3, 29, /* to */  4,  9 ],
    793                                                 2011: [  4, 18, /* to */  4, 30 ],
    794                                                 2012: [  4,  2, /* to */  4, 13 ],
    795                                                 2013: [  3, 25, /* to */  4,  6 ],
    796                                                 2014: [  4, 19, /* to */  5,  2 ],
    797                                                 2015: [  3, 30, /* to */  4, 11 ],
    798                                                 2016: [  3, 24, /* to */  4,  2 ],
    799                                                 2017: [  4, 10, /* to */  4, 21 ],
    800                                         },
    801                                         {
    802                                                 name: 'Sommerferien',
    803                                                 2010: [  6, 24, /* to */  8,  4 ],
    804                                                 2011: [  7, 11, /* to */  8, 19 ],
    805                                                 2012: [  7, 23, /* to */  8, 31 ],
    806                                                 2013: [  7, 15, /* to */  8, 23 ],
    807                                                 2014: [  7, 21, /* to */  8, 29 ],
    808                                                 2015: [  7, 13, /* to */  8, 21 ],
    809                                                 2016: [  6, 27, /* to */  8, 10 ],
    810                                                 2017: [  6, 26, /* to */  8,  9 ],
    811                                         },
    812                                         {
    813                                                 name: 'Pfingstferien',
    814                                                 2011: [  6, 11, /* to */  6, 14 ],
    815                                                 2012: [  5, 25, /* to */  5, 29 ],
    816                                                 2013: [  5, 10, /* to */  5, 10 ],
    817                                                 2014: [  5, 30, /* to */  5, 30 ],
    818                                                 2015: [  5, 15, /* to */  5, 15 ],
    819                                                 2016: [  5,  6, /* to */  5,  6 ],
    820                                                 2017: [  5, 26, /* to */  5, 26 ],
    821                                         },
    822                                         {
    823                                                 name: 'Herbstferien',
    824                                                 2010: [ 10,  9, /* to */ 10, 23 ],
    825                                                 2011: [ 10, 17, /* to */ 10, 28 ],
    826                                                 2012: [ 10, 22, /* to */ 11,  3 ],
    827                                                 2013: [ 10, 21, /* to */ 11,  2 ],
    828                                                 2014: [ 10,  6, /* to */ 10, 18 ],
    829                                                 2015: [ 10,  5, /* to */ 10, 17 ],
    830                                                 2016: [ 10, 10, /* to */ 10, 22 ],
    831                                         },
    832                                         {
    833                                                 name: 'Weihnachtsferien',
    834                                                 2010: [ 12, 23, /* to */  1,  1 ],
    835                                                 2011: [ 12, 23, /* to */  1,  1 ],
    836                                                 2012: [ 12, 24, /* to */  1,  5 ],
    837                                                 2013: [ 12, 23, /* to */  1,  4 ],
    838                                                 2014: [ 12, 22, /* to */  1,  3 ],
    839                                                 2015: [ 12, 23, /* to */  1,  2 ],
    840                                                 2016: [ 12, 23, /* to */ 12, 31 ],
    841                                         },
    842                                 ],
    843                         },
    844                         'Hamburg': {
    845                                 'SH': [
    846                                         {
    847                                                 name: 'Winterferien',
    848                                                 2010: [  1, 29, /* to */  1, 29 ],
    849                                                 2011: [  1, 31, /* to */  1, 31 ],
    850                                                 2012: [  1, 30, /* to */  1, 30 ],
    851                                                 2013: [  2,  1, /* to */  2,  1 ],
    852                                                 2014: [  1, 31, /* to */  1, 31 ],
    853                                                 2015: [  1, 30, /* to */  1, 30 ],
    854                                                 2016: [  1, 29, /* to */  1, 29 ],
    855                                                 2017: [  1, 30, /* to */  1, 30 ],
    856                                         },
    857                                         {
    858                                                 name: 'Osterferien',
    859                                                 2010: [  3,  8, /* to */  3, 20 ],
    860                                                 2011: [  3,  7, /* to */  3, 18 ],
    861                                                 2012: [  3,  5, /* to */  3, 16 ],
    862                                                 2013: [  3,  4, /* to */  3, 15 ],
    863                                                 2014: [  3,  3, /* to */  3, 14 ],
    864                                                 2015: [  3,  2, /* to */  3, 13 ],
    865                                                 2016: [  3,  7, /* to */  3, 18 ],
    866                                                 2017: [  3,  6, /* to */  3, 17 ],
    867                                         },
    868                                         {
    869                                                 name: 'Pfingstferien',
    870                                                 2010: [  5, 14, /* to */  5, 22 ],
    871                                                 2011: [  4, 26, /* to */  4, 29,   6,  3, /* to */  6,  3 ],
    872                                                 2012: [  4, 30, /* to */  5,  4,   5, 18, /* to */  5, 18 ],
    873                                                 2013: [  5,  2, /* to */  5, 10 ],
    874                                                 2014: [  4, 28, /* to */  5,  2,   5, 30, /* to */  5, 30 ],
    875                                                 2015: [  5, 11, /* to */  5, 15 ],
    876                                                 2016: [  5,  6, /* to */  5,  6,   5, 17, /* to */  5, 20 ],
    877                                                 2017: [  5, 22, /* to */  5, 26 ],
    878                                         },
    879                                         {
    880                                                 name: 'Sommerferien',
    881                                                 2010: [  7,  8, /* to */  8, 18 ],
    882                                                 2011: [  6, 30, /* to */  8, 10 ],
    883                                                 2012: [  6, 21, /* to */  8,  1 ],
    884                                                 2013: [  6, 20, /* to */  7, 31 ],
    885                                                 2014: [  7, 10, /* to */  8, 20 ],
    886                                                 2015: [  7, 16, /* to */  8, 26 ],
    887                                                 2016: [  7, 21, /* to */  8, 31 ],
    888                                                 2017: [  7, 20, /* to */  8, 30 ],
    889                                         },
    890                                         {
    891                                                 name: 'Herbstferien',
    892                                                 2010: [ 10,  4, /* to */ 10, 15 ],
    893                                                 2011: [ 10,  4, /* to */ 10, 14 ],
    894                                                 2012: [ 10,  1, /* to */ 10, 12 ],
    895                                                 2013: [  9, 30, /* to */ 10, 11 ],
    896                                                 2014: [ 10, 13, /* to */ 10, 24 ],
    897                                                 2015: [ 10, 19, /* to */ 10, 30 ],
    898                                                 2016: [ 10, 17, /* to */ 10, 28 ],
    899                                         },
    900                                         {
    901                                                 name: 'Weihnachtsferien',
    902                                                 2010: [ 12, 23, /* to */  1,  3 ],
    903                                                 2011: [ 12, 27, /* to */  1,  6 ],
    904                                                 2012: [ 12, 21, /* to */  1,  4 ],
    905                                                 2013: [ 12, 19, /* to */  1,  3 ],
    906                                                 2014: [ 12, 22, /* to */  1,  6 ],
    907                                                 2015: [ 12, 21, /* to */  1,  1 ],
    908                                                 2016: [ 12, 27, /* to */  1,  6 ],
    909                                         },
    910                                 ],
    911                         },
    912                         'Sachsen-Anhalt': {
    913                                 'SH': [
    914                                         {
    915                                                 name: 'Winterferien',
    916                                                 2010: [  2,  8, /* to */  2, 13 ],
    917                                                 2011: [  2,  5, /* to */  2, 12 ],
    918                                                 2012: [  2,  4, /* to */  2, 11 ],
    919                                                 2013: [  2,  1, /* to */  2,  8 ],
    920                                                 2014: [  2,  1, /* to */  2, 12 ],
    921                                                 2015: [  2,  2, /* to */  2, 14 ],
    922                                                 2016: [  2,  1, /* to */  2, 10 ],
    923                                                 2017: [  2,  4, /* to */  2, 11 ],
    924                                         },
    925                                         {
    926                                                 name: 'Osterferien',
    927                                                 2010: [  3, 29, /* to */  4,  9 ],
    928                                                 2011: [  4, 18, /* to */  4, 27 ],
    929                                                 2012: [  4,  2, /* to */  4,  7 ],
    930                                                 2013: [  3, 25, /* to */  3, 30 ],
    931                                                 2014: [  4, 14, /* to */  4, 17 ],
    932                                                 2015: [  4,  2, /* to */  4,  2 ],
    933                                                 2016: [  3, 24, /* to */  3, 24 ],
    934                                                 2017: [  4, 10, /* to */  4, 13 ],
    935                                         },
    936                                         {
    937                                                 name: 'Pfingstferien',
    938                                                 2010: [  5, 14, /* to */  5, 22 ],
    939                                                 2011: [  6, 14, /* to */  6, 18 ],
    940                                                 2012: [  5, 18, /* to */  5, 25 ],
    941                                                 2013: [  5, 10, /* to */  5, 18 ],
    942                                                 2014: [  5, 30, /* to */  6,  7 ],
    943                                                 2015: [  5, 15, /* to */  5, 23 ],
    944                                                 2016: [  5,  6, /* to */  5, 14 ],
    945                                                 2017: [  5, 26, /* to */  5, 26 ],
    946                                         },
    947                                         {
    948                                                 name: 'Sommerferien',
    949                                                 2010: [  6, 24, /* to */  8,  4 ],
    950                                                 2011: [  7, 11, /* to */  8, 24 ],
    951                                                 2012: [  7, 23, /* to */  9,  5 ],
    952                                                 2013: [  7, 15, /* to */  8, 28 ],
    953                                                 2014: [  7, 21, /* to */  9,  3 ],
    954                                                 2015: [  7, 13, /* to */  8, 26 ],
    955                                                 2016: [  6, 27, /* to */  8, 10 ],
    956                                                 2017: [  6, 26, /* to */  8,  9 ],
    957                                         },
    958                                         {
    959                                                 name: 'Herbstferien',
    960                                                 2010: [ 10, 18, /* to */ 10, 23 ],
    961                                                 2011: [ 10, 17, /* to */ 10, 22 ],
    962                                                 2012: [ 10, 29, /* to */ 11,  2 ],
    963                                                 2013: [ 10, 21, /* to */ 10, 25 ],
    964                                                 2014: [ 10, 27, /* to */ 10, 30 ],
    965                                                 2015: [ 10, 17, /* to */ 10, 24 ],
    966                                                 2016: [ 10,  4, /* to */ 10, 15 ],
    967                                         },
    968                                         {
    969                                                 name: 'Weihnachtsferien',
    970                                                 2010: [ 12, 22, /* to */  1,  5 ],
    971                                                 2011: [ 12, 22, /* to */  1,  7 ],
    972                                                 2012: [ 12, 19, /* to */  1,  4 ],
    973                                                 2013: [ 12, 21, /* to */  1,  3 ],
    974                                                 2014: [ 12, 22, /* to */  1,  5 ],
    975                                                 2015: [ 12, 21, /* to */  1,  5 ],
    976                                                 2016: [ 12, 19, /* to */  1,  2 ],
    977                                         },
    978                                 ],
    979                         },
    980                         'Rheinland-Pfalz': {
    981                                 'SH': [
    982                                         {
    983                                                 name: 'Osterferien',
    984                                                 2010: [  3, 26, /* to */  4,  9 ],
    985                                                 2011: [  4, 18, /* to */  4, 29 ],
    986                                                 2012: [  3, 29, /* to */  4, 13 ],
    987                                                 2013: [  3, 20, /* to */  4,  5 ],
    988                                                 2014: [  4, 11, /* to */  4, 25 ],
    989                                                 2015: [  3, 26, /* to */  4, 10 ],
    990                                                 2016: [  3, 18, /* to */  4,  1 ],
    991                                                 2017: [  4, 10, /* to */  4, 21 ],
    992                                         },
    993                                         {
    994                                                 name: 'Sommerferien',
    995                                                 2010: [  7,  5, /* to */  8, 13 ],
    996                                                 2011: [  6, 27, /* to */  8,  5 ],
    997                                                 2012: [  7,  2, /* to */  8, 10 ],
    998                                                 2013: [  7,  8, /* to */  8, 16 ],
    999                                                 2014: [  7, 28, /* to */  9,  5 ],
    1000                                                 2015: [  7, 27, /* to */  9,  4 ],
    1001                                                 2016: [  7, 18, /* to */  8, 26 ],
    1002                                                 2017: [  7,  3, /* to */  8, 11 ],
    1003                                         },
    1004                                         {
    1005                                                 name: 'Herbstferien',
    1006                                                 2010: [ 10, 11, /* to */ 10, 22 ],
    1007                                                 2011: [ 10,  4, /* to */ 10, 14 ],
    1008                                                 2012: [ 10,  1, /* to */ 10, 12 ],
    1009                                                 2013: [ 10,  4, /* to */ 10, 18 ],
    1010                                                 2014: [ 10, 20, /* to */ 10, 31 ],
    1011                                                 2015: [ 10, 19, /* to */ 10, 30 ],
    1012                                                 2016: [ 10, 10, /* to */ 10, 21 ],
    1013                                         },
    1014                                         {
    1015                                                 name: 'Weihnachtsferien',
    1016                                                 2010: [ 12, 23, /* to */  1,  7 ],
    1017                                                 2011: [ 12, 22, /* to */  1,  6 ],
    1018                                                 2012: [ 12, 20, /* to */  1,  4 ],
    1019                                                 2013: [ 12, 23, /* to */  1,  7 ],
    1020                                                 2014: [ 12, 22, /* to */  1,  7 ],
    1021                                                 2015: [ 12, 23, /* to */  1,  8 ],
    1022                                                 2016: [ 12, 22, /* to */  1,  6 ],
    1023                                         },
    1024                                 ],
    1025                         },
    1026                         'Brandenburg': {
    1027                                 'SH': [
    1028                                         {
    1029                                                 name: 'Winterferien',
    1030                                                 2010: [  2,  1, /* to */  2,  6 ],
    1031                                                 2011: [  1, 31, /* to */  2,  5 ],
    1032                                                 2012: [  1, 30, /* to */  2,  4 ],
    1033                                                 2013: [  2,  4, /* to */  2,  9 ],
    1034                                                 2014: [  2,  3, /* to */  2,  8 ],
    1035                                                 2015: [  2,  2, /* to */  2,  7 ],
    1036                                                 2016: [  2,  1, /* to */  2,  6 ],
    1037                                                 2017: [  1, 30, /* to */  2,  4 ],
    1038                                         },
    1039                                         {
    1040                                                 name: 'Osterferien',
    1041                                                 2010: [  3, 31, /* to */  4, 10 ],
    1042                                                 2011: [  4, 20, /* to */  4, 30 ],
    1043                                                 2012: [  4,  4, /* to */  4, 14,   4, 30, /* to */  4, 30 ],
    1044                                                 2013: [  3, 27, /* to */  4,  6 ],
    1045                                                 2014: [  4, 16, /* to */  4, 26,   5,  2, /* to */  5,  2 ],
    1046                                                 2015: [  4,  1, /* to */  4, 11 ],
    1047                                                 2016: [  3, 23, /* to */  4,  2 ],
    1048                                                 2017: [  4, 12, /* to */  4, 22 ],
    1049                                         },
    1050                                         {
    1051                                                 name: 'Pfingstferien',
    1052                                                 2010: [  5, 14, /* to */  5, 14 ],
    1053                                                 2011: [  6,  3, /* to */  6,  3 ],
    1054                                                 2012: [  5, 18, /* to */  5, 18 ],
    1055                                                 2013: [  5, 10, /* to */  5, 10 ],
    1056                                                 2014: [  5, 30, /* to */  5, 30 ],
    1057                                                 2015: [  5, 15, /* to */  5, 15 ],
    1058                                                 2016: [  5,  6, /* to */  5,  6,   5, 17, /* to */  5, 17 ],
    1059                                                 2017: [  5, 26, /* to */  5, 26 ],
    1060                                         },
    1061                                         {
    1062                                                 name: 'Sommerferien',
    1063                                                 2010: [  7,  8, /* to */  8, 21 ],
    1064                                                 2011: [  6, 30, /* to */  8, 13 ],
    1065                                                 2012: [  6, 21, /* to */  8,  3 ],
    1066                                                 2013: [  6, 20, /* to */  8,  2 ],
    1067                                                 2014: [  7, 10, /* to */  8, 22 ],
    1068                                                 2015: [  7, 16, /* to */  8, 28 ],
    1069                                                 2016: [  7, 21, /* to */  9,  3 ],
    1070                                                 2017: [  7, 20, /* to */  9,  1 ],
    1071                                         },
    1072                                         {
    1073                                                 name: 'Herbstferien',
    1074                                                 2010: [ 10, 11, /* to */ 10, 23 ],
    1075                                                 2011: [ 10,  4, /* to */ 10, 14 ],
    1076                                                 2012: [ 10,  1, /* to */ 10, 13 ],
    1077                                                 2013: [  9, 30, /* to */ 10, 12,  11,  1, /* to */ 11,  1 ],
    1078                                                 2014: [ 10, 20, /* to */ 11,  1 ],
    1079                                                 2015: [ 10, 19, /* to */ 10, 30 ],
    1080                                                 2016: [ 10, 17, /* to */ 10, 28 ],
    1081                                         },
    1082                                         {
    1083                                                 name: 'Weihnachtsferien',
    1084                                                 2010: [ 12, 23, /* to */  1,  1 ],
    1085                                                 2011: [ 12, 23, /* to */  1,  3 ],
    1086                                                 2012: [ 12, 24, /* to */  1,  4 ],
    1087                                                 2013: [ 12, 23, /* to */  1,  3 ],
    1088                                                 2014: [ 12, 22, /* to */  1,  2 ],
    1089                                                 2015: [ 12, 23, /* to */  1,  2 ],
    1090                                                 2016: [ 12, 23, /* to */  1,  3 ],
    1091                                         },
    1092                                 ],
    1093                         },
    1094                 }, // }}}
    1095                 'at': { // {{{
    1096                         'PH': { // http://de.wikipedia.org/wiki/Feiertage_in_%C3%96sterreich
    1097                                 'Neujahrstag'                : [  1,  1 ],
    1098                                 'Heilige Drei Könige'        : [  1,  6 ],
    1099                                 // 'Josef'                   : [  3, 19, [ 'Kärnten', 'Steiermark', 'Tirol', 'Vorarlberg' ] ],
    1100                                 // 'Karfreitag'              : [ 'easter', -2 ],
    1101                                 'Ostermontag'                : [ 'easter',  1 ],
    1102                                 'Staatsfeiertag'             : [  5,  1 ],
    1103                                 // 'Florian'                 : [  5,  4, [ 'Oberösterreich' ] ],
    1104                                 'Christi Himmelfahrt'        : [ 'easter', 39 ],
    1105                                 'Pfingstmontag'              : [ 'easter', 50 ],
    1106                                 'Fronleichnam'               : [ 'easter', 60 ],
    1107                                 'Mariä Himmelfahrt'          : [  8, 15 ],
    1108                                 // 'Rupert'                  : [  9, 24, [ 'Salzburg' ] ],
    1109                                 // 'Tag der Volksabstimmung' : [ 10, 10, [ 'Kärnten' ] ],
    1110                                 'Nationalfeiertag'           : [ 10, 26 ],
    1111                                 'Allerheiligen'              : [ 11,  1 ],
    1112                                 // 'Martin'                  : [ 11, 11, [ 'Burgenland' ] ],
    1113                                 // 'Leopold'                 : [ 11, 15, [ 'Niederösterreich', 'Wien' ] ],
    1114                                 'Mariä Empfängnis'           : [ 12,  8 ],
    1115                                 // 'Heiliger Abend'          : [ 12, 24 ],
    1116                                 'Christtag'                  : [ 12, 25 ],
    1117                                 'Stefanitag'                 : [ 12, 26 ],
    1118                                 // 'Silvester'               : [ 12, 31 ],
    1119                         },
    1120                 }, // }}}
    1121                 'ca': { // {{{
    1122                         'PH': { // https://en.wikipedia.org/wiki/Public_holidays_in_Canada
    1123                                 "New Year's Day" : [  1,  1 ],
    1124                                 "Good Friday"    : [  'easter', -2 ],
    1125                                 "Canada Day"     : [  'canadaDay', 0 ],
    1126                                 "Labour Day"     : [  'firstSeptemberMonday', 0 ],
    1127                                 "Christmas Day"  : [ 12, 25 ]
    1128                         },
    1129                         'Alberta': {
    1130                                 'PH': {
    1131                                         "New Year's Day"     : [  1,  1 ],
    1132                                         "Alberta Family Day" : [  'firstFebruaryMonday', 14 ],
    1133                                         "Good Friday"        : [  'easter', -2 ],
    1134                                         "Easter Monday"      : [  'easter', 1 ],
    1135                                         "Victoria Day"       : [  'victoriaDay', 0 ],
    1136                                         "Canada Day"         : [  'canadaDay', 0 ],
    1137                                         "Heritage Day"       : [  'firstAugustMonday', 0 ],
    1138                                         "Labour Day"         : [  'firstSeptemberMonday', 0 ],
    1139                                         "Thanksgiving"       : [  'firstOctoberMonday', 7 ],
    1140                                         "Remembrance Day"    : [ 11, 11 ],
    1141                                         "Christmas Day"      : [ 12, 25 ],
    1142                                         "Boxing Day"         : [ 12, 26 ]
    1143                                 },
    1144                         },
    1145                         'British Columbia': {
    1146                                 'PH': {
    1147                                         "New Year's Day"       : [  1,  1 ],
    1148                                         "Family Day"           : [  'firstFebruaryMonday', 7 ],
    1149                                         "Good Friday"          : [  'easter', -2 ],
    1150                                         "Victoria Day"         : [  'victoriaDay', 0 ],
    1151                                         "Canada Day"           : [  'canadaDay', 0 ],
    1152                                         "British Columbia Day" : [  'firstAugustMonday', 0 ],
    1153                                         "Labour Day"           : [  'firstSeptemberMonday', 0 ],
    1154                                         "Thanksgiving"         : [  'firstOctoberMonday', 7 ],
    1155                                         "Remembrance Day"      : [ 11, 11 ],
    1156                                         "Christmas Day"        : [ 12, 25 ]
    1157                                 },
    1158                         },
    1159                         'Manitoba': {
    1160                                 'PH': {
    1161                                         "New Year's Day"  : [  1,  1 ],
    1162                                         "Louis Riel Day"  : [  'firstFebruaryMonday', 14 ],
    1163                                         "Good Friday"     : [  'easter', -2 ],
    1164                                         "Victoria Day"    : [  'victoriaDay', 0 ],
    1165                                         "Canada Day"      : [  'canadaDay', 0 ],
    1166                                         "Civic Holiday"   : [  'firstAugustMonday', 0 ],
    1167                                         "Labour Day"      : [  'firstSeptemberMonday', 0 ],
    1168                                         "Thanksgiving"    : [  'firstOctoberMonday', 7 ],
    1169                                         "Remembrance Day" : [ 11, 11 ],
    1170                                         "Christmas Day"   : [ 12, 25 ]
    1171                                 },
    1172                         },
    1173                         'New Brunswick': {
    1174                                 'PH': {
    1175                                         "New Year's Day"    : [  1,  1 ],
    1176                                         "Good Friday"       : [  'easter', -2 ],
    1177                                         "Victoria Day"      : [  'victoriaDay', 0 ],
    1178                                         "Canada Day"        : [  'canadaDay', 0 ],
    1179                                         "New Brunswick Day" : [  'firstAugustMonday', 0 ],
    1180                                         "Labour Day"        : [  'firstSeptemberMonday', 0 ],
    1181                                         "Thanksgiving"      : [  'firstOctoberMonday', 7 ],
    1182                                         "Remembrance Day"   : [ 11, 11 ],
    1183                                         "Christmas Day"     : [ 12, 25 ],
    1184                                         "Boxing Day"        : [ 12, 26 ]
    1185                                 },
    1186                         },
    1187                         'Newfoundland and Labrador': {
    1188                                 'PH': {
    1189                                         "New Year's Day"      : [  1,  1 ],
    1190                                         "Saint Patrick's Day" : [  3, 17 ],
    1191                                         "Good Friday"         : [  'easter', -2 ],
    1192                                         "Saint George's Day"  : [  4, 23 ],
    1193                                         "Discovery Day"       : [  6, 24 ],
    1194                                         "Memorial Day"        : [  7, 1 ],
    1195                                         "Orangemen's Day"     : [  7, 12 ],
    1196                                         "Labour Day"          : [  'firstSeptemberMonday', 0 ],
    1197                                         "Armistice Day"       : [ 11, 11 ],
    1198                                         "Christmas Day"       : [ 12, 25 ]
    1199                                 },
    1200                         },
    1201                         'Northwest Territories': {
    1202                                 'PH': {
    1203                                         "New Year's Day"          : [  1,  1 ],
    1204                                         "Good Friday"             : [  'easter', -2 ],
    1205                                         "Victoria Day"            : [  'victoriaDay', 0 ],
    1206                                         "National Aboriginal Day" : [  6, 21 ],
    1207                                         "Canada Day"              : [  'canadaDay', 0 ],
    1208                                         "Civic Holiday"           : [  'firstAugustMonday', 0 ],
    1209                                         "Labour Day"              : [  'firstSeptemberMonday', 0 ],
    1210                                         "Thanksgiving"            : [  'firstOctoberMonday', 7 ],
    1211                                         "Remembrance Day"         : [ 11, 11 ],
    1212                                         "Christmas Day"           : [ 12, 25 ]
    1213                                 },
    1214                         },
    1215                         'Nova Scotia': {
    1216                                 'PH': {
    1217                                         "New Year's Day"  : [  1,  1 ],
    1218                                         "Good Friday"     : [  'easter', -2 ],
    1219                                         "Victoria Day"    : [  'victoriaDay', 0 ],
    1220                                         "Canada Day"      : [  'canadaDay', 0 ],
    1221                                         "Natal Day"       : [  'firstAugustMonday', 0 ],
    1222                                         "Labour Day"      : [  'firstSeptemberMonday', 0 ],
    1223                                         "Thanksgiving"    : [  'firstOctoberMonday', 7 ],
    1224                                         "Remembrance Day" : [ 11, 11 ],
    1225                                         "Christmas Day"   : [ 12, 25 ],
    1226                                         "Boxing Day"      : [ 12, 26 ]
    1227                                 },
    1228                         },
    1229                         'Nunavut': {
    1230                                 'PH': {
    1231                                         "New Year's Day"  : [  1,  1 ],
    1232                                         "Good Friday"     : [  'easter', -2 ],
    1233                                         "Victoria Day"    : [  'victoriaDay', 0 ],
    1234                                         "Canada Day"      : [  'canadaDay', 0 ],
    1235                                         "Nunavut Day"     : [  7, 9 ],
    1236                                         "Civic Holiday"   : [  'firstAugustMonday', 0 ],
    1237                                         "Labour Day"      : [  'firstSeptemberMonday', 0 ],
    1238                                         "Thanksgiving"    : [  'firstOctoberMonday', 7 ],
    1239                                         "Remembrance Day" : [ 11, 11 ],
    1240                                         "Christmas Day"   : [ 12, 25 ]
    1241                                 },
    1242                         },
    1243                         'Ontario': {
    1244                                 'PH': {
    1245                                         "New Year's Day"              : [  1,  1 ],
    1246                                         "Family Day"                  : [  'firstFebruaryMonday', 14 ],
    1247                                         "Good Friday"                 : [  'easter', -2 ],
    1248                                         "Victoria Day"                : [  'victoriaDay', 0 ],
    1249                                         "Canada Day"                  : [  'canadaDay', 0 ],
    1250                                         "August Civic Public Holiday" : [  'firstAugustMonday', 0 ],
    1251                                         "Labour Day"                  : [  'firstSeptemberMonday', 0 ],
    1252                                         "Thanksgiving"                : [  'firstOctoberMonday', 7 ],
    1253                                         "Remembrance Day"             : [ 11, 11 ],
    1254                                         "Christmas Day"               : [ 12, 25 ],
    1255                                         "Boxing Day"                  : [ 12, 26 ]
    1256                                 },
    1257                         },
    1258                         'Prince Edward Island': {
    1259                                 'PH': {
    1260                                         "New Year's Day"      : [  1,  1 ],
    1261                                         "Islander Day"        : [  'firstFebruaryMonday', 14 ],
    1262                                         "Good Friday"         : [  'easter', -2 ],
    1263                                         "Easter Monday"       : [  'easter', 1 ],
    1264                                         "Victoria Day"        : [  'victoriaDay', 0 ],
    1265                                         "Canada Day"          : [  'canadaDay', 0 ],
    1266                                         "Civic Holiday"       : [  'firstAugustMonday', 0 ],
    1267                                         "Gold Cup Parade Day" : [  'firstAugustMonday', 18 ],
    1268                                         "Labour Day"          : [  'firstSeptemberMonday', 0 ],
    1269                                         "Thanksgiving"        : [  'firstOctoberMonday', 7 ],
    1270                                         "Remembrance Day"     : [ 11, 11 ],
    1271                                         "Christmas Day"       : [ 12, 25 ],
    1272                                         "Boxing Day"          : [ 12, 26 ]
    1273                                 },
    1274                         },
    1275                         'Quebec': {
    1276                                 'PH': {
    1277                                         "Jour de l'an"                    : [  1,  1 ],
    1278                                         "Vendredi saint"                  : [  'easter', -2 ],
    1279                                         "Lundi de Pâques"                 : [  'easter', 1 ],
    1280                                         "Journée nationale des patriotes" : [  'victoriaDay', 0 ],
    1281                                         "Fête nationale du Québec"        : [  6, 24 ],
    1282                                         "Fête du Canada"                  : [  'canadaDay', 0 ],
    1283                                         "Fête du Travail"                 : [  'firstSeptemberMonday', 0 ],
    1284                                         "Jour de l'Action de grâce"       : [  'firstOctoberMonday', 7 ],
    1285                                         "Noël"                            : [ 12, 25 ]
    1286                                 },
    1287                         },
    1288                         'Saskatchewan': {
    1289                                 'PH': {
    1290                                         "New Year's Day"   : [  1,  1 ],
    1291                                         "Family Day"       : [  'firstFebruaryMonday', 14 ],
    1292                                         "Good Friday"      : [  'easter', -2 ],
    1293                                         "Victoria Day"     : [  'victoriaDay', 0 ],
    1294                                         "Canada Day"       : [  'canadaDay', 0 ],
    1295                                         "Saskatchewan Day" : [  'firstAugustMonday', 0 ],
    1296                                         "Labour Day"       : [  'firstSeptemberMonday', 0 ],
    1297                                         "Thanksgiving"     : [  'firstOctoberMonday', 7 ],
    1298                                         "Remembrance Day"  : [ 11, 11 ],
    1299                                         "Christmas Day"    : [ 12, 25 ]
    1300                                 },
    1301                         },
    1302                         'Yukon': {
    1303                                 'PH': {
    1304                                         "New Year's Day"  : [  1,  1 ],
    1305                                         "Heritage Day"    : [  'lastFebruarySunday',  -2 ],
    1306                                         "Good Friday"     : [  'easter', -2 ],
    1307                                         "Easter Monday"   : [  'easter', 1 ],
    1308                                         "Victoria Day"    : [  'victoriaDay', 0 ],
    1309                                         "Canada Day"      : [  'canadaDay', 0 ],
    1310                                         "Discovery Day"   : [  'firstAugustMonday', 14 ],
    1311                                         "Labour Day"      : [  'firstSeptemberMonday', 0 ],
    1312                                         "Thanksgiving"    : [  'firstOctoberMonday', 7 ],
    1313                                         "Remembrance Day" : [ 11, 11 ],
    1314                                         "Christmas Day"   : [ 12, 25 ],
    1315                                         "Boxing Day"      : [ 12, 26 ]
    1316                                 },
    1317                         },
    1318                 }, // }}}
    1319                 'ru': { // {{{
    1320                         'PH': { // https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8_%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D0%B8
    1321                                 "1. Новогодние каникулы":     [ 1, 1 ],
    1322                                 "2. Новогодние каникулы":     [ 1, 2 ],
    1323                                 "3. Новогодние каникулы":     [ 1, 3 ],
    1324                                 "4. Новогодние каникулы":     [ 1, 4 ],
    1325                                 "5. Новогодние каникулы":     [ 1, 5 ],
    1326                                 "6. Новогодние каникулы":     [ 1, 6 ],
    1327                                 "Рождество Христово":         [ 1, 7 ],
    1328                                 "8. Новогодние каникулы":     [ 1, 8 ],
    1329                                 "День защитника Отечества":   [ 2, 23 ],
    1330                                 "Международный женский день": [ 3, 8 ],
    1331                                 "День Победы":                [ 5, 9 ],
    1332                                 "Праздник Весны и Труда":     [ 5, 1 ],
    1333                                 "День народного единства":    [ 11, 4 ],
    1334                                 "День России":                [ 6, 12 ],
    1335                         },
    1336                         'Tatarstan': { // https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8_%D0%A2%D0%B0%D1%82%D0%B0%D1%80%D1%81%D1%82%D0%B0%D0%BD%D0%B0
    1337                                 'PH': {
    1338                                         "1. Новогодние каникулы":                [ 1, 1 ],
    1339                                         "2. Новогодние каникулы":                [ 1, 2 ],
    1340                                         "3. Новогодние каникулы":                [ 1, 3 ],
    1341                                         "4. Новогодние каникулы":                [ 1, 4 ],
    1342                                         "5. Новогодние каникулы":                [ 1, 5 ],
    1343                                         "6. Новогодние каникулы":                [ 1, 6 ],
    1344                                         "Рождество Христово":                    [ 1, 7 ],
    1345                                         "8. Новогодние каникулы":                [ 1, 8 ],
    1346                                         "День защитника Отечества":              [ 2, 23 ],
    1347                                         "Международный женский день":            [ 3, 8 ],
    1348                                         "День Победы":                           [ 5, 9 ],
    1349                                         "Праздник Весны и Труда":                [ 5, 1 ],
    1350                                         "День народного единства":               [ 11, 4 ],
    1351                                         "День России":                           [ 6, 12 ],
    1352                                         // local
    1353                                         "Ураза-байрам":                          [ 7, 28 ],
    1354                                         "День Республики Татарстан":             [ 8, 30 ],
    1355                                         "Курбан-байрам":                         [ 10, 4 ],
    1356                                         "День Конституции Республики Татарстан": [ 11, 6 ],
    1357                                 },
    1358                         },
    1359                         'Bashkortostan': { // https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8_%D0%91%D0%B0%D1%88%D0%BA%D0%BE%D1%80%D1%82%D0%BE%D1%81%D1%82%D0%B0%D0%BD%D0%B0
    1360                                 'PH': {
    1361                                         "1. Новогодние каникулы":               [ 1, 1 ],
    1362                                         "2. Новогодние каникулы":           [ 1, 2 ],
    1363                                         "3. Новогодние каникулы":           [ 1, 3 ],
    1364                                         "4. Новогодние каникулы":           [ 1, 4 ],
    1365                                         "5. Новогодние каникулы":           [ 1, 5 ],
    1366                                         "6. Новогодние каникулы":           [ 1, 6 ],
    1367                                         "Рождество Христово":               [ 1, 7 ],
    1368                                         "8. Новогодние каникулы":           [ 1, 8 ],
    1369                                         "День защитника Отечества":         [ 2, 23 ],
    1370                                         "Международный женский день":       [ 3, 8 ],
    1371                                         "День Победы":                      [ 5, 9 ],
    1372                                         "Праздник Весны и Труда":           [ 5, 1 ],
    1373                                         "День народного единства":          [ 11, 4 ],
    1374                                         "День России":                      [ 6, 12 ],
    1375                                         // local
    1376                                         "Ураза-байрам":                     [ 7, 28 ],
    1377                                         "Курбан-байрам":                    [ 10, 4 ],
    1378                                         "День Республики Башкирии":         [ 10, 11 ],
    1379                                         "День Конституции Башкортостана":   [ 12, 24 ],
    1380                                 },
    1381                         },
    1382                         'Chuvashia': {
    1383                                 'PH': {
    1384                                         "1. Новогодние каникулы":           [ 1, 1 ],
    1385                                         "2. Новогодние каникулы":           [ 1, 2 ],
    1386                                         "3. Новогодние каникулы":           [ 1, 3 ],
    1387                                         "4. Новогодние каникулы":           [ 1, 4 ],
    1388                                         "5. Новогодние каникулы":           [ 1, 5 ],
    1389                                         "6. Новогодние каникулы":           [ 1, 6 ],
    1390                                         "Рождество Христово":               [ 1, 7 ],
    1391                                         "8. Новогодние каникулы":           [ 1, 8 ],
    1392                                         "День защитника Отечества":         [ 2, 23 ],
    1393                                         "Международный женский день":       [ 3, 8 ],
    1394                                         "День Победы":                      [ 5, 9 ],
    1395                                         "Праздник Весны и Труда":           [ 5, 1 ],
    1396                                         "День народного единства":          [ 11, 4 ],
    1397                                         "День России":                      [ 6, 12 ],
    1398                                         // local
    1399                                         "День Чувашской республики":        [ 6, 24 ],
    1400                                 },
    1401                         },
    1402                         'Sakha Republic': { // https://ru.wikipedia.org/wiki/%D0%AF%D0%BA%D1%83%D1%82%D0%B8%D1%8F#.D0.9F.D1.80.D0.B0.D0.B7.D0.B4.D0.BD.D0.B8.D0.BA.D0.B8_.D0.AF.D0.BA.D1.83.D1.82.D0.B8.D0.B8
    1403                                 'PH': {
    1404                                         "1. Новогодние каникулы":                 [ 1, 1 ],
    1405                                         "2. Новогодние каникулы":                 [ 1, 2 ],
    1406                                         "3. Новогодние каникулы":                 [ 1, 3 ],
    1407                                         "4. Новогодние каникулы":                 [ 1, 4 ],
    1408                                         "5. Новогодние каникулы":                 [ 1, 5 ],
    1409                                         "6. Новогодние каникулы":                 [ 1, 6 ],
    1410                                         "Рождество Христово":                     [ 1, 7 ],
    1411                                         "8. Новогодние каникулы":                 [ 1, 8 ],
    1412                                         "День защитника Отечества":               [ 2, 23 ],
    1413                                         "Международный женский день":             [ 3, 8 ],
    1414                                         "День Победы":                            [ 5, 9 ],
    1415                                         "Праздник Весны и Труда":                 [ 5, 1 ],
    1416                                         "День народного единства":                [ 11, 4 ],
    1417                                         "День России":                            [ 6, 12 ],
    1418                                         // local
    1419                                         "День Республики Саха":                   [ 4, 27 ],
    1420                                         "Ысыах":                                  [ 6, 23 ],
    1421                                         "День государственности Республики Саха": [ 9, 27 ],
    1422                                 },
    1423                         },
    1424                         'Republic of Kalmykia': { // https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8_%D0%B8_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%BD%D1%8B%D0%B5_%D0%B4%D0%B0%D1%82%D1%8B_%D0%9A%D0%B0%D0%BB%D0%BC%D1%8B%D0%BA%D0%B8%D0%B8
    1425                                 'PH': {
    1426                                         "1. Новогодние каникулы":                                            [ 1, 1 ],
    1427                                         "2. Новогодние каникулы":                                            [ 1, 2 ],
    1428                                         "3. Новогодние каникулы":                                            [ 1, 3 ],
    1429                                         "4. Новогодние каникулы":                                            [ 1, 4 ],
    1430                                         "5. Новогодние каникулы":                                            [ 1, 5 ],
    1431                                         "6. Новогодние каникулы":                                            [ 1, 6 ],
    1432                                         "Рождество Христово":                                                [ 1, 7 ],
    1433                                         "8. Новогодние каникулы":                                            [ 1, 8 ],
    1434                                         "День защитника Отечества":                                          [ 2, 23 ],
    1435                                         "Международный женский день":                                        [ 3, 8 ],
    1436                                         "День Победы":                                                       [ 5, 9 ],
    1437                                         "Праздник Весны и Труда":                                            [ 5, 1 ],
    1438                                         "День народного единства":                                           [ 11, 4 ],
    1439                                         "День России":                                                       [ 6, 12 ],
    1440                                         // local
    1441                                         "Цаган Сар":                                                         [ 1, 14 ],
    1442                                         "День принятия Степного Уложения (Конституции) Республики Калмыкия": [ 4, 5 ],
    1443                                         "День рождения Будды Шакьямун":                                                  [ 6, 6 ],
    1444                                         "Зул":                                                                                               [ 12, 15 ],
    1445                                         "День памяти жертв депортации калмыцкого народа":                    [ 12, 28 ],
    1446                                 },
    1447                         },
    1448                         'Buryatia': { // https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8_%D0%91%D1%83%D1%80%D1%8F%D1%82%D0%B8%D0%B8
    1449                                 'PH': {
    1450                                         "1. Новогодние каникулы":     [ 1, 1 ],
    1451                                         "2. Новогодние каникулы":     [ 1, 2 ],
    1452                                         "3. Новогодние каникулы":     [ 1, 3 ],
    1453                                         "4. Новогодние каникулы":     [ 1, 4 ],
    1454                                         "5. Новогодние каникулы":     [ 1, 5 ],
    1455                                         "6. Новогодние каникулы":     [ 1, 6 ],
    1456                                         "Рождество Христово":         [ 1, 7 ],
    1457                                         "8. Новогодние каникулы":     [ 1, 8 ],
    1458                                         "День защитника Отечества":   [ 2, 23 ],
    1459                                         "Международный женский день": [ 3, 8 ],
    1460                                         "День Победы":                [ 5, 9 ],
    1461                                         "Праздник Весны и Труда":     [ 5, 1 ],
    1462                                         "День народного единства":    [ 11, 4 ],
    1463                                         "День России":                [ 6, 12 ],
    1464                                         //
    1465                                         "Сагаалган":                  [ 1, 14 ],
    1466                                 },
    1467                         },
    1468                         'Republic of Karelia': { // https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8_%D0%A0%D0%B5%D1%81%D0%BF%D1%83%D0%B1%D0%BB%D0%B8%D0%BA%D0%B8_%D0%9A%D0%B0%D1%80%D0%B5%D0%BB%D0%B8%D1%8F
    1469                                 'PH': {
    1470                                         "1. Новогодние каникулы":                              [ 1, 1 ],
    1471                                         "2. Новогодние каникулы":                              [ 1, 2 ],
    1472                                         "3. Новогодние каникулы":                              [ 1, 3 ],
    1473                                         "4. Новогодние каникулы":                              [ 1, 4 ],
    1474                                         "5. Новогодние каникулы":                              [ 1, 5 ],
    1475                                         "6. Новогодние каникулы":                              [ 1, 6 ],
    1476                                         "Рождество Христово":                                  [ 1, 7 ],
    1477                                         "8. Новогодние каникулы":                              [ 1, 8 ],
    1478                                         "День защитника Отечества":                            [ 2, 23 ],
    1479                                         "Международный женский день":                          [ 3, 8 ],
    1480                                         "День Победы":                                         [ 5, 9 ],
    1481                                         "Праздник Весны и Труда":                              [ 5, 1 ],
    1482                                         "День народного единства":                             [ 11, 4 ],
    1483                                         "День России":                                         [ 6, 12 ],
    1484                                         // local
    1485                                         "День Республики Карелия":                             [ 6, 8 ],
    1486                                         "День освобождения Карелии от фашистских захватчиков": [ 9, 30 ],
    1487                                 },
    1488                         },
    1489                         'Удмуртская республика': {
    1490                                 'PH': {
    1491                                         "1. Новогодние каникулы":                       [ 1, 1 ],
    1492                                         "2. Новогодние каникулы":                       [ 1, 2 ],
    1493                                         "3. Новогодние каникулы":                       [ 1, 3 ],
    1494                                         "4. Новогодние каникулы":                       [ 1, 4 ],
    1495                                         "5. Новогодние каникулы":                       [ 1, 5 ],
    1496                                         "6. Новогодние каникулы":                       [ 1, 6 ],
    1497                                         "Рождество Христово":                           [ 1, 7 ],
    1498                                         "8. Новогодние каникулы":                       [ 1, 8 ],
    1499                                         "День защитника Отечества":                     [ 2, 23 ],
    1500                                         "Международный женский день":                   [ 3, 8 ],
    1501                                         "День Победы":                                  [ 5, 9 ],
    1502                                         "Праздник Весны и Труда":                       [ 5, 1 ],
    1503                                         "День народного единства":                      [ 11, 4 ],
    1504                                         "День России":                                  [ 6, 12 ],
    1505                                         // local
    1506                                         "День Государственности Удмуртской Республики": [ 5, 31 ],
    1507                                 },
    1508                         },
    1509                         'Adygea': {
    1510                                 'PH': {
    1511                                         "1. Новогодние каникулы":             [ 1, 1 ],
    1512                                         "2. Новогодние каникулы":             [ 1, 2 ],
    1513                                         "3. Новогодние каникулы":             [ 1, 3 ],
    1514                                         "4. Новогодние каникулы":             [ 1, 4 ],
    1515                                         "5. Новогодние каникулы":             [ 1, 5 ],
    1516                                         "6. Новогодние каникулы":             [ 1, 6 ],
    1517                                         "Рождество Христово":                 [ 1, 7 ],
    1518                                         "8. Новогодние каникулы":             [ 1, 8 ],
    1519                                         "День защитника Отечества":           [ 2, 23 ],
    1520                                         "Международный женский день":         [ 3, 8 ],
    1521                                         "День Победы":                        [ 5, 9 ],
    1522                                         "Праздник Весны и Труда":             [ 5, 1 ],
    1523                                         "День народного единства":            [ 11, 4 ],
    1524                                         "День России":                        [ 6, 12 ],
    1525                                         // local
    1526                                         "Ураза-байрам":                       [ 7, 28 ],
    1527                                         "Курбан-байрам":                      [ 10, 4 ],
    1528                                         "День образования Республики Адыгея": [ 10, 5 ],
    1529                                 },
    1530                         },
    1531                         'Republic of Dagestan': { // https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8_%D0%94%D0%B0%D0%B3%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B0
    1532                                 'PH': {
    1533                                         "1. Новогодние каникулы":               [ 1, 1 ],
    1534                                         "2. Новогодние каникулы":               [ 1, 2 ],
    1535                                         "3. Новогодние каникулы":               [ 1, 3 ],
    1536                                         "4. Новогодние каникулы":               [ 1, 4 ],
    1537                                         "5. Новогодние каникулы":               [ 1, 5 ],
    1538                                         "6. Новогодние каникулы":               [ 1, 6 ],
    1539                                         "Рождество Христово":                   [ 1, 7 ],
    1540                                         "8. Новогодние каникулы":               [ 1, 8 ],
    1541                                         "День защитника Отечества":             [ 2, 23 ],
    1542                                         "Международный женский день":           [ 3, 8 ],
    1543                                         "День Победы":                          [ 5, 9 ],
    1544                                         "Праздник Весны и Труда":               [ 5, 1 ],
    1545                                         "День народного единства":              [ 11, 4 ],
    1546                                         "День России":                          [ 6, 12 ],
    1547                                         // local
    1548                                         "День Конституции Республики Дагестан": [ 7, 26 ],
    1549                                         "Ураза-байрам":                         [ 7, 28 ],
    1550                                         "День единства народов Дагестана":      [ 9, 15 ],
    1551                                         "Курбан-байрам":                        [ 10, 4 ],
    1552                                 },
    1553                         },
    1554                         'Ingushetia': { // https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8_%D0%98%D0%BD%D0%B3%D1%83%D1%88%D0%B5%D1%82%D0%B8%D0%B8
    1555                                 'PH': {
    1556                                         "1. Новогодние каникулы":                [ 1, 1 ],
    1557                                         "2. Новогодние каникулы":                [ 1, 2 ],
    1558                                         "3. Новогодние каникулы":                [ 1, 3 ],
    1559                                         "4. Новогодние каникулы":                [ 1, 4 ],
    1560                                         "5. Новогодние каникулы":                [ 1, 5 ],
    1561                                         "6. Новогодние каникулы":                [ 1, 6 ],
    1562                                         "Рождество Христово":                    [ 1, 7 ],
    1563                                         "8. Новогодние каникулы":                [ 1, 8 ],
    1564                                         "День защитника Отечества":              [ 2, 23 ],
    1565                                         "Международный женский день":            [ 3, 8 ],
    1566                                         "День Победы":                           [ 5, 9 ],
    1567                                         "Праздник Весны и Труда":                [ 5, 1 ],
    1568                                         "День народного единства":               [ 11, 4 ],
    1569                                         "День России":                           [ 6, 12 ],
    1570                                         // local
    1571                                         "День образования Республики Ингушетия": [ 6, 4 ],
    1572                                         "Ураза-байрам":                          [ 7, 28 ],
    1573                                         "Курбан-байрам":                         [ 10, 4 ],
    1574                                 },
    1575                         },
    1576                         'Карачаево-Черкесская республика': {
    1577                                 'PH': {
    1578                                         "1. Новогодние каникулы":                [ 1, 1 ],
    1579                                         "2. Новогодние каникулы":                [ 1, 2 ],
    1580                                         "3. Новогодние каникулы":                [ 1, 3 ],
    1581                                         "4. Новогодние каникулы":                [ 1, 4 ],
    1582                                         "5. Новогодние каникулы":                [ 1, 5 ],
    1583                                         "6. Новогодние каникулы":                [ 1, 6 ],
    1584                                         "Рождество Христово":                    [ 1, 7 ],
    1585                                         "8. Новогодние каникулы":                [ 1, 8 ],
    1586                                         "День защитника Отечества":              [ 2, 23 ],
    1587                                         "Международный женский день":            [ 3, 8 ],
    1588                                         "День Победы":                           [ 5, 9 ],
    1589                                         "Праздник Весны и Труда":                [ 5, 1 ],
    1590                                         "День народного единства":               [ 11, 4 ],
    1591                                         "День России":                           [ 6, 12 ],
    1592                                         // local
    1593                                         "День возрождения карачаевского народа": [ 5, 3 ],
    1594                                         "Ураза-байрам":                          [ 7, 28 ],
    1595                                         "Курбан-байрам":                         [ 10, 4 ],
    1596                                 },
    1597                         },
    1598                         'Chechen Republic': { // https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B7%D0%B4%D0%BD%D0%B8%D0%BA%D0%B8_%D0%A7%D0%B5%D1%87%D0%BD%D0%B8
    1599                                 'PH': {
    1600                                         "1. Новогодние каникулы":           [ 1, 1 ],
    1601                                         "2. Новогодние каникулы":           [ 1, 2 ],
    1602                                         "3. Новогодние каникулы":           [ 1, 3 ],
    1603                                         "4. Новогодние каникулы":           [ 1, 4 ],
    1604                                         "5. Новогодние каникулы":           [ 1, 5 ],
    1605                                         "6. Новогодние каникулы":           [ 1, 6 ],
    1606                                         "Рождество Христово":               [ 1, 7 ],
    1607                                         "8. Новогодние каникулы":           [ 1, 8 ],
    1608                                         "День защитника Отечества":         [ 2, 23 ],
    1609                                         "Международный женский день":       [ 3, 8 ],
    1610                                         "День Победы":                      [ 5, 9 ],
    1611                                         "Праздник Весны и Труда":           [ 5, 1 ],
    1612                                         "День народного единства":          [ 11, 4 ],
    1613                                         "День России":                      [ 6, 12 ],
    1614                                         // local
    1615                                         "День мира в Чеченской Республике": [ 4, 16 ],
    1616                                         "Ураза-байрам":                     [ 7, 28 ],
    1617                                         "Курбан-байрам":                    [ 10, 4 ],
    1618                                 },
    1619                         },
    1620                         'Кабардино-Балкарская республика': {
    1621                                 'PH': {
    1622                                         "1. Новогодние каникулы":                                 [ 1, 1 ],
    1623                                         "2. Новогодние каникулы":                                 [ 1, 2 ],
    1624                                         "3. Новогодние каникулы":                                 [ 1, 3 ],
    1625                                         "4. Новогодние каникулы":                                 [ 1, 4 ],
    1626                                         "5. Новогодние каникулы":                                 [ 1, 5 ],
    1627                                         "6. Новогодние каникулы":                                 [ 1, 6 ],
    1628                                         "Рождество Христово":                                     [ 1, 7 ],
    1629                                         "8. Новогодние каникулы":                                 [ 1, 8 ],
    1630                                         "День защитника Отечества":                               [ 2, 23 ],
    1631                                         "Международный женский день":                             [ 3, 8 ],
    1632                                         "День Победы":                                            [ 5, 9 ],
    1633                                         "Праздник Весны и Труда":                                 [ 5, 1 ],
    1634                                         "День народного единства":                                [ 11, 4 ],
    1635                                         "День России":                                            [ 6, 12 ],
    1636                                         // local
    1637                                         "День возрождения балкарского народа":                    [ 3, 28 ],
    1638                                         "Черкесский день траура":                                 [ 5, 21 ],
    1639                                         "Ураза-байрам":                                           [ 7, 28 ],
    1640                                         "День государственности Кабардино-Балкарской Республики": [ 9, 1 ],
    1641                                         "Курбан-байрам":                                          [ 10, 4 ],
    1642                                 },
    1643                         },
    1644                         'Altai Republic': {
    1645                                 'PH': {
    1646                                         "1. Новогодние каникулы":           [ 1, 1 ],
    1647                                         "2. Новогодние каникулы":           [ 1, 2 ],
    1648                                         "3. Новогодние каникулы":           [ 1, 3 ],
    1649                                         "4. Новогодние каникулы":           [ 1, 4 ],
    1650                                         "5. Новогодние каникулы":           [ 1, 5 ],
    1651                                         "6. Новогодние каникулы":           [ 1, 6 ],
    1652                                         "Рождество Христово":               [ 1, 7 ],
    1653                                         "8. Новогодние каникулы":           [ 1, 8 ],
    1654                                         "День защитника Отечества":         [ 2, 23 ],
    1655                                         "Международный женский день":       [ 3, 8 ],
    1656                                         "День Победы":                      [ 5, 9 ],
    1657                                         "Праздник Весны и Труда":           [ 5, 1 ],
    1658                                         "День народного единства":          [ 11, 4 ],
    1659                                         "День России":                      [ 6, 12 ],
    1660                                         // local
    1661                                         "Чага-Байрам":                      [ 1, 14 ],
    1662                                 },
    1663                         },
    1664                         'Tuva': {
    1665                                 'PH': {
    1666                                         "1. Новогодние каникулы":           [ 1, 1 ],
    1667                                         "2. Новогодние каникулы":           [ 1, 2 ],
    1668                                         "3. Новогодние каникулы":           [ 1, 3 ],
    1669                                         "4. Новогодние каникулы":           [ 1, 4 ],
    1670                                         "5. Новогодние каникулы":           [ 1, 5 ],
    1671                                         "6. Новогодние каникулы":           [ 1, 6 ],
    1672                                         "Рождество Христово":               [ 1, 7 ],
    1673                                         "8. Новогодние каникулы":           [ 1, 8 ],
    1674                                         "День защитника Отечества":         [ 2, 23 ],
    1675                                         "Международный женский день":       [ 3, 8 ],
    1676                                         "День Победы":                      [ 5, 9 ],
    1677                                         "Праздник Весны и Труда":           [ 5, 1 ],
    1678                                         "День народного единства":          [ 11, 4 ],
    1679                                         "День России":                      [ 6, 12 ],
    1680                                         // local
    1681                                         "Народный праздник Шагаа":          [ 1, 14 ],
    1682                                         "День Республики Тыва":             [ 8, 15 ],
    1683                                 },
    1684                         },
    1685                         'Saratov Oblast': {
    1686                                 'PH': {
    1687                                         "1. Новогодние каникулы":           [ 1, 1 ],
    1688                                         "2. Новогодние каникулы":           [ 1, 2 ],
    1689                                         "3. Новогодние каникулы":           [ 1, 3 ],
    1690                                         "4. Новогодние каникулы":           [ 1, 4 ],
    1691                                         "5. Новогодние каникулы":           [ 1, 5 ],
    1692                                         "6. Новогодние каникулы":           [ 1, 6 ],
    1693                                         "Рождество Христово":               [ 1, 7 ],
    1694                                         "8. Новогодние каникулы":           [ 1, 8 ],
    1695                                         "День защитника Отечества":         [ 2, 23 ],
    1696                                         "Международный женский день":       [ 3, 8 ],
    1697                                         "День Победы":                      [ 5, 9 ],
    1698                                         "Праздник Весны и Труда":           [ 5, 1 ],
    1699                                         "День народного единства":          [ 11, 4 ],
    1700                                         "День России":                      [ 6, 12 ],
    1701                                         // local
    1702                                         "Радоница":                         [ 4, 29 ],
    1703                                 },
    1704                         },
    1705                         'Bryansk Oblast': {
    1706                                 'PH': {
    1707                                         "1. Новогодние каникулы":           [ 1, 1 ],
    1708                                         "2. Новогодние каникулы":           [ 1, 2 ],
    1709                                         "3. Новогодние каникулы":           [ 1, 3 ],
    1710                                         "4. Новогодние каникулы":           [ 1, 4 ],
    1711                                         "5. Новогодние каникулы":           [ 1, 5 ],
    1712                                         "6. Новогодние каникулы":           [ 1, 6 ],
    1713                                         "Рождество Христово":               [ 1, 7 ],
    1714                                         "8. Новогодние каникулы":           [ 1, 8 ],
    1715                                         "День защитника Отечества":         [ 2, 23 ],
    1716                                         "Международный женский день":       [ 3, 8 ],
    1717                                         "День Победы":                      [ 5, 9 ],
    1718                                         "Праздник Весны и Труда":           [ 5, 1 ],
    1719                                         "День народного единства":          [ 11, 4 ],
    1720                                         "День России":                      [ 6, 12 ],
    1721                                         // local
    1722                                         "Радоница":                         [ 4, 29 ],
    1723                                         "День освобождения города Брянска": [ 9, 17 ],
    1724                                 },
    1725                         },
    1726                         'Komi Republic': {
    1727                                 'PH': {
    1728                                         "1. Новогодние каникулы":     [ 1, 1 ],
    1729                                         "2. Новогодние каникулы":     [ 1, 2 ],
    1730                                         "3. Новогодние каникулы":     [ 1, 3 ],
    1731                                         "4. Новогодние каникулы":     [ 1, 4 ],
    1732                                         "5. Новогодние каникулы":     [ 1, 5 ],
    1733                                         "6. Новогодние каникулы":     [ 1, 6 ],
    1734                                         "Рождество Христово":         [ 1, 7 ],
    1735                                         "8. Новогодние каникулы":     [ 1, 8 ],
    1736                                         "День защитника Отечества":   [ 2, 23 ],
    1737                                         "Международный женский день": [ 3, 8 ],
    1738                                         "День Победы":                [ 5, 9 ],
    1739                                         "Праздник Весны и Труда":     [ 5, 1 ],
    1740                                         "День народного единства":    [ 11, 4 ],
    1741                                         "День России":                [ 6, 12 ],
    1742                                         // local
    1743                                         "День Республики Коми":       [ 8, 22 ],
    1744                                 },
    1745                         },
    1746                 }, // }}}
    1747                 'ua': { // {{{
    1748                         'PH': { // http://uk.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D1%82%D0%B0_%D1%82%D0%B0_%D0%BF%D0%B0%D0%BC%27%D1%8F%D1%82%D0%BD%D1%96_%D0%B4%D0%BD%D1%96_%D0%B2_%D0%A3%D0%BA%D1%80%D0%B0%D1%97%D0%BD%D1%96
    1749                                 "Новий рік"                 : [  1,  1 ],
    1750                                 "Різдво"                    : [  1,  7 ],
    1751                                 "Міжнародний жіночий день"  : [  3,  8 ],
    1752                                 "Великдень"                 : [ 'orthodox easter',  1 ],
    1753                                 "День Праці 1"              : [  5,  1 ],
    1754                                 "День Праці 2"              : [  5,  2 ],
    1755                                 "День Перемоги"             : [  5,  9 ],
    1756                                 "День Конституції України"  : [  6, 28 ],
    1757                                 "День Незалежності України" : [  8, 24 ],
    1758                         }
    1759                 }, // }}}
    1760                 'us': { // {{{
    1761                         'PH': { // https://en.wikipedia.org/wiki/Public_holidays_in_the_United_States
    1762                                 "New Year's Day"   : [ 1, 1 ],
    1763                                 "Memorial Day"     : [ "lastMayMonday", 0 ],
    1764                                 "Independence Day" : [ 7, 4 ],
    1765                                 "Labor Day"        : [ "firstSeptemberMonday", 0 ],
    1766                                 "Veterans Day"     : [ 11, 11 ],
    1767                                 "Thanksgiving"     : [ "firstNovemberThursday", 21 ],
    1768                                 "Christmas Day"    : [ 12, 25 ]
    1769                         },
    1770                         'Alabama': {
    1771                                 'PH': { // http://www.archives.alabama.gov/intro/holidays.html
    1772                                         "New Year's Day"                              : [ 1, 1 ],
    1773                                         "Robert E. Lee/Martin Luther King Birthday"   : [ "firstJanuaryMonday", 14 ],
    1774                                         "George Washington/Thomas Jefferson Birthday" : [ "firstFebruaryMonday", 14 ],
    1775                                         "Memorial Day"                                : [ "lastMayMonday", 0 ],
    1776                                         "Independence Day"                            : [ 7, 4 ],
    1777                                         "Labor Day"                                   : [ "firstSeptemberMonday", 0 ],
    1778                                         "Columbus Day"                                : [ "firstOctoberMonday", 7 ],
    1779                                         "Veterans Day"                                : [ 11, 11 ],
    1780                                         "Thanksgiving"                                : [ "firstNovemberThursday", 21 ],
    1781                                         "Christmas Day"                               : [ 12, 25 ],
    1782                                         "Confederate Memorial Day"                    : [ "firstAprilMonday", 21 ],
    1783                                         "Jefferson Davis' Birthday"                   : [ "firstJuneMonday", 0 ]
    1784                                 }
    1785                         },
    1786                         'Alaska': {
    1787                                 'PH': {
    1788                                         "New Year's Day"              : [ 1, 1 ],
    1789                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1790                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    1791                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1792                                         "Independence Day"            : [ 7, 4 ],
    1793                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1794                                         "Veterans Day"                : [ 11, 11 ],
    1795                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1796                                         "Christmas Day"               : [ 12, 25 ],
    1797                                         "Seward's Day"                : [ "lastMarchMonday", 0 ],
    1798                                         "Alaska Day"                  : [ 10, 18 ]
    1799                                 }
    1800                         },
    1801                         'Arizona': {
    1802                                 'PH': {
    1803                                         "New Year's Day"                              : [ 1, 1 ],
    1804                                         "Dr. Martin Luther King Jr./Civil Rights Day" : [ "firstJanuaryMonday", 14 ],
    1805                                         "Washington's Birthday"                       : [ "firstFebruaryMonday", 14 ],
    1806                                         "Memorial Day"                                : [ "lastMayMonday", 0 ],
    1807                                         "Independence Day"                            : [ 7, 4 ],
    1808                                         "Labor Day"                                   : [ "firstSeptemberMonday", 0 ],
    1809                                         "Columbus Day"                                : [ "firstOctoberMonday", 7 ],
    1810                                         "Veterans Day"                                : [ 11, 11 ],
    1811                                         "Thanksgiving"                                : [ "firstNovemberThursday", 21 ],
    1812                                         "Christmas Day"                               : [ 12, 25 ]
    1813                                 }
    1814                         },
    1815                         'Arkansas': {
    1816                                 'PH': {
    1817                                         "New Year's Day"                                           : [ 1, 1 ],
    1818                                         "Dr. Martin Luther King Jr. and Robert E. Lee's Birthdays" : [ "firstJanuaryMonday", 14 ],
    1819                                         "George Washington's Birthday and Daisy Gatson Bates Day"  : [ "firstFebruaryMonday", 14 ],
    1820                                         "Memorial Day"                                             : [ "lastMayMonday", 0 ],
    1821                                         "Independence Day"                                         : [ 7, 4 ],
    1822                                         "Labor Day"                                                : [ "firstSeptemberMonday", 0 ],
    1823                                         "Columbus Day"                                             : [ "firstOctoberMonday", 7 ],
    1824                                         "Veterans Day"                                             : [ 11, 11 ],
    1825                                         "Thanksgiving"                                             : [ "firstNovemberThursday", 21 ],
    1826                                         "Christmas Eve"                                            : [ 12, 24 ],
    1827                                         "Christmas Day"                                            : [ 12, 25 ]
    1828                                 }
    1829                         },
    1830                         'California': {
    1831                                 'PH': {
    1832                                         "New Year's Day"              : [ 1, 1 ],
    1833                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1834                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    1835                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1836                                         "Independence Day"            : [ 7, 4 ],
    1837                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1838                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    1839                                         "Veterans Day"                : [ 11, 11 ],
    1840                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1841                                         "Christmas Day"               : [ 12, 25 ],
    1842                                         "César Chávez Day"            : [ 3, 31 ]
    1843                                 }
    1844                         },
    1845                         'Colorado': {
    1846                                 'PH': {
    1847                                         "New Year's Day"              : [ 1, 1 ],
    1848                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1849                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    1850                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1851                                         "Independence Day"            : [ 7, 4 ],
    1852                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1853                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    1854                                         "Veterans Day"                : [ 11, 11 ],
    1855                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1856                                         "Christmas Day"               : [ 12, 25 ]
    1857                                 }
    1858                         },
    1859                         'Connecticut': {
    1860                                 'PH': {
    1861                                         "New Year's Day"              : [ 1, 1 ],
    1862                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1863                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    1864                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1865                                         "Independence Day"            : [ 7, 4 ],
    1866                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1867                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    1868                                         "Veterans Day"                : [ 11, 11 ],
    1869                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1870                                         "Christmas Day"               : [ 12, 25 ],
    1871                                         "Lincoln's Birthday"          : [ 2, 12 ],
    1872                                         "Good Friday"                 : [ "easter", -2 ]
    1873                                 }
    1874                         },
    1875                         'Delaware': {
    1876                                 'PH': {
    1877                                         "New Year's Day"              : [ 1, 1 ],
    1878                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1879                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    1880                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1881                                         "Independence Day"            : [ 7, 4 ],
    1882                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1883                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    1884                                         "Veterans Day"                : [ 11, 11 ],
    1885                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1886                                         "Day After Thanksgiving"      : [ "firstNovemberThursday", 22 ],
    1887                                         "Christmas Day"               : [ 12, 25 ],
    1888                                         "Good Friday"                 : [ "easter", -2 ]
    1889                                 }
    1890                         },
    1891                         'District of Columbia': {
    1892                                 'PH': {
    1893                                         "New Year's Day"              : [ 1, 1 ],
    1894                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1895                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    1896                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1897                                         "Independence Day"            : [ 7, 4 ],
    1898                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1899                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    1900                                         "Veterans Day"                : [ 11, 11 ],
    1901                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1902                                         "Christmas Day"               : [ 12, 25 ],
    1903                                         "Emancipation Day"            : [ 4, 16 ]
    1904                                 }
    1905                         },
    1906                         'Florida': {
    1907                                 'PH': { // http://www.leg.state.fl.us/Statutes/index.cfm?App_mode=Display_Statute&Search_String=&URL=0100-0199/0110/Sections/0110.117.html
    1908                                         "New Year's Day"              : [ 1, 1 ],
    1909                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1910                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1911                                         "Independence Day"            : [ 7, 4 ],
    1912                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1913                                         "Veterans Day"                : [ 11, 11 ],
    1914                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1915                                         "Friday after Thanksgiving"   : [ "firstNovemberThursday", 22 ],
    1916                                         "Christmas Day"               : [ 12, 25 ]
    1917                                 }
    1918                         },
    1919                         'Georgia': {
    1920                                 'PH': {
    1921                                         "New Year's Day"              : [ 1, 1 ],
    1922                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1923                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1924                                         "Independence Day"            : [ 7, 4 ],
    1925                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1926                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    1927                                         "Veterans Day"                : [ 11, 11 ],
    1928                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1929                                         "Robert E. Lee's Birthday"    : [ "firstNovemberThursday", 22 ],
    1930                                         "Washington's Birthday"       : [ 12, 24 ],
    1931                                         "Christmas Day"               : [ 12, 25 ],
    1932                                         "Confederate Memorial Day"    : [ "lastAprilMonday", 0 ]
    1933                                 }
    1934                         },
    1935                         'Guam': {
    1936                                 'PH': {
    1937                                         "New Year's Day"              : [ 1, 1 ],
    1938                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1939                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    1940                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1941                                         "Independence Day"            : [ 7, 4 ],
    1942                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1943                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    1944                                         "Veterans Day"                : [ 11, 11 ],
    1945                                         "Guam Discovery Day"          : [ 3, 5 ],
    1946                                         "Good Friday"                 : [ "easter", -2 ],
    1947                                         "Liberation Day"              : [ 7, 21 ],
    1948                                         "All Souls' Day"              : [ 11, 2 ],
    1949                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1950                                         "Lady of Camarin Day"         : [ 12, 8 ],
    1951                                         "Christmas Day"               : [ 12, 25 ],
    1952                                 }
    1953                         },
    1954                         'Hawaii': {
    1955                                 'PH': {
    1956                                         "New Year's Day"                      : [ 1, 1 ],
    1957                                         "Martin Luther King, Jr. Day"         : [ "firstJanuaryMonday", 14 ],
    1958                                         "Washington's Birthday"               : [ "firstFebruaryMonday", 14 ],
    1959                                         "Memorial Day"                        : [ "lastMayMonday", 0 ],
    1960                                         "Independence Day"                    : [ 7, 4 ],
    1961                                         "Labor Day"                           : [ "firstSeptemberMonday", 0 ],
    1962                                         "Veterans Day"                        : [ 11, 11 ],
    1963                                         "Thanksgiving"                        : [ "firstNovemberThursday", 21 ],
    1964                                         "Christmas Day"                       : [ 12, 25 ],
    1965                                         "Prince Jonah Kuhio Kalanianaole Day" : [ 3, 26 ],
    1966                                         "Kamehameha Day"                      : [ 6, 11 ],
    1967                                         "Statehood Day"                       : [ "firstAugustFriday", 14 ],
    1968                                         "Election Day"                        : [ "firstNovemberMonday", 1 ]
    1969                                 }
    1970                         },
    1971                         'Idaho': {
    1972                                 'PH': {
    1973                                         "New Year's Day"                                 : [ 1, 1 ],
    1974                                         "Martin Luther King, Jr.-Idaho Human Rights Day" : [ "firstJanuaryMonday", 14 ],
    1975                                         "Washington's Birthday"                          : [ "firstFebruaryMonday", 14 ],
    1976                                         "Memorial Day"                                   : [ "lastMayMonday", 0 ],
    1977                                         "Independence Day"                               : [ 7, 4 ],
    1978                                         "Labor Day"                                      : [ "firstSeptemberMonday", 0 ],
    1979                                         "Columbus Day"                                   : [ "firstOctoberMonday", 7 ],
    1980                                         "Veterans Day"                                   : [ 11, 11 ],
    1981                                         "Thanksgiving"                                   : [ "firstNovemberThursday", 21 ],
    1982                                         "Christmas Day"                                  : [ 12, 25 ]
    1983                                 }
    1984                         },
    1985                         'Illinois': {
    1986                                 'PH': {
    1987                                         "New Year's Day"              : [ 1, 1 ],
    1988                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    1989                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    1990                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    1991                                         "Independence Day"            : [ 7, 4 ],
    1992                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    1993                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    1994                                         "Veterans Day"                : [ 11, 11 ],
    1995                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    1996                                         "Christmas Day"               : [ 12, 25 ],
    1997                                         "Lincoln's Birthday"          : [ 2, 12 ],
    1998                                         "Casimir Pulaski Day"         : [ "firstMarchMonday", 0 ],
    1999                                         "Election Day"                : [ "firstNovemberMonday", 1 ]
    2000                                 }
    2001                         },
    2002                         'Indiana': {
    2003                                 'PH': {
    2004                                         "New Year's Day"              : [ 1, 1 ],
    2005                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2006                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2007                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2008                                         "Independence Day"            : [ 7, 4 ],
    2009                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2010                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2011                                         "Veterans Day"                : [ 11, 11 ],
    2012                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2013                                         "Lincoln's Birthday"          : [ "firstNovemberThursday", 22 ],
    2014                                         "Christmas Day"               : [ 12, 25 ],
    2015                                         "Good Friday"                 : [ "easter", -2 ],
    2016                                         "Primary Election Day"        : [ "firstMayMonday", 1 ],
    2017                                         "Election Day"                : [ "firstNovemberMonday", 1 ]
    2018                                 }
    2019                         },
    2020                         'Iowa': {
    2021                                 'PH': {
    2022                                         "New Year's Day"              : [ 1, 1 ],
    2023                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2024                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2025                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2026                                         "Independence Day"            : [ 7, 4 ],
    2027                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2028                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2029                                         "Veterans Day"                : [ 11, 11 ],
    2030                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2031                                         "Christmas Day"               : [ 12, 25 ],
    2032                                         "Lincoln's Birthday"          : [ 2, 12 ]
    2033                                 }
    2034                         },
    2035                         'Kansas': {
    2036                                 'PH': {
    2037                                         "New Year's Day"              : [ 1, 1 ],
    2038                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2039                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2040                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2041                                         "Independence Day"            : [ 7, 4 ],
    2042                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2043                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2044                                         "Veterans Day"                : [ 11, 11 ],
    2045                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2046                                         "Christmas Day"               : [ 12, 25 ]
    2047                                 }
    2048                         },
    2049                         'Kentucky': {
    2050                                 'PH': {
    2051                                         "New Year's Day"              : [ 1, 1 ],
    2052                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2053                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2054                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2055                                         "Independence Day"            : [ 7, 4 ],
    2056                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2057                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2058                                         "Veterans Day"                : [ 11, 11 ],
    2059                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2060                                         "Christmas Eve"               : [ 12, 24 ],
    2061                                         "Christmas Day"               : [ 12, 25 ],
    2062                                         "New Year's Eve"              : [ 12, 31 ],
    2063                                         "Good Friday"                 : [ "easter", -2 ]
    2064                                 }
    2065                         },
    2066                         'Louisiana': {
    2067                                 'PH': {
    2068                                         "New Year's Day"              : [ 1, 1 ],
    2069                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2070                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2071                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2072                                         "Independence Day"            : [ 7, 4 ],
    2073                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2074                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2075                                         "Veterans Day"                : [ 11, 11 ],
    2076                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2077                                         "Christmas Day"               : [ 12, 25 ],
    2078                                         "Mardi Gras"                  : [ "easter", -47 ],
    2079                                         "Good Friday"                 : [ "easter", -2 ],
    2080                                         "Election Day"                : [ "firstNovemberMonday", 1 ]
    2081                                 }
    2082                         },
    2083                         'Maine': {
    2084                                 'PH': {
    2085                                         "New Year's Day"              : [ 1, 1 ],
    2086                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2087                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2088                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2089                                         "Independence Day"            : [ 7, 4 ],
    2090                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2091                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2092                                         "Veterans Day"                : [ 11, 11 ],
    2093                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2094                                         "Christmas Day"               : [ 12, 25 ],
    2095                                         "Patriots' Day"               : [ "firstAprilMonday", 14 ]
    2096                                 }
    2097                         },
    2098                         'Maryland': {
    2099                                 'PH': {
    2100                                         "New Year's Day"               : [ 1, 1 ],
    2101                                         "Martin Luther King, Jr. Day"  : [ "firstJanuaryMonday", 14 ],
    2102                                         "Washington's Birthday"        : [ "firstFebruaryMonday", 14 ],
    2103                                         "Memorial Day"                 : [ "lastMayMonday", 0 ],
    2104                                         "Independence Day"             : [ 7, 4 ],
    2105                                         "Labor Day"                    : [ "firstSeptemberMonday", 0 ],
    2106                                         "Columbus Day"                 : [ "firstOctoberMonday", 7 ],
    2107                                         "Veterans Day"                 : [ 11, 11 ],
    2108                                         "Thanksgiving"                 : [ "firstNovemberThursday", 21 ],
    2109                                         "Native American Heritage Day" : [ "firstNovemberThursday", 22 ],
    2110                                         "Christmas Day"                : [ 12, 25 ]
    2111                                 }
    2112                         },
    2113                         'Massachusetts': {
    2114                                 'PH': {
    2115                                         "New Year's Day"              : [ 1, 1 ],
    2116                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2117                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2118                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2119                                         "Independence Day"            : [ 7, 4 ],
    2120                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2121                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2122                                         "Veterans Day"                : [ 11, 11 ],
    2123                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2124                                         "Christmas Day"               : [ 12, 25 ],
    2125                                         "Patriots' Day"               : [ "firstAprilMonday", 14 ]
    2126                                 }
    2127                         },
    2128                         'Michigan': {
    2129                                 'PH': {
    2130                                         "New Year's Day"              : [ 1, 1 ],
    2131                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2132                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2133                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2134                                         "Independence Day"            : [ 7, 4 ],
    2135                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2136                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2137                                         "Veterans Day"                : [ 11, 11 ],
    2138                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2139                                         "Christmas Eve"               : [ 12, 24 ],
    2140                                         "Christmas Day"               : [ 12, 25 ],
    2141                                         "New Year's Eve"              : [ 12, 31 ]
    2142                                 }
    2143                         },
    2144                         'Minnesota': {
    2145                                 'PH': {
    2146                                         "New Year's Day"              : [ 1, 1 ],
    2147                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2148                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2149                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2150                                         "Independence Day"            : [ 7, 4 ],
    2151                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2152                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2153                                         "Veterans Day"                : [ 11, 11 ],
    2154                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2155                                         "Christmas Day"               : [ 12, 25 ]
    2156                                 }
    2157                         },
    2158                         'Mississippi': {
    2159                                 'PH': {
    2160                                         "New Year's Day"                                     : [ 1, 1 ],
    2161                                         "Martin Luther King's and Robert E. Lee's Birthdays" : [ "firstJanuaryMonday", 14 ],
    2162                                         "Washington's Birthday"                              : [ "firstFebruaryMonday", 14 ],
    2163                                         "Memorial Day"                                       : [ "lastMayMonday", 0 ],
    2164                                         "Independence Day"                                   : [ 7, 4 ],
    2165                                         "Labor Day"                                          : [ "firstSeptemberMonday", 0 ],
    2166                                         "Columbus Day"                                       : [ "firstOctoberMonday", 7 ],
    2167                                         "Veterans Day"                                       : [ 11, 11 ],
    2168                                         "Thanksgiving"                                       : [ "firstNovemberThursday", 21 ],
    2169                                         "Christmas Day"                                      : [ 12, 25 ],
    2170                                         "Confederate Memorial Day"                           : [ "lastAprilMonday", 0 ]
    2171                                 }
    2172                         },
    2173                         'Missouri': {
    2174                                 'PH': {
    2175                                         "New Year's Day"              : [ 1, 1 ],
    2176                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2177                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2178                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2179                                         "Independence Day"            : [ 7, 4 ],
    2180                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2181                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2182                                         "Veterans Day"                : [ 11, 11 ],
    2183                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2184                                         "Christmas Day"               : [ 12, 25 ],
    2185                                         "Truman Day"                  : [ 5, 8 ]
    2186                                 }
    2187                         },
    2188                         'Montana': {
    2189                                 'PH': {
    2190                                         "New Year's Day"              : [ 1, 1 ],
    2191                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2192                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2193                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2194                                         "Independence Day"            : [ 7, 4 ],
    2195                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2196                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2197                                         "Veterans Day"                : [ 11, 11 ],
    2198                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2199                                         "Christmas Day"               : [ 12, 25 ],
    2200                                         "Election Day"                : [ "firstNovemberMonday", 1 ],
    2201                                         "Christmas Eve"               : [ 12, 24 ],
    2202                                         "New Year's Eve"              : [ 12, 31 ]
    2203                                 }
    2204                         },
    2205                         'Nebraska': {
    2206                                 'PH': {
    2207                                         "New Year's Day"              : [ 1, 1 ],
    2208                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2209                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2210                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2211                                         "Independence Day"            : [ 7, 4 ],
    2212                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2213                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2214                                         "Veterans Day"                : [ 11, 11 ],
    2215                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2216                                         "Christmas Day"               : [ 12, 25 ],
    2217                                         "Arbor Day"                   : [ "lastAprilFriday", 0 ]
    2218                                 }
    2219                         },
    2220                         'Nevada': {
    2221                                 'PH': {
    2222                                         "New Year's Day"              : [ 1, 1 ],
    2223                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2224                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2225                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2226                                         "Independence Day"            : [ 7, 4 ],
    2227                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2228                                         "Veterans Day"                : [ 11, 11 ],
    2229                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2230                                         "Christmas Day"               : [ 12, 25 ],
    2231                                         "Nevada Day"                  : [ "lastOctoberFriday", 0 ],
    2232                                         "Family Day"                  : [ "firstNovemberThursday", 22 ]
    2233                                 }
    2234                         },
    2235                         'New Hampshire': {
    2236                                 'PH': {
    2237                                         "New Year's Day"                           : [ 1, 1 ],
    2238                                         "Martin Luther King, Jr. Civil Rights Day" : [ "firstJanuaryMonday", 14 ],
    2239                                         "Washington's Birthday"                    : [ "firstFebruaryMonday", 14 ],
    2240                                         "Memorial Day"                             : [ "lastMayMonday", 0 ],
    2241                                         "Independence Day"                         : [ 7, 4 ],
    2242                                         "Labor Day"                                : [ "firstSeptemberMonday", 0 ],
    2243                                         "Columbus Day"                             : [ "firstOctoberMonday", 7 ],
    2244                                         "Veterans Day"                             : [ 11, 11 ],
    2245                                         "Thanksgiving"                             : [ "firstNovemberThursday", 21 ],
    2246                                         "Day after Thanksgiving"                   : [ "firstNovemberThursday", 22 ],
    2247                                         "Christmas Day"                            : [ 12, 25 ],
    2248                                         "Election Day"                             : [ "firstNovemberMonday", 1 ]
    2249                                 }
    2250                         },
    2251                         'New Jersey': {
    2252                                 'PH': {
    2253                                         "New Year's Day"              : [ 1, 1 ],
    2254                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2255                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2256                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2257                                         "Independence Day"            : [ 7, 4 ],
    2258                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2259                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2260                                         "Veterans Day"                : [ 11, 11 ],
    2261                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2262                                         "Christmas Day"               : [ 12, 25 ],
    2263                                         "Lincoln's Birthday"          : [ 2, 12 ],
    2264                                         "Good Friday"                 : [ "easter", -2 ],
    2265                                         "Election Day"                : [ "firstNovemberMonday", 1 ]
    2266                                 }
    2267                         },
    2268                         'New Mexico': {
    2269                                 'PH': {
    2270                                         "New Year's Day"              : [ 1, 1 ],
    2271                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2272                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2273                                         "Independence Day"            : [ 7, 4 ],
    2274                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2275                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2276                                         "Veterans Day"                : [ 11, 11 ],
    2277                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2278                                         "Day after Thanksgiving"      : [ "firstNovemberThursday", 22 ],
    2279                                         "Christmas Day"               : [ 12, 25 ]
    2280                                 }
    2281                         },
    2282                         'New York': {
    2283                                 'PH': {
    2284                                         "New Year's Day"              : [ 1, 1 ],
    2285                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2286                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2287                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2288                                         "Independence Day"            : [ 7, 4 ],
    2289                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2290                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2291                                         "Veterans Day"                : [ 11, 11 ],
    2292                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2293                                         "Christmas Day"               : [ 12, 25 ],
    2294                                         "Lincoln's Birthday"          : [ 2, 12 ],
    2295                                         "Election Day"                : [ "firstNovemberMonday", 1 ]
    2296                                 }
    2297                         },
    2298                         'North Carolina': {
    2299                                 'PH': {
    2300                                         "New Year's Day"              : [ 1, 1 ],
    2301                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2302                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2303                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2304                                         "Independence Day"            : [ 7, 4 ],
    2305                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2306                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2307                                         "Veterans Day"                : [ 11, 11 ],
    2308                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2309                                         "Day after Thanksgiving"      : [ "firstNovemberThursday", 22 ],
    2310                                         "Christmas Eve"               : [ 12, 24 ],
    2311                                         "Christmas Day"               : [ 12, 25 ],
    2312                                         "Day after Christmas"         : [ 12, 26 ],
    2313                                         "Good Friday"                 : [ "easter", -2 ]
    2314                                 }
    2315                         },
    2316                         'North Dakota': {
    2317                                 'PH': {
    2318                                         "New Year's Day"              : [ 1, 1 ],
    2319                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2320                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2321                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2322                                         "Independence Day"            : [ 7, 4 ],
    2323                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2324                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2325                                         "Veterans Day"                : [ 11, 11 ],
    2326                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2327                                         "Christmas Day"               : [ 12, 25 ]
    2328                                 }
    2329                         },
    2330                         'Ohio': {
    2331                                 'PH': {
    2332                                         "New Year's Day"              : [ 1, 1 ],
    2333                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2334                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2335                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2336                                         "Independence Day"            : [ 7, 4 ],
    2337                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2338                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2339                                         "Veterans Day"                : [ 11, 11 ],
    2340                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2341                                         "Christmas Day"               : [ 12, 25 ]
    2342                                 }
    2343                         },
    2344                         'Oklahoma': {
    2345                                 'PH': {
    2346                                         "New Year's Day"              : [ 1, 1 ],
    2347                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2348                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2349                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2350                                         "Independence Day"            : [ 7, 4 ],
    2351                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2352                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2353                                         "Veterans Day"                : [ 11, 11 ],
    2354                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2355                                         "Day after Thanksgiving"      : [ "firstNovemberThursday", 22 ],
    2356                                         "Christmas Day"               : [ 12, 25 ]
    2357                                 }
    2358                         },
    2359                         'Oregon': {
    2360                                 'PH': {
    2361                                         "New Year's Day"              : [ 1, 1 ],
    2362                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2363                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2364                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2365                                         "Independence Day"            : [ 7, 4 ],
    2366                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2367                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2368                                         "Veterans Day"                : [ 11, 11 ],
    2369                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2370                                         "Christmas Day"               : [ 12, 25 ]
    2371                                 }
    2372                         },
    2373                         'Pennsylvania': {
    2374                                 'PH': {
    2375                                         "New Year's Day"              : [ 1, 1 ],
    2376                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2377                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2378                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2379                                         "Independence Day"            : [ 7, 4 ],
    2380                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2381                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2382                                         "Veterans Day"                : [ 11, 11 ],
    2383                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2384                                         "Christmas Day"               : [ 12, 25 ],
    2385                                         "Flag Day"                    : [ 6, 14 ]
    2386                                 }
    2387                         },
    2388                         'Puerto Rico': {
    2389                                 'PH': {
    2390                                         "Día de Año Nuevo"                         : [ 1, 1 ],
    2391                                         "Día de Reyes"                             : [ 1, 6 ],
    2392                                         "Natalicio de Eugenio María de Hostos"     : [ "firstJanuaryMonday", 7 ],
    2393                                         "Natalicio de Martin Luther King, Jr."     : [ "firstJanuaryMonday", 14 ],
    2394                                         "Día de los Presidentes"                   : [ "firstFebruaryMonday", 14 ],
    2395                                         "Día de la Abolición de Esclavitud"        : [ 3, 22 ],
    2396                                         "Viernes Santo"                            : [ "easter", -2 ],
    2397                                         "Natalicio de José de Diego"               : [ "firstAprilMonday", 14 ],
    2398                                         "Recordación de los Muertos de la Guerra"  : [ "lastMayMonday", 0 ],
    2399                                         "Día de la Independencia"                  : [ 7, 4 ],
    2400                                         "Constitución de Puerto Rico"              : [ 7, 25 ],
    2401                                         "Natalicio de Dr. José Celso Barbosa"      : [ 7, 27 ],
    2402                                         "Día del Trabajo"                          : [ "firstSeptemberMonday", 0 ],
    2403                                         "Día de la Raza Descubrimiento de América" : [ "firstOctoberMonday", 7 ],
    2404                                         "Día del Veterano"                         : [ 11, 11 ],
    2405                                         "Día del Descubrimiento de Puerto Rico"    : [ 11, 19 ],
    2406                                         "Día de Acción de Gracias"                 : [ "firstNovemberThursday", 21 ],
    2407                                         "Noche Buena"                              : [ 12, 24 ],
    2408                                         "Día de Navidad"                           : [ 12, 25 ]
    2409                                 }
    2410                         },
    2411                         'Rhode Island': {
    2412                                 'PH': {
    2413                                         "New Year's Day"              : [ 1, 1 ],
    2414                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2415                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2416                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2417                                         "Independence Day"            : [ 7, 4 ],
    2418                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2419                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2420                                         "Veterans Day"                : [ 11, 11 ],
    2421                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2422                                         "Christmas Day"               : [ 12, 25 ],
    2423                                         "Victory Day"                 : [ "firstAugustMonday", 7 ]
    2424                                 }
    2425                         },
    2426                         'South Carolina': {
    2427                                 'PH': {
    2428                                         "New Year's Day"              : [ 1, 1 ],
    2429                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2430                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2431                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2432                                         "Independence Day"            : [ 7, 4 ],
    2433                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2434                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2435                                         "Veterans Day"                : [ 11, 11 ],
    2436                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2437                                         "Christmas Day"               : [ 12, 25 ],
    2438                                         "Confederate Memorial Day"    : [ 5, 10 ]
    2439                                 }
    2440                         },
    2441                         'South Dakota': {
    2442                                 'PH': {
    2443                                         "New Year's Day"              : [ 1, 1 ],
    2444                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2445                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2446                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2447                                         "Independence Day"            : [ 7, 4 ],
    2448                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2449                                         "Native American Day"         : [ "firstOctoberMonday", 7 ],
    2450                                         "Veterans Day"                : [ 11, 11 ],
    2451                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2452                                         "Christmas Day"               : [ 12, 25 ]
    2453                                 }
    2454                         },
    2455                         'Tennessee': {
    2456                                 'PH': {
    2457                                         "New Year's Day"              : [ 1, 1 ],
    2458                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2459                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2460                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2461                                         "Independence Day"            : [ 7, 4 ],
    2462                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2463                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2464                                         "Veterans Day"                : [ 11, 11 ],
    2465                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2466                                         "Christmas Eve"               : [ 12, 24 ],
    2467                                         "Christmas Day"               : [ 12, 25 ],
    2468                                         "Good Friday"                 : [ "easter", -2 ]
    2469                                 }
    2470                         },
    2471                         'Texas': {
    2472                                 'PH': {
    2473                                         "New Year's Day"              : [ 1, 1 ],
    2474                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2475                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2476                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2477                                         "Independence Day"            : [ 7, 4 ],
    2478                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2479                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2480                                         "Veterans Day"                : [ 11, 11 ],
    2481                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2482                                         "Friday after Thanksgiving"   : [ "firstNovemberThursday", 22 ],
    2483                                         "Christmas Eve"               : [ 12, 24 ],
    2484                                         "Christmas Day"               : [ 12, 25 ],
    2485                                         "Day after Christmas"         : [ 12, 26 ]
    2486                                 }
    2487                         },
    2488                         'United States Virgin Islands': {
    2489                                 'PH': {
    2490                                         "New Year's Day"                            : [ 1, 1 ],
    2491                                         "Martin Luther King, Jr. Day"               : [ "firstJanuaryMonday", 14 ],
    2492                                         "Washington's Birthday"                     : [ "firstFebruaryMonday", 14 ],
    2493                                         "Memorial Day"                              : [ "lastMayMonday", 0 ],
    2494                                         "Independence Day"                          : [ 7, 4 ],
    2495                                         "Labor Day"                                 : [ "firstSeptemberMonday", 0 ],
    2496                                         "Virgin Islands-Puerto Rico Friendship Day" : [ "firstOctoberMonday", 7 ],
    2497                                         "Veterans Day"                              : [ 11, 11 ],
    2498                                         "Thanksgiving"                              : [ "firstNovemberThursday", 21 ],
    2499                                         "Christmas Day"                             : [ 12, 25 ],
    2500                                         "Three Kings Day"                           : [ 1, 6 ],
    2501                                         "Transfer Day"                              : [ 3, 31 ],
    2502                                         "Holy Thursday"                             : [ "easter", -3 ],
    2503                                         "Good Friday"                               : [ "easter", -2 ],
    2504                                         "Easter Monday"                             : [ "easter", 1 ],
    2505                                         "Emancipation Day"                          : [ 7, 3 ],
    2506                                         "Hurricane Supplication Day"                : [ "firstJulyMonday", 21 ],
    2507                                         "Hurricane Thanksgiving"                    : [ 10, 25 ],
    2508                                         "Liberty Day"                               : [ 11, 1 ],
    2509                                         "Christmas Second Day"                      : [ 12, 26 ],
    2510                                         "New Year's Eve"                            : [ 12, 31 ]
    2511                                 }
    2512                         },
    2513                         'Utah': {
    2514                                 'PH': {
    2515                                         "New Year's Day"              : [ 1, 1 ],
    2516                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2517                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2518                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2519                                         "Independence Day"            : [ 7, 4 ],
    2520                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2521                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2522                                         "Veterans Day"                : [ 11, 11 ],
    2523                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2524                                         "Christmas Day"               : [ 12, 25 ],
    2525                                         "Pioneer Day"                 : [ 7, 24 ]
    2526                                 }
    2527                         },
    2528                         'Vermont': {
    2529                                 'PH': {
    2530                                         "New Year's Day"              : [ 1, 1 ],
    2531                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2532                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2533                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2534                                         "Independence Day"            : [ 7, 4 ],
    2535                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2536                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2537                                         "Veterans Day"                : [ 11, 11 ],
    2538                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2539                                         "Christmas Day"               : [ 12, 25 ],
    2540                                         "Town Meeting Day"            : [ "firstMarchTuesday", 0 ],
    2541                                         "Battle of Bennington"        : [ "firstAugustMonday", 14 ]
    2542                                 }
    2543                         },
    2544                         'Virginia': {
    2545                                 'PH': {
    2546                                         "New Year's Day"              : [ 1, 1 ],
    2547                                         "Lee-Jackson Day"             : [ "firstJanuaryMonday", 11 ],
    2548                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2549                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2550                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2551                                         "Independence Day"            : [ 7, 4 ],
    2552                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2553                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2554                                         "Veterans Day"                : [ 11, 11 ],
    2555                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2556                                         "Christmas Day"               : [ 12, 25 ]
    2557                                 }
    2558                         },
    2559                         'Washington': {
    2560                                 'PH': {
    2561                                         "New Year's Day"              : [ 1, 1 ],
    2562                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2563                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2564                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2565                                         "Independence Day"            : [ 7, 4 ],
    2566                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2567                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2568                                         "Veterans Day"                : [ 11, 11 ],
    2569                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2570                                         "Christmas Day"               : [ 12, 25 ]
    2571                                 }
    2572                         },
    2573                         'West Virginia': {
    2574                                 'PH': {
    2575                                         "New Year's Day"              : [ 1, 1 ],
    2576                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2577                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2578                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2579                                         "Independence Day"            : [ 7, 4 ],
    2580                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2581                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2582                                         "Veterans Day"                : [ 11, 11 ],
    2583                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2584                                         "Christmas Day"               : [ 12, 25 ],
    2585                                         "West Virginia Day"           : [ 6, 20 ],
    2586                                         "Lincoln's Day"               : [ "firstNovemberThursday", 22 ]
    2587                                 }
    2588                         },
    2589                         'Wisconsin': {
    2590                                 'PH': { // http://docs.legis.wisconsin.gov/statutes/statutes/995/20
    2591                                         "New Year's Day"              : [ 1, 1 ],
    2592                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2593                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2594                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2595                                         "Independence Day"            : [ 7, 4 ],
    2596                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2597                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2598                                         "Veterans Day"                : [ 11, 11 ],
    2599                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2600                                         "Christmas Day"               : [ 12, 25 ],
    2601                                         "Primary Election Day"        : [ "firstAugustTuesday", 7 ],
    2602                                         "Election Day"                : [ "firstNovemberMonday", 1 ]
    2603                                 }
    2604                         },
    2605                         'Wyoming': {
    2606                                 'PH': {
    2607                                         "New Year's Day"              : [ 1, 1 ],
    2608                                         "Martin Luther King, Jr. Day" : [ "firstJanuaryMonday", 14 ],
    2609                                         "Washington's Birthday"       : [ "firstFebruaryMonday", 14 ],
    2610                                         "Memorial Day"                : [ "lastMayMonday", 0 ],
    2611                                         "Independence Day"            : [ 7, 4 ],
    2612                                         "Labor Day"                   : [ "firstSeptemberMonday", 0 ],
    2613                                         "Columbus Day"                : [ "firstOctoberMonday", 7 ],
    2614                                         "Veterans Day"                : [ 11, 11 ],
    2615                                         "Thanksgiving"                : [ "firstNovemberThursday", 21 ],
    2616                                         "Christmas Day"               : [ 12, 25 ]
    2617                                 }
    2618                         }
    2619                 }, // }}}
    2620                 'si': { // {{{
    2621                         'PH': { // http://www.vlada.si/o_sloveniji/politicni_sistem/prazniki/
    2622                                 'novo leto'                                 : [  1,  1 ],
    2623                                 'Prešernov dan, slovenski kulturni praznik' : [  2,  8 ],
    2624                                 'velikonočna nedelja'                       : [ 'easter',  0 ],
    2625                                 'velikonočni ponedeljek'                    : [ 'easter',  1 ],
    2626                                 'dan upora proti okupatorju'                : [  4,  27 ],
    2627                                 'praznik dela 1'                            : [  5, 1 ],
    2628                                 'praznik dela 2'                            : [  5, 2 ],
    2629                                 'binkoštna nedelja - binkošti'              : [ 'easter',  49 ],
    2630                                 'dan državnosti'                            : [  6, 25 ],
    2631                                 'Marijino vnebovzetje'                      : [  8, 15 ],
    2632                                 'dan reformacije'                           : [ 10, 31 ],
    2633                                 'dan spomina na mrtve'                      : [ 11,  1 ],
    2634                                 'božič'                                     : [ 12, 25 ],
    2635                                 'dan samostojnosti in enotnosti'            : [ 12, 26 ]
    2636                         }
    2637                 }, // }}}
    2638                 'it': { // {{{
    2639                         'PH': { // http://www.governo.it/Presidenza/ufficio_cerimoniale/cerimoniale/giornate.html
    2640                                 'Capodanno'                                 : [  1,  1 ],
    2641                                 'Epifania'                                  : [  1,  6 ],
    2642                                 'Liberazione dal nazifascismo (1945)'       : [  4, 25 ],
    2643                                 'Pasqua'                                    : [ 'easter',  0 ],
    2644                                 'Lunedì di Pasqua'                          : [ 'easter',  1 ],
    2645                                 'Festa del lavoro'                          : [  5, 1 ],
    2646                                 'Festa della Repubblica'                    : [  6, 2 ],
    2647                                 'Assunzione di Maria'                       : [  8, 15 ],
    2648                                 'Ognissanti'                                : [ 11,  1 ],
    2649                                 'Festa dell’unità nazionale'                : [ 'firstSeptemberSunday', 0 ],
    2650                                 'Immacolata Concezione'                     : [ 12,  8 ],
    2651                                 'Natale di Gesù'                            : [ 12, 25 ],
    2652                                 'Santo Stefano'                             : [ 12, 26 ],
    2653                         },
    2654                 }, // }}}
    2655         };
    2656         // }}}
    2657 
    2658         // error correction {{{
    2659         // Taken form http://www.netzwolf.info/j/osm/time_domain.js
    2660         // Credits go to Netzwolf
    2661         //
    2662         // Key to word_error_correction is the token name except wrong_words
    2663         var word_error_correction = {
    2664                 wrong_words: { /* {{{ */
    2665                         'Assuming "<ok>" for "<ko>".': {
    2666                                 'Frühling':  'Mar-May',
    2667                                 'Frühjahr':  'Mar-May',
    2668                                 'Sommer':    'Jun-Aug',
    2669                                 'Herbst':    'Sep-Nov',
    2670                                 'winter':    'Dec-Feb',
    2671                         }, '"<ko>" wird als "<ok>" interpertiert.': {
    2672                                 'spring':  'Mar-May',
    2673                                 'summer':  'Jun-Aug',
    2674                                 'autumn':  'Sep-Nov',
    2675                                 // 'winter':  'Dec-Feb', // Same as in English.
    2676                                 // morning: '08:00-12:00',
    2677                                 // evening: '13:00-18:00',
    2678                                 '_':  '-',
    2679                                 'daytime': 'sunrise-sunset',
    2680                         }, 'Bitte benutze die englische Schreibweise "<ok>" für "<ko>".': {
    2681                                 'sommer':   'summer',
    2682                                 'werktag':  'Mo-Fr',
    2683                                 'werktags': 'Mo-Fr',
    2684                         }, 'Bitte benutze "<ok>" für "<ko>". Beispiel: "Mo-Fr 08:00-12:00; Tu off".': {
    2685                                 'ruhetag':     'off',
    2686                                 'ruhetage':    'off',
    2687                                 'geschlossen': 'off',
    2688                                 'geschl':      'off',
    2689                                 // 'ausser':      'off',
    2690                                 // 'außer':       'off',
    2691                         }, 'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.': {
    2692                                 'gesloten':   'off',
    2693                                 'feestdag':   'PH',
    2694                                 'feestdagen': 'PH',
    2695                         }, 'Assuming "<ok>" for "<ko>". Please avoid using "workday": http://wiki.openstreetmap.org/wiki/Talk:Key:opening_hours#need_syntax_for_holidays_and_workingdays': {
    2696                                 // Used around 260 times but the problem is, that work day might be different in other countries.
    2697                                 'wd':           'Mo-Fr',
    2698                                 'on work day':  'Mo-Fr',
    2699                                 'on work days': 'Mo-Fr',
    2700                                 'weekday':      'Mo-Fr',
    2701                                 'weekdays':     'Mo-Fr',
    2702                                 'vardagar':     'Mo-Fr',
    2703                         }, 'Please use something like "Mo off" instead "<ko>".': {
    2704                                 'except': 'off',
    2705                         }, 'Please omit "<ko>" or use a colon instead: "12:00-14:00".': {
    2706                                 'h': '',
    2707                         }, 'Please omit "<ko>".': {
    2708                                 'season': '',
    2709                                 'hs':     '',
    2710                                 'hrs':    '',
    2711                                 'hours':  '',
    2712                                 '·':      '',
    2713                         }, 'Please omit "<ko>". The key must not be in the value.': {
    2714                                 'opening_hours=': '',
    2715                         }, 'Please omit "<ko>". You might want to express open end which can be specified as "12:00+" for example.': {
    2716                                 'from': '',
    2717                         }, 'You can use notation "<ok>" for "<ko>" in the case that you want to express open end times. Example: "12:00+".': {
    2718                                 'til late': '+',
    2719                                 'till late': '+',
    2720                                 'bis open end': '+',
    2721                                 '-late': '+',
    2722                                 '-open end': '+',
    2723                                 '-openend': '+',
    2724                         }, 'Please use notation "<ok>" for "<ko>". If the times are unsure or vary consider a comment e.g. 12:00-14:00 "only on sunshine".': {
    2725                                 '~':  '-',
    2726                                 '~': '-',
    2727                         }, 'Please use notation "<ok>" for "<ko>". Fallback rule: 12:00-14:00 || "call us"': {
    2728                                 'otherwise':  '||',
    2729                         }, 'You can use notation "<ok>" for "<ko>" temporally if the syntax will still be valid.': {
    2730                                 '?':  'unknown "please add this if known"',
    2731                         }, 'Please use notation "<ok>" for "<ko>". Although using "–" is typographical correct, the opening_hours syntax is defined with the normal hyphen. Correct typography should be done on application level …': {
    2732                                 '–':  '-',
    2733                         }, 'Please use notation "<ok>" for "<ko>".': {
    2734                                 '→':               '-',
    2735                                 '−':               '-',
    2736                                 '=':               '-',
    2737                                 'ー':              '-',
    2738                                 'to':              '-',
    2739                                 'до':              '-',
    2740                                 'a':               '-', // language unknown
    2741                                 'as':              '-', // language unknown
    2742                                 'á':               '-', // language unknown
    2743                                 'ás':              '-', // language unknown
    2744                                 'às':              '-', // language unknown
    2745                                 'ate':             '-', // language unknown
    2746                                 'till':            '-',
    2747                                 'til':             '-',
    2748                                 'until':           '-',
    2749                                 'through':         '-',
    2750                                 'and':             ',',
    2751                                 '&':               ',',
    2752                                 // '/':               ',', // Can not be corrected as / is a valid token
    2753                                 ':':              ':',
    2754                                 '°°':              ':00',
    2755                                 'always':          '24/7',
    2756                                 'nonstop':         '24/7',
    2757                                 '24x7':            '24/7',
    2758                                 'anytime':         '24/7',
    2759                                 'all day':         '24/7',
    2760                                 'daily':           'Mo-Su',
    2761                                 'everyday':        'Mo-Su',
    2762                                 'every day':       'Mo-Su',
    2763                                 'all days':        'Mo-Su',
    2764                                 '7j/7':            'Mo-Su', // I guess that it means that
    2765                                 '7/7':             'Mo-Su', // I guess that it means that
    2766                                 /* {{{
    2767                                  * Fixing this causes to ignore the following warning: "There should be no
    2768                                  * reason to differ more than 6 days from a constrained
    2769                                  * weekdays. If so tell us …".
    2770                                  * The following mistake is expected to occur more often.
    2771                                  */
    2772                                 '7days':           'Mo-Su',
    2773                                 '7 days':          'Mo-Su',
    2774                                 // }}}
    2775                                 '7 days a week':   'Mo-Su',
    2776                                 '7 days/week':     'Mo-Su',
    2777                                 '24 hours 7 days a week':   '24/7',
    2778                                 '24 hours':                '00:00-24:00',
    2779                                 'midday':          '12:00',
    2780                                 'midnight':        '00:00',
    2781                                 'holiday':         'PH',
    2782                                 'holidays':        'PH',
    2783                                 'public holidays': 'PH',
    2784                                 'public holiday':  'PH',
    2785                                 'day after public holiday':      'PH +1 day',
    2786                                 'one day after public holiday':  'PH +1 day',
    2787                                 'day before public holiday':     'PH -1 day',
    2788                                 'one day before public holiday': 'PH -1 day',
    2789                                 'school holiday':  'SH',
    2790                                 'school holidays': 'SH',
    2791                                 // summerholiday:  'SH',
    2792                                 // summerholidays: 'SH',
    2793                                 /* Not implemented {{{ */
    2794                                 // 'day after school holiday':      'SH +1 day',
    2795                                 // 'one day after school holiday':  'SH +1 day',
    2796                                 // 'day before school holiday':     'SH -1 day',
    2797                                 // 'one day before school holiday': 'SH -1 day',
    2798                                 /* }}} */
    2799                                 'weekend':         'Sa,Su',
    2800                                 'weekends':        'Sa,Su',
    2801                                 'daylight':        'sunrise-sunset',
    2802                         }, 'Please use notation "<ok>" for "<ko>". Those characters look very similar but are not the same!': {
    2803                                 'оff':             'off', // Russian o
    2804                         }, 'Please use time format in 24 hours notation ("<ko>"). If PM is used you might have to convert the hours to the 24 hours notation.': {
    2805                                 'pm': '',
    2806                                 'рм': '',
    2807                                 'am': '',
    2808                                 'ам': '',
    2809                         }, 'Bitte verzichte auf "<ko>".': {
    2810                                 'uhr': '',
    2811                                 'geöffnet': '',
    2812                                 'zwischen': '',
    2813                                 'ist': '',
    2814                                 'durchgehend': '',
    2815                         }, 'Bitte verzichte auf "<ko>". Sie möchten eventuell eine Öffnungszeit ohne vorgegebenes Ende (Open End) angeben. Beispiel: "12:00+"': {
    2816                                 'ab':  '',
    2817                                 'von': '',
    2818                         }, 'Es sieht so aus also möchten Sie zusätzliche Einschränkungen für eine Öffnungszeit geben. Falls sich dies nicht mit der Syntax ausdrücken lässt können Kommentare verwendet werden. Zusätzlich sollte eventuell das Schlüsselwort `open` benutzt werden. Bitte probiere "<ok>" für "<ko>".': {
    2819                                 'damen':  'open "Damen"',
    2820                                 'herren': 'open "Herren"',
    2821                         }, 'Bitte benutze die Schreibweise "<ok>" für "<ko>".': {
    2822                                 'bis':         '-',
    2823                                 'täglich':     'Mo-Su',
    2824                                 'schulferien': 'SH',
    2825                                 'sonn und feiertag':   'PH,Su',
    2826                                 'sonn und feiertags':  'PH,Su',
    2827                                 'sonn- und feiertags': 'PH,Su',
    2828                                 'sonn-/feiertag':      'PH,Su',
    2829                                 'sonn-/feiertags':     'PH,Su',
    2830                                 'an sonn- und feiertagen': 'PH,Su',
    2831                                 'nur sonn-/feiertags': 'PH,Su',
    2832                                 'sonn- und feiertage': 'PH,Su',
    2833                         }, 'Bitte benutze die Schreibweise "<ok>" für "<ko>". Es ist war typografisch korrekt aber laut der Spezifikation für opening_hours nicht erlaubt. Siehe auch: http://wiki.openstreetmap.org/wiki/DE:Key:opening_hours/specification.': {
    2834                                 '„': '"',
    2835                                 '“': '"',
    2836                                 '”': '"',
    2837                         }, 'Please use notation "<ok>" for "<ko>". The used quote signs might be typographically correct but are not defined in the specification. See http://wiki.openstreetmap.org/wiki/Key:opening_hours/specification.': {
    2838                                 '«': '"',
    2839                                 '»': '"',
    2840                                 '‚': '"',
    2841                                 '‘': '"',
    2842                                 '’': '"',
    2843                                 '「': '"',
    2844                                 '」': '"',
    2845                                 '『': '"',
    2846                                 '』': '"',
    2847                         }, 'Please use notation "<ok>" for "<ko>". The used quote signs are not defined in the specification. See http://wiki.openstreetmap.org/wiki/Key:opening_hours/specification.': {
    2848                                 "'": '"',
    2849                         }, 'You might want to use comments instead of brackets (which are not valid in this context). If you do, replace "<ok>" with "<ko>".': {
    2850                                 // '(': '"',
    2851                                 // ')': '"',
    2852                         }, 'Bitte benutze die Schreibweise "<ok>" als Ersatz für "und" bzw. "u.".': {
    2853                                 'und': ',',
    2854                                 'u':   ',',
    2855                         }, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".': {
    2856                                 'feiertag':   'PH',
    2857                                 'feiertags':  'PH',
    2858                                 'feiertage':  'PH',
    2859                                 'feiertagen': 'PH'
    2860                         }, 'S\'il vous plaît utiliser "<ok>" pour "<ko>".': {
    2861                                 'fermé':        'off',
    2862                                 'et':           ',',
    2863                                 'à':            '-',
    2864                                 'jours fériés': 'PH',
    2865                         }
    2866                 }, /* }}} */
    2867 
    2868                 month: { /* {{{ */
    2869                         'default': {
    2870                                 'jan':  0,
    2871                                 'feb':  1,
    2872                                 'mar':  2,
    2873                                 'apr':  3,
    2874                                 'may':  4,
    2875                                 'jun':  5,
    2876                                 'jul':  6,
    2877                                 'aug':  7,
    2878                                 'sep':  8,
    2879                                 'oct':  9,
    2880                                 'nov': 10,
    2881                                 'dec': 11,
    2882                         }, 'Please use the English abbreviation "<ok>" for "<ko>".': {
    2883                                 'jänner':   0, // Austria
    2884                                 'january':    0,
    2885                                 'february':   1,
    2886                                 'march':      2,
    2887                                 'april':      3,
    2888                                 // 'may':     4,
    2889                                 'june':       5,
    2890                                 'july':       6,
    2891                                 'august':     7,
    2892                                 'september':  8,
    2893                                 'sept':       8,
    2894                                 'october':    9,
    2895                                 'november':  10,
    2896                                 'december':  11,
    2897                         }, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".': {
    2898                                 'januar':    0,
    2899                                 'februar':   1,
    2900                                 'märz':    2,
    2901                                 'maerz':     2,
    2902                                 'mai':       4,
    2903                                 'juni':      5,
    2904                                 'juli':      6,
    2905                                 'okt':       9,
    2906                                 'oktober':   9,
    2907                                 'dez':      11,
    2908                                 'dezember': 11,
    2909                         }, 'S\'il vous plaît utiliser l\'abréviation "<ok>" pour "<ko>".': {
    2910                                 'janvier':    0,
    2911                                 'février':    1,
    2912                                 'fév':        1,
    2913                                 'mars':       2,
    2914                                 'avril':      3,
    2915                                 'avr':        3,
    2916                                 'mai':        4,
    2917                                 'juin':       5,
    2918                                 'juillet':    6,
    2919                                 'août':       7,
    2920                                 'aoû':        7,
    2921                                 'septembre':  8,
    2922                                 'octobre':    9,
    2923                                 'novembre':  10,
    2924                                 'décembre':  11,
    2925                         }, 'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.': {
    2926                                 'januari':  0,
    2927                                 'februari': 1,
    2928                                 'maart':    2,
    2929                                 'mei':      4,
    2930                                 'augustus': 7,
    2931                         }
    2932                 }, /* }}} */
    2933 
    2934                 calcday: {
    2935                         'default': {
    2936                                 'day': 'day',
    2937                                 'days': 'days',
    2938                         },
    2939                 },
    2940 
    2941                 weekday: { // {{{ Good source: http://www.omniglot.com/language/time/days.htm */
    2942                         'default': {
    2943                                 'su': 0,
    2944                                 'mo': 1,
    2945                                 'tu': 2,
    2946                                 'we': 3,
    2947                                 'th': 4,
    2948                                 'fr': 5,
    2949                                 'sa': 6,
    2950                         }, 'Assuming "<ok>" for "<ko>"': {
    2951                                 'm':          1,
    2952                                 'w':          3,
    2953                                 'f':          5,
    2954                         }, 'Please use the abbreviation "<ok>" for "<ko>".': {
    2955                                 'sun':        0,
    2956                                 'sunday':     0,
    2957                                 'sundays':    0,
    2958                                 'mon':        1,
    2959                                 'monday':     1,
    2960                                 'mondays':    1,
    2961                                 'tue':        2,
    2962                                 'tues':       2, // Used here: http://www.westerhambeauty.co.uk/contact.php
    2963                                 'tuesday':    2,
    2964                                 'tuesdays':   2,
    2965                                 'wed':        3,
    2966                                 'weds':       3,
    2967                                 'wednesday':  3,
    2968                                 'wednesdays': 3,
    2969                                 'thu':        4,
    2970                                 'thur':       4,
    2971                                 'thurs':      4,
    2972                                 'thursday':   4,
    2973                                 'thursdays':  4,
    2974                                 'fri':        5,
    2975                                 'friday':     5,
    2976                                 'fridays':    5,
    2977                                 'sat':        6,
    2978                                 'saturday':   6,
    2979                                 'saturdays':  6,
    2980                         }, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>". Could also mean Saturday in Polish …': {
    2981                                 'so':         0,
    2982                         }, 'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".': {
    2983                                 'son':         0,
    2984                                 'sonntag':     0,
    2985                                 'sonn-':       0,
    2986                                 'sonntags':    0,
    2987                                 'montag':      1,
    2988                                 'montags':     1,
    2989                                 'di':          2,
    2990                                 'die':         2,
    2991                                 'dienstag':    2,
    2992                                 'dienstags':   2,
    2993                                 'mi':          3,
    2994                                 'mit':         3,
    2995                                 'mittwoch':    3,
    2996                                 'mittwochs':   3,
    2997                                 'do':          4,
    2998                                 'don':         4,
    2999                                 'donnerstag':  4,
    3000                                 'donnerstags': 4,
    3001                                 'fre':         5,
    3002                                 'freitag':     5,
    3003                                 'freitags':    5,
    3004                                 'sam':         6,
    3005                                 'samstag':     6,
    3006                                 'samstags':    6,
    3007                         }, 'S\'il vous plaît utiliser l\'abréviation "<ok>" pour "<ko>".': {
    3008                                 'dim':      0,
    3009                                 'dimanche': 0,
    3010                                 'lu':       1,
    3011                                 'lun':      1,
    3012                                 'lundi':    1,
    3013                                 'mardi':    2,
    3014                                 'mer':      3,
    3015                                 'mercredi': 3,
    3016                                 'je':       4,
    3017                                 'jeu':      4,
    3018                                 'jeudi':    4,
    3019                                 've':       5,
    3020                                 'ven':      5,
    3021                                 'vendredi': 5,
    3022                                 'samedi':   6,
    3023                         }, 'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.': {
    3024                                 'zo':        0,
    3025                                 'zon':       0,
    3026                                 'zontag':    0, // correct?
    3027                                 'zondag':    0,
    3028                                 'maandag':   1,
    3029                                 'din':       2,
    3030                                 'dinsdag':   2,
    3031                                 'wo':        3,
    3032                                 'woe':       3,
    3033                                 'woensdag':  3,
    3034                                 'donderdag': 4,
    3035                                 'vr':        5,
    3036                                 'vri':       5,
    3037                                 'vrijdag':   5,
    3038                                 'za':        6,
    3039                                 'zat':       6,
    3040                                 'zaterdag':  6,
    3041                         }, 'Please use the English abbreviation "<ok>" for "<ko>".': { // FIXME: Translate to Czech.
    3042                                 'neděle':  0,
    3043                                 'ne':      0,
    3044                                 'pondělí': 1,
    3045                                 'po':      1,
    3046                                 'úterý':   2,
    3047                                 'út':      2,
    3048                                 'středa':  3,
    3049                                 'st':      3,
    3050                                 'čtvrtek': 4,
    3051                                 'čt':      4,
    3052                                 'pátek':   5,
    3053                                 'pá':      5,
    3054                                 'sobota':  6,
    3055                         }, 'Please use the English abbreviation "<ok>" (Spanish) for "<ko>".': {
    3056                                 'martes':    0,
    3057                                 'miércoles': 1,
    3058                                 'jueves':    2,
    3059                                 'viernes':   3,
    3060                                 'sábado':    4,
    3061                                 'domingo':   5,
    3062                                 'lunes':     6,
    3063                         }, 'Please use the English abbreviation "<ok>" (Indonesian) for "<ko>".': {
    3064                                 'selasa': 0,
    3065                                 'rabu':   1,
    3066                                 'kami':   2,
    3067                                 'jumat':  3,
    3068                                 'sabtu':  4,
    3069                                 'minggu': 5,
    3070                                 'senin':  6,
    3071                         }, 'Please use the English abbreviation "<ok>" (Swedish) for "<ko>".': {
    3072                                 'söndag':   0,
    3073                                 'söndagar': 0,
    3074                                 'måndag':   1,
    3075                                 'ma':       1,
    3076                                 'tisdag':   2,
    3077                                 'onsdag':   3, // Same in Danish
    3078                                 'torsdag':  4,
    3079                                 'fredag':   5,
    3080                                 'lördag':   6,
    3081                                 'lördagar': 6,
    3082                         }, 'Please use the English abbreviation "<ok>" (Polish) for "<ko>".': {
    3083                                 'niedziela': 0, 'niedz': 0, 'n': 0, 'ndz': 0,
    3084                                 'poniedziałek': 1, 'poniedzialek': 1, 'pon': 1, 'pn': 1,
    3085                                 'wtorek': 2, 'wt': 2,
    3086                                 'środa': 3, 'sroda': 3, 'śr': 3, 'sr': 3,
    3087                                 'czwartek': 4, 'czw': 4, 'cz': 4,
    3088                                 'piątek': 5, 'piatek': 5, 'pt': 5,
    3089                                 'sobota': 6, 'sob': 6, // 'so': 6 // abbreviation also used in German
    3090                         }, 'Please use the English abbreviation "<ok>" (Russian) for "<ko>".': {
    3091                                 'воскресенье' : 0,
    3092                                 'Вс'          : 0,
    3093                                 "voskresen'ye": 0,
    3094                                 'понедельник' : 1,
    3095                                 'Пн'          : 1,
    3096                                 "ponedel'nik" : 1,
    3097                                 'вторник'     : 2,
    3098                                 'vtornik'     : 2,
    3099                                 'среда'       : 3,
    3100                                 'sreda'       : 3,
    3101                                 'четверг'     : 4,
    3102                                 'chetverk'    : 4,
    3103                                 'пятница'     : 5,
    3104                                 'pyatnitsa'   : 5,
    3105                                 'суббота'     : 6,
    3106                                 'subbota'     : 6,
    3107                         }, 'Please use the English abbreviation "<ok>" (Danish) for "<ko>".': {
    3108                                 'søndag' : 0,
    3109                                 'mandag' : 1,
    3110                                 'tirsdag': 2,
    3111                                 'onsdag' : 3, // Same in Swedish
    3112                                 'torsdag': 4,
    3113                                 'fredag' : 5,
    3114                                 'lørdag' : 6,
    3115                         },
    3116                 }, /* }}} */
    3117 
    3118                 timevar: { /* {{{ Special time variables which actual value depends on the date and the position of the facility. */
    3119                         'default': {
    3120                                 'sunrise': 'sunrise',
    3121                                 'sunset':  'sunset',
    3122                                 'dawn':    'dawn',
    3123                                 'dusk':    'dusk',
    3124                         }, 'Please use notation "<ok>" for "<ko>".': {
    3125                                 'sundown':  'sunset',
    3126                         }, 'Bitte benutze die Schreibweise "<ok>" für "<ko>".': {
    3127                                 'morgendämmerung': 'dawn',
    3128                                 'abenddämmerung':  'dusk',
    3129                                 'sonnenaufgang':   'sunrise',
    3130                                 'sonnenuntergang': 'sunset',
    3131                         },
    3132                 }, /* }}} */
    3133 
    3134                 'event': { // variable events
    3135                         'default': {
    3136                                 'easter': 'easter',
    3137                         }, 'Bitte benutze die Schreibweise "<ok>" für "<ko>".': {
    3138                                 'ostern': 'easter',
    3139                         },
    3140                 },
    3141         };
    3142         // }}}
    3143         // }}}
    3144 
    3145         // make the library accessible for the outside world {{{
    3146         if (typeof exports === 'object') {
    3147                 // For nodejs
    3148                 var SunCalc = require('suncalc');
    3149                 module.exports = factory(SunCalc, holidays, word_error_correction);
    3150         } else {
    3151                 // For browsers
    3152                 root.opening_hours = factory(root.SunCalc, holidays, word_error_correction);
    3153         }
    3154         /// }}}
    3155 }(this, function (SunCalc, holidays, word_error_correction) {
    3156         return function(value, nominatiomJSON, oh_mode) {
    3157                 // short constants {{{
    3158                 var word_value_replacement = { // If the correct values can not be calculated.
    3159                         dawn    : 60 * 5 + 30,
    3160                         sunrise : 60 * 6,
    3161                         sunset  : 60 * 18,
    3162                         dusk    : 60 * 18 + 30,
    3163                 };
    3164                 var months   = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
    3165                 var weekdays = ['Su','Mo','Tu','We','Th','Fr','Sa'];
    3166                 var default_prettify_conf = {
    3167                         // Update README.md if changed.
    3168                         'zero_pad_hour': true,           // enforce ("%02d", hour)
    3169                         'one_zero_if_hour_zero': false,  // only one zero "0" if hour is zero "0"
    3170                         'leave_off_closed': true,        // leave keywords "off" and "closed" as is
    3171                         'keyword_for_off_closed': 'off', // use given keyword instead of "off" or "closed"
    3172                         'rule_sep_string': ' ',          // separate rules by string
    3173                         'print_semicolon': true,         // print token which separates normal rules
    3174                         'leave_weekday_sep_one_day_betw': true, // use the separator (either "," or "-" which is used to separate days which follow to each other like Sa,Su or Su-Mo
    3175                         'sep_one_day_between': ',',      // separator which should be used
    3176                         'zero_pad_month_and_week_numbers': false, // Format week (e.g. `week 01`) and month day numbers (e.g. `Jan 01`) with "%02d".
    3177                 };
    3178 
    3179                 var minutes_in_day = 60 * 24;
    3180                 var msec_in_day    = 1000 * 60 * minutes_in_day;
    3181                 var msec_in_week   = msec_in_day * 7;
    3182 
    3183                 var library_name   = 'opening_hours.js';
    3184                 var repository_url = 'https://github.com/ypid/' + library_name;
    3185                 var issues_url     = repository_url + '/issues?state=open';
    3186                 // }}}
    3187 
    3188                 // constructor parameters {{{
    3189                 // Evaluate additional information which can be given. They are
    3190                 // required to reasonably calculate 'sunrise' and to use the correct
    3191                 // holidays.
    3192                 var location_cc, location_state, lat, lon;
    3193                 if (typeof nominatiomJSON !== 'undefined') {
    3194                         if (typeof nominatiomJSON.address !== 'undefined') {
    3195                                 if (typeof nominatiomJSON.address.country_code !== 'undefined') {
    3196                                         location_cc    = nominatiomJSON.address.country_code;
    3197                                 }
    3198                                 if (typeof nominatiomJSON.address.state !== 'undefined') {
    3199                                         location_state = nominatiomJSON.address.state;
    3200                                 } else if (typeof nominatiomJSON.address.county !== 'undefined') {
    3201                                         location_state = nominatiomJSON.address.county;
    3202                                 }
    3203                         }
    3204 
    3205                         if (typeof nominatiomJSON.lon !== 'undefined') { // lat will be tested later …
    3206                                 lat = nominatiomJSON.lat;
    3207                                 lon = nominatiomJSON.lon;
    3208                         }
    3209                 }
    3210 
    3211                 // 0: time ranges (default), tags: opening_hours, lit, …
    3212                 // 1: points in time
    3213                 // 2: both (time ranges and points in time), tags: collection_times, service_times
    3214                 if (typeof oh_mode === 'undefined') {
    3215                         oh_mode = 0;
    3216                 } else if (!(typeof oh_mode === 'number' && (oh_mode === 0 || oh_mode === 1 || oh_mode === 2))) {
    3217                         throw 'The third constructor parameter is oh_mode and must be a number (0, 1 or 2)';
    3218                 }
    3219                 // }}}
    3220 
    3221                 // Tokenize value and generate selector functions. {{{
    3222                 if (value.match(/^(?:\s*;?\s*)+$/))
    3223                         throw 'Value contains nothing meaningful which can be parsed';
    3224 
    3225                 var parsing_warnings = []; // Elements are fed into function formatWarnErrorMessage(nrule, at, message)
    3226                 var done_with_warnings = false; // The functions which throw warnings can be called multiple times.
    3227                 var done_with_selector_reordering = false;
    3228                 var done_with_selector_reordering_warnings = false;
    3229                 var tokens = tokenize(value);
    3230                 // console.log(JSON.stringify(tokens, null, '    '));
    3231                 var prettified_value = '';
    3232                 var week_stable = true;
    3233 
    3234                 var rules = [];
    3235                 var new_tokens = [];
    3236 
    3237                 for (var nrule = 0; nrule < tokens.length; nrule++) {
    3238                         if (tokens[nrule][0].length === 0) {
    3239                                 // Rule does contain nothing useful e.g. second rule of '10:00-12:00;' (empty) which needs to be handled.
    3240                                 parsing_warnings.push([nrule, -1,
    3241                                         'This rule does not contain anything useful. Please remove this empty rule.'
    3242                                         + (nrule === tokens.length - 1 && nrule > 0 && !tokens[nrule][1] ?
    3243                                                 ' Might it be possible that you are a programmer and adding a semicolon after each statement is hardwired in your muscle memory ;) ?'
    3244                                                 + ' The thing is that the semicolon in the opening_hours syntax is defined as rule separator.'
    3245                                                 + ' So for compatibility reasons you should omit this last semicolon.': '')
    3246                                         ]);
    3247                                 continue;
    3248                         }
    3249 
    3250                         var continue_at = 0;
    3251                         var next_rule_is_additional = false;
    3252                         do {
    3253                                 if (continue_at === tokens[nrule][0].length) break;
    3254                                 // Additional rule does contain nothing useful e.g. second rule of '10:00-12:00,' (empty) which needs to be handled.
    3255 
    3256                                 var selectors = {
    3257                                         // Time selectors
    3258                                         time: [],
    3259 
    3260                                         // Temporary array of selectors from time wrapped to the next day
    3261                                         wraptime: [],
    3262 
    3263                                         // Date selectors
    3264                                         weekday: [],
    3265                                         holiday: [],
    3266                                         week: [],
    3267                                         month: [],
    3268                                         monthday: [],
    3269                                         year: [],
    3270 
    3271                                         // Array with non-empty date selector types, with most optimal ordering
    3272                                         date: [],
    3273 
    3274                                         fallback: tokens[nrule][1],
    3275                                         additional: continue_at ? true : false,
    3276                                         meaning: true,
    3277                                         unknown: false,
    3278                                         comment: undefined,
    3279                                         build_from_token_rule: undefined,
    3280                                 };
    3281 
    3282                                 selectors.build_from_token_rule = [ nrule, continue_at, new_tokens.length ];
    3283                                 continue_at = parseGroup(tokens[nrule][0], continue_at, selectors, nrule);
    3284                                 if (typeof continue_at === 'object') {
    3285                                         continue_at = continue_at[0];
    3286                                 } else {
    3287                                         continue_at = 0;
    3288                                 }
    3289 
    3290                                 // console.log('Current tokens: ' + JSON.stringify(tokens[nrule], null, '    '));
    3291 
    3292                                 new_tokens.push(
    3293                                         [
    3294                                                 tokens[nrule][0].slice(
    3295                                                         selectors.build_from_token_rule[1],
    3296                                                         continue_at === 0
    3297                                                                 ? tokens[nrule][0].length
    3298                                                                 : continue_at
    3299                                                 ),
    3300                                                 tokens[nrule][1],
    3301                                                 tokens[nrule][2],
    3302                                         ]
    3303                                 );
    3304 
    3305                                 if (next_rule_is_additional && new_tokens.length > 1) {
    3306                                         // Move 'rule separator' from last token of last rule to first token of this rule.
    3307                                         new_tokens[new_tokens.length - 1][0].unshift(new_tokens[new_tokens.length - 2][0].pop());
    3308                                 }
    3309 
    3310                                 next_rule_is_additional = continue_at === 0 ? false : true;
    3311 
    3312                                 if (selectors.year.length > 0)
    3313                                         selectors.date.push(selectors.year);
    3314                                 if (selectors.holiday.length > 0)
    3315                                         selectors.date.push(selectors.holiday);
    3316                                 if (selectors.month.length > 0)
    3317                                         selectors.date.push(selectors.month);
    3318                                 if (selectors.monthday.length > 0)
    3319                                         selectors.date.push(selectors.monthday);
    3320                                 if (selectors.week.length > 0)
    3321                                         selectors.date.push(selectors.week);
    3322                                 if (selectors.weekday.length > 0)
    3323                                         selectors.date.push(selectors.weekday);
    3324 
    3325                                 // console.log('weekday: ' + JSON.stringify(selectors.weekday, null, '\t'));
    3326                                 rules.push(selectors);
    3327 
    3328                                 // This handles selectors with time ranges wrapping over midnight (e.g. 10:00-02:00)
    3329                                 // it generates wrappers for all selectors and creates a new rule.
    3330                                 if (selectors.wraptime.length > 0) {
    3331                                         var wrapselectors = {
    3332                                                 time: selectors.wraptime,
    3333                                                 date: [],
    3334 
    3335                                                 meaning: selectors.meaning,
    3336                                                 unknown: selectors.unknown,
    3337                                                 comment: selectors.comment,
    3338 
    3339                                                 wrapped: true,
    3340                                                 build_from_token_rule: selectors.build_from_token_rule,
    3341                                         };
    3342 
    3343                                         for (var dselg = 0; dselg < selectors.date.length; dselg++) {
    3344                                                 wrapselectors.date.push([]);
    3345                                                 for (var dsel = 0; dsel < selectors.date[dselg].length; dsel++) {
    3346                                                         wrapselectors.date[wrapselectors.date.length-1].push(
    3347                                                                         generateDateShifter(selectors.date[dselg][dsel], -msec_in_day)
    3348                                                                 );
    3349                                                 }
    3350                                         }
    3351 
    3352                                         rules.push(wrapselectors);
    3353                                 }
    3354                         } while (continue_at);
    3355                 }
    3356                 // console.log(JSON.stringify(tokens, null, '    '));
    3357                 // console.log(JSON.stringify(new_tokens, null, '    '));
    3358                 // }}}
    3359 
    3360                 /* Format warning or error message for the user. {{{
    3361                  *
    3362                  * :param nrule: Rule number starting with zero.
    3363                  * :param at: Token position at which the issue occurred.
    3364                  * :param message: Human readable string with the message.
    3365                  * :returns: String with position of the warning or error marked for the user.
    3366                  */
    3367                 function formatWarnErrorMessage(nrule, at, message) {
    3368                         // FIXME: Change to new_tokens.
    3369                         if (typeof nrule === 'number') {
    3370                                 var pos = 0;
    3371                                 if (nrule === -1) { // Usage of rule index not required because we do have access to value.length.
    3372                                         pos = value.length - at;
    3373                                 } else { // Issue accrued at a later time, position in string needs to be reconstructed.
    3374                                         if (typeof tokens[nrule][0][at] === 'undefined') {
    3375                                                 if (typeof tokens[nrule][0] && at === -1) {
    3376                                                         pos = value.length;
    3377                                                         if (typeof tokens[nrule+1] === 'object' && typeof tokens[nrule+1][2] === 'number') {
    3378                                                                 pos -= tokens[nrule+1][2];
    3379                                                         } else if (typeof tokens[nrule][2] === 'number') {
    3380                                                                 pos -= tokens[nrule][2];
    3381                                                         }
    3382                                                 } else {
    3383                                                         // Given position is invalid.
    3384                                                         //
    3385                                                         formatLibraryBugMessage('Bug in warning generation code which could not determine the exact position of the warning or error in value.');
    3386                                                         pos = value.length;
    3387                                                         if (typeof tokens[nrule][2] !== 'undefined') {
    3388                                                                 // Fallback: Point to last token in the rule which caused the problem.
    3389                                                                 // Run real_test regularly to fix the problem before a user is confronted with it.
    3390                                                                 pos -= tokens[nrule][2];
    3391                                                                 console.warn('Last token for rule: ' + tokens[nrule]);
    3392                                                                 console.log(value.substring(0, pos) + ' <--- (' + message + ')');
    3393                                                                 console.log('\n');
    3394                                                         } {
    3395                                                                 console.warn('tokens[nrule][2] is undefined. This is ok if nrule is the last rule.');
    3396                                                         }
    3397                                                 }
    3398                                         } else {
    3399                                                 pos = value.length;
    3400                                                 if (typeof tokens[nrule][0][at+1] !== 'undefined') {
    3401                                                         pos -= tokens[nrule][0][at+1][2];
    3402                                                 } else if (typeof tokens[nrule][2] !== 'undefined') {
    3403                                                         pos -= tokens[nrule][2];
    3404                                                 }
    3405                                         }
    3406                                 }
    3407                                 return value.substring(0, pos) + ' <--- (' + message + ')';
    3408                         } else if (typeof nrule === 'string') {
    3409                                 return nrule.substring(0, at) + ' <--- (' + message + ')';
    3410                         }
    3411                 }
    3412                 // }}}
    3413 
    3414                 /* Format internal library error message. {{{
    3415                  *
    3416                  * :param message: Human readable string with the error message.
    3417                  * :returns: Error message for the user.
    3418                  */
    3419                 function formatLibraryBugMessage(message) {
    3420                         if (typeof message === 'undefined')
    3421                                 message = '';
    3422                         else
    3423                                 message = ' ' + message;
    3424 
    3425                         message = 'An error occurred during evaluation of the value "' + value + '".'
    3426                                 + ' Please file a bug report here: ' + issues_url + '.'
    3427                                 + message;
    3428                         console.log(message);
    3429                         return message;
    3430                 }
    3431                 // }}}
    3432 
    3433                 /* Tokenize input stream. {{{
    3434                  *
    3435                  * :param value: Raw opening_hours value.
    3436                  * :returns: Tokenized list object. Complex structure. Check the
    3437                  *              internal documentation in the doc directory for details.
    3438                  */
    3439                 function tokenize(value) {
    3440                         var all_tokens       = [];
    3441                         var curr_rule_tokens = [];
    3442 
    3443                         var last_rule_fallback_terminated = false;
    3444 
    3445                         while (value !== '') {
    3446                                 // console.log("Parsing value: " + value);
    3447                                 var tmp;
    3448                                 if (tmp = value.match(/^week\b/i)) {
    3449                                         // Reserved keywords.
    3450                                         curr_rule_tokens.push([tmp[0].toLowerCase(), tmp[0].toLowerCase(), value.length ]);
    3451                                         value = value.substr(tmp[0].length);
    3452                                 } else if (tmp = value.match(/^(?:off\b|closed\b|open\b|unknown\b)/i)) {
    3453                                         // Reserved keywords.
    3454                                         curr_rule_tokens.push([tmp[0].toLowerCase(), 'state', value.length ]);
    3455                                         value = value.substr(tmp[0].length);
    3456                                 } else if (tmp = value.match(/^24\/7/i)) {
    3457                                         // Reserved keyword.
    3458                                         curr_rule_tokens.push([tmp[0], tmp[0], value.length ]);
    3459                                         value = value.substr(tmp[0].length);
    3460                                 } else if (tmp = value.match(/^(?:PH|SH)/i)) {
    3461                                         // special day name (holidays)
    3462                                         curr_rule_tokens.push([tmp[0].toUpperCase(), 'holiday', value.length ]);
    3463                                         value = value.substr(2);
    3464                                 } else if (tmp = value.match(/^(&|_|→|–|−|=|·|opening_hours=|ー|\?|~|~|:|°°|24x7|24 hours 7 days a week|24 hours|7 ?days(?:(?: a |\/)week)?|7j?\/7|all days?|every day|(?:|-|till? |bis )?(?:late|open[ ]?end)|(?:(?:one )?day (?:before|after) )?(?:school|public) holidays?|days?\b|до|рм|ам|jours fériés|on work days?|sonntag?|(?:nur |an )?sonn-?(?:(?: und |\/)feiertag(?:s|en?)?)?|[a-zäößàáéøčěíúýřПнВсо]+\b|à|á|mo|tu|we|th|fr|sa|su|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\.?/i)) {
    3465                                         /* Handle all remaining words and specific other characters with error tolerance.
    3466                                          *
    3467                                          * à|á: Word boundary does not work with unicode chars: 'test à test'.match(/\bà\b/i)
    3468                                          * https://stackoverflow.com/questions/10590098/javascript-regexp-word-boundaries-unicode-characters
    3469                                          * Order in the regular expression capturing group is important in some cases.
    3470                                          *
    3471                                          * mo|tu|we|th|fr|sa|su|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec: Prefer defended keywords
    3472                                          * if used in cases like 'mo12:00-14:00' (when keyword is followed by number).
    3473                                          */
    3474                                         var correct_val = returnCorrectWordOrToken(tmp[1].toLowerCase(), value.length);
    3475                                         // console.log('Error tolerance for string "' + tmp[1] + '" returned "' + correct_val + '".');
    3476                                         if (typeof correct_val === 'object') {
    3477                                                 curr_rule_tokens.push([ correct_val[0], correct_val[1], value.length ]);
    3478                                                 value = value.substr(tmp[0].length);
    3479                                         } else if (typeof correct_val === 'string') {
    3480                                                 if (tmp[1].toLowerCase() === 'pm') {
    3481                                                         var hours_token_at = curr_rule_tokens.length - 1;
    3482                                                         var hours_token;
    3483                                                         if (hours_token_at >= 0) {
    3484                                                                 if (hours_token_at -2 >= 0 &&
    3485                                                                                 matchTokens(
    3486                                                                                         curr_rule_tokens, hours_token_at - 2,
    3487                                                                                         'number', 'timesep', 'number'
    3488                                                                                 )
    3489                                                                         ) {
    3490                                                                         hours_token_at -= 2;
    3491                                                                         hours_token = curr_rule_tokens[hours_token_at];
    3492                                                                 } else if (matchTokens(curr_rule_tokens, hours_token_at, 'number')) {
    3493                                                                         hours_token = curr_rule_tokens[hours_token_at];
    3494                                                                 }
    3495 
    3496                                                                 if (typeof hours_token === 'object' && hours_token[0] <= 12) {
    3497                                                                         hours_token[0] += 12;
    3498                                                                         curr_rule_tokens[hours_token_at] = hours_token;
    3499                                                                 }
    3500                                                         }
    3501                                                 }
    3502                                                 var correct_tokens = tokenize(correct_val)[0];
    3503                                                 if (correct_tokens[1] === true) { // last_rule_fallback_terminated
    3504                                                         throw formatLibraryBugMessage();
    3505                                                 }
    3506                                                 for (var i = 0; i < correct_tokens[0].length; i++) {
    3507                                                         curr_rule_tokens.push([correct_tokens[0][i][0], correct_tokens[0][i][1], value.length]);
    3508                                                         // value.length - tmp[0].length does not have the desired effect for all test cases.
    3509                                                 }
    3510 
    3511                                                 value = value.substr(tmp[0].length);
    3512                                                 // value = correct_val + value.substr(tmp[0].length);
    3513                                                 // Does not work because it would generate the wrong length for formatWarnErrorMessage.
    3514                                         } else {
    3515                                                 // other single-character tokens
    3516                                                 curr_rule_tokens.push([value[0].toLowerCase(), value[0].toLowerCase(), value.length - 1 ]);
    3517                                                 value = value.substr(1);
    3518                                         }
    3519                                 } else if (tmp = value.match(/^\d+/)) {
    3520                                         // number
    3521                                         if (Number(tmp[0]) > 1900) { // Assumed to be a year number.
    3522                                                 curr_rule_tokens.push([Number(tmp[0]), 'year', value.length ]);
    3523                                                 if (Number(tmp[0]) >= 2100) // Probably an error
    3524                                                         parsing_warnings.push([ -1, value.length - 1,
    3525                                                                 'The number ' + Number(tmp[0]) + ' will be interpreted as year.'
    3526                                                                 + ' This is probably not intended. Times can be specified as "12:00".'
    3527                                                         ]);
    3528                                         } else {
    3529                                                 curr_rule_tokens.push([Number(tmp[0]), 'number', value.length ]);
    3530                                         }
    3531 
    3532                                         value = value.substr(tmp[0].length);
    3533                                 } else if (tmp = value.match(/^"([^"]+)"/)) {
    3534                                         // Comment following the specification.
    3535                                         // Any character is allowed inside the comment except " itself.
    3536                                         curr_rule_tokens.push([tmp[1], 'comment', value.length ]);
    3537                                         value = value.substr(tmp[0].length);
    3538                                 } else if (tmp = value.match(/^(["'„“‚‘’«「『])([^"'“”‘’»」』;|]*)(["'”“‘’»」』])/)) {
    3539                                         // Comments with error tolerance.
    3540                                         // The comments still have to be somewhat correct meaning
    3541                                         // the start and end quote signs used have to be
    3542                                         // appropriate. So “testing„ will not match as it is not a
    3543                                         // quote but rather something unknown which the user should
    3544                                         // fix first.
    3545                                         // console.log('Matched: ' + JSON.stringify(tmp));
    3546                                         for (var pos = 1; pos <= 3; pos += 2) {
    3547                                                 // console.log('Pos: ' + pos + ', substring: ' + tmp[pos]);
    3548                                                 var correct_val = returnCorrectWordOrToken(tmp[pos],
    3549                                                         value.length - (pos === 3 ? tmp[1].length + tmp[2].length : 0)
    3550                                                 );
    3551                                                 if (typeof correct_val !== 'string' && tmp[pos] !== '"') {
    3552                                                         throw formatLibraryBugMessage(
    3553                                                                 'A character for error tolerance was allowed in the regular expression'
    3554                                                                 + ' but is not covered by word_error_correction'
    3555                                                                 + ' which is needed to format a proper message for the user.'
    3556                                                         );
    3557                                                 }
    3558                                         }
    3559                                         curr_rule_tokens.push([tmp[2], 'comment', value.length ]);
    3560                                         value = value.substr(tmp[0].length);
    3561                                 } else if (value.match(/^;/)) {
    3562                                         // semicolon terminates rule
    3563                                         // next tokens belong to a new rule
    3564                                         all_tokens.push([ curr_rule_tokens, last_rule_fallback_terminated, value.length ]);
    3565                                         value = value.substr(1);
    3566 
    3567                                         curr_rule_tokens = [];
    3568                                         last_rule_fallback_terminated = false;
    3569                                 } else if (value.match(/^\|\|/)) {
    3570                                         // || terminates rule
    3571                                         // Next tokens belong to a fallback rule.
    3572                                         if (curr_rule_tokens.length === 0)
    3573                                                 throw formatWarnErrorMessage(-1, value.length - 2, 'Rule before fallback rule does not contain anything useful');
    3574 
    3575                                         all_tokens.push([ curr_rule_tokens, last_rule_fallback_terminated, value.length ]);
    3576                                         curr_rule_tokens = [];
    3577                                         // curr_rule_tokens = [ [ '||', 'rule separator', value.length  ] ];
    3578                                         // FIXME: Use this. Unknown bug needs to be solved in the process.
    3579                                         value = value.substr(2);
    3580 
    3581                                         last_rule_fallback_terminated = true;
    3582                                 } else if (value.match(/^(?:␣|\s)/)) {
    3583                                         // Using "␣" as space is not expected to be a normal
    3584                                         // mistake. Just ignore it to make using taginfo easier.
    3585                                         value = value.substr(1);
    3586                                 } else if (tmp = value.match(/^\s+/)) {
    3587                                         // whitespace is ignored
    3588                                         value = value.substr(tmp[0].length);
    3589                                 } else if (value.match(/^[:.]/)) {
    3590                                         // time separator
    3591                                         if (value[0] === '.' && !done_with_warnings)
    3592                                                 parsing_warnings.push([ -1, value.length - 1, 'Please use ":" as hour/minute-separator' ]);
    3593                                         curr_rule_tokens.push([ ':', 'timesep', value.length ]);
    3594                                         value = value.substr(1);
    3595                                 } else {
    3596                                         // other single-character tokens
    3597                                         curr_rule_tokens.push([value[0].toLowerCase(), value[0].toLowerCase(), value.length ]);
    3598                                         value = value.substr(1);
    3599                                 }
    3600                         }
    3601 
    3602                         all_tokens.push([ curr_rule_tokens, last_rule_fallback_terminated ]);
    3603 
    3604                         return all_tokens;
    3605                 }
    3606                 // }}}
    3607 
    3608                 /* error correction/tolerance function {{{
    3609                  * Go through word_error_correction hash and get correct value back.
    3610                  *
    3611                  * :param word: Wrong Word or character.
    3612                  * :param value_length: Current value_length (used for warnings).
    3613                  * :returns:
    3614                  *              * (valid) opening_hours sub string.
    3615                  *              * object with [ internal_value, token_name ] if value is correct.
    3616                  *              * undefined if word could not be found (and thus is not be corrected).
    3617                  */
    3618                 function returnCorrectWordOrToken(word, value_length) {
    3619                         for (var token_name in word_error_correction) {
    3620                                 for (var comment in word_error_correction[token_name]) {
    3621                                         for (var old_val in word_error_correction[token_name][comment]) {
    3622                                                 if (old_val === word) {
    3623                                                         var val = word_error_correction[token_name][comment][old_val];
    3624                                                         if (comment === 'default') {
    3625                                                                 // Return internal representation of word.
    3626                                                                 return [ val, token_name ];
    3627                                                         } else if (token_name === 'wrong_words' && !done_with_warnings) {
    3628                                                                 // Replace wrong words or characters with correct ones.
    3629                                                                 // This will return a string which is then being tokenized.
    3630                                                                 parsing_warnings.push([ -1, value_length - old_val.length,
    3631                                                                         comment.replace(/<ko>/, old_val).replace(/<ok>/, val) ]);
    3632                                                                 return val;
    3633                                                         } else {
    3634                                                                 // Get correct string value from the 'default' hash and generate warning.
    3635                                                                 var correct_abbr;
    3636                                                                 for (correct_abbr in word_error_correction[token_name]['default']) {
    3637                                                                         if (word_error_correction[token_name]['default'][correct_abbr] === val)
    3638                                                                                 break;
    3639                                                                 }
    3640                                                                 if (typeof correct_abbr === 'undefined') {
    3641                                                                         throw formatLibraryBugMessage('Including the stacktrace.');
    3642                                                                 }
    3643                                                                 if (token_name !== 'timevar') {
    3644                                                                         // Everything else than timevar:
    3645                                                                         // E.g. 'Mo' start with a upper case letter.
    3646                                                                         // It just looks better.
    3647                                                                         correct_abbr = correct_abbr.charAt(0).toUpperCase()
    3648                                                                                 + correct_abbr.slice(1);
    3649                                                                 }
    3650                                                                 if (!done_with_warnings)
    3651                                                                         parsing_warnings.push([ -1, value_length - old_val.length,
    3652                                                                                 comment.replace(/<ko>/, old_val).replace(/<ok>/, correct_abbr) ]);
    3653                                                                 return [ val, token_name ];
    3654                                                         }
    3655                                                 }
    3656                                         }
    3657                                 }
    3658                         }
    3659                         return undefined;
    3660                 }
    3661                 // }}}
    3662 
    3663                 /* return warnings as list {{{
    3664                  *
    3665                  * :param it: Iterator object if available (optional).
    3666                  * :returns: Warnings as list with one warning per element.
    3667                  */
    3668                 function getWarnings(it) {
    3669                         if (!done_with_warnings && typeof it === 'object') {
    3670                                 /* getWarnings was called in a state without critical errors.
    3671                                  * We can do extended tests.
    3672                                  */
    3673 
    3674                                 /* Place all tests in this function if an additional (high
    3675                                  * level) test is added and this does not require to rewrite
    3676                                  * big parts of (sub) selector parsers only to get the
    3677                                  * position. If that is the case, then rather place the test
    3678                                  * code in the (sub) selector parser function directly.
    3679                                  */
    3680 
    3681                                 var wide_range_selectors = [ 'year', 'month', 'week', 'holiday' ];
    3682                                 var small_range_selectors = [ 'weekday', 'time', '24/7', 'state', 'comment'];
    3683 
    3684                                 // How many times was a selector_type used per rule? {{{
    3685                                 var used_selectors = [];
    3686                                 var used_selectors_types_array = [];
    3687                                 var has_token = {};
    3688 
    3689                                 for (var nrule = 0; nrule < new_tokens.length; nrule++) {
    3690                                         if (new_tokens[nrule][0].length === 0) continue;
    3691                                         // Rule does contain nothing useful e.g. second rule of '10:00-12:00;' (empty) which needs to be handled.
    3692 
    3693                                         var selector_start_end_type = [ 0, 0, undefined ],
    3694                                                 prettified_group_value  = [];
    3695                                         // console.log(new_tokens[nrule][0]);
    3696 
    3697                                         used_selectors[nrule] = {};
    3698                                         used_selectors_types_array[nrule] = [];
    3699 
    3700                                         do {
    3701                                                 selector_start_end_type = getSelectorRange(new_tokens[nrule][0], selector_start_end_type[1]);
    3702                                                 // console.log(selector_start_end_type, new_tokens[nrule][0].length);
    3703 
    3704                                                 if (selector_start_end_type[0] === selector_start_end_type[1] &&
    3705                                                         new_tokens[nrule][0][selector_start_end_type[0]][0] === '24/7'
    3706                                                         ) {
    3707                                                                 has_token['24/7'] = true;
    3708                                                 }
    3709 
    3710                                                 if (typeof used_selectors[nrule][selector_start_end_type[2]] !== 'object') {
    3711                                                         used_selectors[nrule][selector_start_end_type[2]] = [ selector_start_end_type[1] ];
    3712                                                 } else {
    3713                                                         used_selectors[nrule][selector_start_end_type[2]].push(selector_start_end_type[1]);
    3714                                                 }
    3715                                                 used_selectors_types_array[nrule].push(selector_start_end_type[2]);
    3716 
    3717                                                 selector_start_end_type[1]++;
    3718                                         } while (selector_start_end_type[1] < new_tokens[nrule][0].length);
    3719                                 }
    3720                                 // console.log('used_selectors: ' + JSON.stringify(used_selectors, null, '    '));
    3721                                 // }}}
    3722 
    3723                                 for (var nrule = 0; nrule < used_selectors.length; nrule++) {
    3724 
    3725                                         /* Check if more than one not connected selector of the same type is used in one rule {{{ */
    3726                                         for (var selector_type in used_selectors[nrule]) {
    3727                                                 // console.log(selector_type + ' use at: ' + used_selectors[nrule][selector_type].length);
    3728                                                 if (used_selectors[nrule][selector_type].length > 1) {
    3729                                                         parsing_warnings.push([nrule, used_selectors[nrule][selector_type][used_selectors[nrule][selector_type].length - 1],
    3730                                                                 'You have used ' + used_selectors[nrule][selector_type].length
    3731                                                                 + (selector_type.match(/^(?:comment|state)/) ?
    3732                                                                         ' ' + selector_type
    3733                                                                         + (selector_type === 'state' ? ' keywords' : 's')
    3734                                                                         + ' in one rule.'
    3735                                                                         + ' You may only use one in one rule.'
    3736                                                                         :
    3737                                                                         ' not connected ' + selector_type
    3738                                                                         + (selector_type.match(/^(?:month|weekday)$/) ? 's' : ' ranges')
    3739                                                                         + ' in one rule.'
    3740                                                                         + ' This is probably an error.'
    3741                                                                         + ' Equal selector types can (and should) always be written in conjunction separated by comma.'
    3742                                                                         + ' Example for time ranges "12:00-13:00,15:00-18:00".'
    3743                                                                         + ' Example for weekdays "Mo-We,Fr".'
    3744                                                                   )
    3745                                                                 + ' Rules can be separated by ";".' ]
    3746                                                         );
    3747                                                         done_with_selector_reordering = true; // Correcting the selector order makes no sense if this kind of issue exists.
    3748                                                 }
    3749                                         }
    3750                                         /* }}} */
    3751 
    3752                                         /* Check if change default state rule is not the first rule {{{ */
    3753                                         if (   typeof used_selectors[nrule].state === 'object'
    3754                                                 && Object.keys(used_selectors[nrule]).length === 1
    3755                                         ) {
    3756 
    3757                                                 if (nrule !== 0) {
    3758                                                         parsing_warnings.push([nrule, new_tokens[nrule][0].length - 1,
    3759                                                                 "This rule which changes the default state (which is closed) for all following rules is not the first rule."
    3760                                                                 + " The rule will overwrite all previous rules."
    3761                                                                 + " It can be legitimate to change the default state to open for example"
    3762                                                                 + " and then only specify for which times the facility is closed."
    3763                                                         ]);
    3764                                                 }
    3765                                         /* }}} */
    3766                                         /* Check if a rule (with state open) has no time selector {{{ */
    3767                                         } else if (typeof used_selectors[nrule].time === 'undefined') {
    3768                                                 if (    (          typeof used_selectors[nrule].state === 'object'
    3769                                                                         && new_tokens[nrule][0][used_selectors[nrule].state[0]][0] === 'open'
    3770                                                                         && typeof used_selectors[nrule].comment === 'undefined'
    3771                                                                 ) || ( typeof used_selectors[nrule].comment === 'undefined'
    3772                                                                         && typeof used_selectors[nrule].state === 'undefined'
    3773                                                                 ) &&
    3774                                                                 typeof used_selectors[nrule]['24/7'] === 'undefined'
    3775                                                 ) {
    3776 
    3777                                                         parsing_warnings.push([nrule, new_tokens[nrule][0].length - 1,
    3778                                                                 "This rule is not very explicit because there is no time selector being used."
    3779                                                                 + " Please add a time selector to this rule or use a comment to make it more explicit."
    3780                                                         ]);
    3781                                                 }
    3782                                         }
    3783                                         /* }}} */
    3784 
    3785                                         /* Check if empty comment was given {{{ */
    3786                                         if (typeof used_selectors[nrule].comment === 'object'
    3787                                                 && new_tokens[nrule][0][used_selectors[nrule].comment[0]][0].length === 0
    3788                                         ) {
    3789 
    3790                                                 parsing_warnings.push([nrule, used_selectors[nrule].comment[0],
    3791                                                         "You have used an empty comment."
    3792                                                         + " Please either write something in the comment or use the keyword unknown instead."
    3793                                                 ]);
    3794                                         }
    3795                                         /* }}} */
    3796 
    3797                                         /* Check if rule with closed|off modifier is additional {{{ */
    3798                                         /* FIXME: Enable this test. */
    3799                                         if (typeof new_tokens[nrule][0][0] === 'object'
    3800                                                         && new_tokens[nrule][0][0][0] === ','
    3801                                                         && new_tokens[nrule][0][0][1] === 'rule separator'
    3802                                                         && typeof used_selectors[nrule].state === 'object'
    3803                                                         && (
    3804                                                                    new_tokens[nrule][0][used_selectors[nrule].state[0]][0] === 'closed'
    3805                                                                 || new_tokens[nrule][0][used_selectors[nrule].state[0]][0] === 'off'
    3806                                                            )
    3807                                         ) {
    3808 
    3809                                                 // parsing_warnings.push([nrule, new_tokens[nrule][0].length - 1,
    3810                                                         // "This rule will be evaluated as closed but it was specified as additional rule."
    3811                                                         // + " It is enough to specify this rule as normal rule using the \";\" character."
    3812                                                         // + " See https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification#explain:rule_modifier:closed."
    3813                                                 // ]);
    3814                                         }
    3815                                         /* }}} */
    3816 
    3817                                         /* Check for valid use of <separator_for_readability> {{{ */
    3818                                         for (var i = 0; i < used_selectors_types_array[nrule].length - 1; i++) {
    3819                                                 var selector_type = used_selectors_types_array[nrule][i];
    3820                                                 var next_selector_type = used_selectors_types_array[nrule][i+1];
    3821                                                 if (   (   wide_range_selectors.indexOf(selector_type)       !== -1
    3822                                                                 && wide_range_selectors.indexOf(next_selector_type)  !== -1
    3823                                                         ) || ( small_range_selectors.indexOf(selector_type)      !== -1
    3824                                                                 && small_range_selectors.indexOf(next_selector_type) !== -1)
    3825                                                         ) {
    3826 
    3827                                                         if (new_tokens[nrule][0][used_selectors[nrule][selector_type][0]][0] === ':') {
    3828                                                                 parsing_warnings.push([nrule, used_selectors[nrule][selector_type][0],
    3829                                                                         "You have used the optional symbol <separator_for_readability> in the wrong place."
    3830                                                                         + " Please check the syntax specification to see where it could be used or remove it."
    3831                                                                 ]);
    3832                                                         }
    3833                                                 }
    3834                                         }
    3835                                         /* }}} */
    3836 
    3837                                 }
    3838 
    3839                                 /* Check if 24/7 is used and it does not mean 24/7 because there are other rules {{{ */
    3840                                 var has_advanced = it.advance();
    3841 
    3842                                 if (has_advanced === true && has_token['24/7'] && !done_with_warnings) {
    3843                                         parsing_warnings.push([ -1, 0, 'You used 24/7 in a way that is probably not interpreted as "24 hours 7 days a week".'
    3844                                                         // Probably because of: "24/7; 12:00-14:00 open", ". Needs extra testing.
    3845                                                         + ' For correctness you might want to use "open" or "closed"'
    3846                                                         + ' for this rule and then write your exceptions which should achieve the same goal and is more clear'
    3847                                                         + ' e.g. "open; Mo 12:00-14:00 off".']);
    3848                                 }
    3849                                 /* }}} */
    3850 
    3851                                 prettifyValue();
    3852                         }
    3853                         done_with_warnings = true;
    3854 
    3855                         var warnings = [];
    3856                         // FIXME: Sort based on parsing_warnings[1], tricky …
    3857                         for (var i = 0; i < parsing_warnings.length; i++) {
    3858                                 warnings.push( formatWarnErrorMessage(parsing_warnings[i][0], parsing_warnings[i][1], parsing_warnings[i][2]) );
    3859                         }
    3860                         return warnings;
    3861                 }
    3862 
    3863                 /* Helpers for getWarnings {{{ */
    3864 
    3865                 /* Check if token is the begin of a selector and why. {{{
    3866                  *
    3867                  * :param tokens: List of token objects.
    3868                  * :param at: Position where to start.
    3869                  * :returns:
    3870                  *              * false the current token is not the begin of a selector.
    3871                  *              * Position in token array from where the decision was made that
    3872                  *                the token is the start of a selector.
    3873                  */
    3874                 function tokenIsTheBeginOfSelector(tokens, at) {
    3875                         if (typeof tokens[at][3] === 'string') {
    3876                                 return 3;
    3877                         } else if (tokens[at][1] === 'comment'
    3878                                         || tokens[at][1] === 'state'
    3879                                         || tokens[at][1] === '24/7'
    3880                                         || tokens[at][1] === 'rule separator'
    3881                                 ){
    3882 
    3883                                 return 1;
    3884                         } else {
    3885                                 return false;
    3886                         }
    3887                 }
    3888                 /* }}} */
    3889 
    3890                 /* Get start and end position of a selector. {{{
    3891                  * For example this value 'Mo-We,Fr' will return the position of the
    3892                  * token lexeme 'Mo' and 'Fr' e.g. there indexes [ 0, 4 ] in the
    3893                  * selector array of tokens.
    3894                  *
    3895                  * :param tokens: List of token objects.
    3896                  * :param at: Position where to start.
    3897                  * :returns: Array:
    3898                  *                      0. Index of first token in selector array of tokens.
    3899                  *                      1. Index of last token in selector array of tokens.
    3900                  *                      2. Selector type.
    3901                  */
    3902                 function getSelectorRange(tokens, at) {
    3903                         var selector_start = at,
    3904                                 selector_end,
    3905                                 pos_in_token_array;
    3906 
    3907                         for (; selector_start >= 0; selector_start--) {
    3908                                 pos_in_token_array = tokenIsTheBeginOfSelector(tokens, selector_start);
    3909                                 if (pos_in_token_array)
    3910                                         break;
    3911                         }
    3912                         selector_end = selector_start;
    3913 
    3914                         if (pos_in_token_array === 1) {
    3915                                 // Selector consists of a single token.
    3916 
    3917                                 // Include tailing colon.
    3918                                 if (selector_end + 1 < tokens.length && tokens[selector_end + 1][0] === ':')
    3919                                         selector_end++;
    3920 
    3921                                 return [ selector_start, selector_end, tokens[selector_start][pos_in_token_array] ];
    3922                         }
    3923 
    3924                         for (selector_end++; selector_end < tokens.length ; selector_end++) {
    3925                                 if (tokenIsTheBeginOfSelector(tokens, selector_end))
    3926                                         return [ selector_start, selector_end - 1, tokens[selector_start][pos_in_token_array] ];
    3927                         }
    3928 
    3929                         return [ selector_start, selector_end - 1, tokens[selector_start][pos_in_token_array] ];
    3930                 }
    3931                 /* }}} */
    3932                 /* }}} */
    3933                 /* }}} */
    3934 
    3935                 /* Prettify raw value from user. {{{
    3936                  * The value is generated by putting the tokens back together to a string.
    3937                  *
    3938                  * :param argument_hash: Hash which can contain:
    3939                  *              'conf': Configuration hash.
    3940                  *              'get_internals: If true export internal data structures.
    3941                  *              'rule_index: Only prettify the rule with this index.
    3942                  * :returns: Prettified value string or object if get_internals is true.
    3943                  */
    3944                 function prettifyValue(argument_hash) {
    3945                         var user_conf = {},
    3946                                 get_internals   = false,
    3947                                 rule_index;
    3948                         if (typeof argument_hash !== 'undefined') {
    3949 
    3950                                 if (typeof argument_hash.conf === 'object')
    3951                                         user_conf = argument_hash.conf;
    3952 
    3953                                 if (typeof argument_hash.rule_index === 'number')
    3954                                         rule_index = argument_hash.rule_index;
    3955 
    3956                                 if (argument_hash.get_internals === true)
    3957                                         get_internals = true;
    3958                         }
    3959 
    3960                         for (var key in default_prettify_conf) {
    3961                                 if (typeof user_conf[key] === 'undefined')
    3962                                         user_conf[key] = default_prettify_conf[key];
    3963                         }
    3964 
    3965                         prettified_value = '';
    3966                         var prettified_value_array = [];
    3967 
    3968                         for (var nrule = 0; nrule < new_tokens.length; nrule++) {
    3969                                 if (new_tokens[nrule][0].length === 0) continue;
    3970                                 // Rule does contain nothing useful e.g. second rule of '10:00-12:00;' (empty) which needs to be handled.
    3971 
    3972                                 if (typeof rule_index === 'number') {
    3973                                         if (rule_index !== nrule) continue;
    3974                                 } else {
    3975                                         if (nrule !== 0)
    3976                                                 prettified_value += (
    3977                                                         new_tokens[nrule][1]
    3978                                                                 ? user_conf.rule_sep_string + '|| '
    3979                                                                 : (
    3980                                                                         new_tokens[nrule][0][0][1] === 'rule separator'
    3981                                                                         ? ','
    3982                                                                         : (
    3983                                                                                 user_conf.print_semicolon
    3984                                                                                 ? ';'
    3985                                                                                 : ''
    3986                                                                         )
    3987                                                                 ) +
    3988                                                         user_conf.rule_sep_string);
    3989                                 }
    3990 
    3991                                 var selector_start_end_type = [ 0, 0, undefined ],
    3992                                         prettified_group_value = [];
    3993                                 // console.log(new_tokens[nrule][0]);
    3994                                 var count = 0;
    3995 
    3996 
    3997                                 do {
    3998                                         selector_start_end_type = getSelectorRange(new_tokens[nrule][0], selector_start_end_type[1]);
    3999                                         // console.log(selector_start_end_type, new_tokens[nrule][0].length, count);
    4000 
    4001                                         if (count > 50) {
    4002                                                 throw formatLibraryBugMessage('infinite loop');
    4003                                         }
    4004 
    4005                                         if (selector_start_end_type[2] !== 'rule separator') {
    4006                                                 prettified_group_value.push(
    4007                                                         [
    4008                                                                 selector_start_end_type,
    4009                                                                 prettifySelector(
    4010                                                                         new_tokens[nrule][0],
    4011                                                                         selector_start_end_type[0],
    4012                                                                         selector_start_end_type[1],
    4013                                                                         selector_start_end_type[2],
    4014                                                                         user_conf
    4015                                                                 ),
    4016                                                         ]
    4017                                                 );
    4018                                         }
    4019 
    4020                                         selector_start_end_type[1]++;
    4021                                         count++;
    4022                                         // console.log(selector_start_end_type, new_tokens[nrule][0].length, count);
    4023                                 } while (selector_start_end_type[1] < new_tokens[nrule][0].length);
    4024                                 // console.log('Prettified value: ' + JSON.stringify(prettified_group_value, null, '    '));
    4025                                 var not_sorted_prettified_group_value = prettified_group_value.slice();
    4026 
    4027                                 if (!done_with_selector_reordering) {
    4028                                         prettified_group_value.sort(
    4029                                                 function (a, b) {
    4030                                                         var selector_order = [ 'year', 'month', 'week', 'holiday', 'weekday', 'time', '24/7', 'state', 'comment'];
    4031                                                         return selector_order.indexOf(a[0][2]) - selector_order.indexOf(b[0][2]);
    4032                                                 }
    4033                                         );
    4034                                 }
    4035                                 var old_prettified_value_length = prettified_value.length;
    4036 
    4037                                 prettified_value += prettified_group_value.map(
    4038                                         function (array) {
    4039                                                 return array[1];
    4040                                         }
    4041                                 ).join(' ');
    4042 
    4043                                 prettified_value_array.push( prettified_group_value );
    4044 
    4045                                 if (!done_with_selector_reordering_warnings) {
    4046                                         for (var i = 0, l = not_sorted_prettified_group_value.length; i < l; i++) {
    4047                                                 if (not_sorted_prettified_group_value[i] !== prettified_group_value[i]) {
    4048                                                         // console.log(i + ': ' + prettified_group_value[i][0][2]);
    4049                                                         var length = i + old_prettified_value_length; // i: Number of spaces in string.
    4050                                                         for (var x = 0; x <= i; x++) {
    4051                                                                 length += prettified_group_value[x][1].length;
    4052                                                                 // console.log('Length: ' + length + ' ' + prettified_group_value[x][1]);
    4053                                                         }
    4054                                                         // console.log(length);
    4055                                                         parsing_warnings.push([ prettified_value, length,
    4056                                                                 'The selector "' + prettified_group_value[i][0][2] + '" was switched with'
    4057                                                                 + ' the selector "' + not_sorted_prettified_group_value[i][0][2] + '"'
    4058                                                                 + ' for readablitity and compatibiltity reasons.'
    4059                                                         ]);
    4060                                                 }
    4061                                         }
    4062                                 }
    4063                         }
    4064 
    4065                         done_with_selector_reordering_warnings = true;
    4066                         // console.log(JSON.stringify(prettified_value_array, null, '    '));
    4067 
    4068                         if (get_internals) {
    4069                                 return [ prettified_value_array, new_tokens ];
    4070                         } else {
    4071                                 return prettified_value;
    4072                         }
    4073                 }
    4074                 // }}}
    4075 
    4076                 /* Check selector array of tokens for specific token name pattern. {{{
    4077                  *
    4078                  * :param tokens: List of token objects.
    4079                  * :param at: Position at which the matching should begin.
    4080                  * :param token_name(s): One or many token_name strings which have to match in that order.
    4081                  * :returns: true if token_name(s) match in order false otherwise.
    4082                  */
    4083                 function matchTokens(tokens, at /*, matches... */) {
    4084                         if (at + arguments.length - 2 > tokens.length)
    4085                                 return false;
    4086                         for (var i = 0; i < arguments.length - 2; i++) {
    4087                                 if (tokens[at + i][1] !== arguments[i + 2])
    4088                                         return false;
    4089                         }
    4090 
    4091                         return true;
    4092                 }
    4093                 // }}}
    4094 
    4095                 /* Generate selector wrapper with time offset {{{
    4096                  *
    4097                  * :param func: Generated selector code function.
    4098                  * :param shirt: Time to shift in milliseconds.
    4099                  * :param token_name(s): One or many token_name strings which have to match in that order.
    4100                  * :returns: See selector code.
    4101                  */
    4102                 function generateDateShifter(func, shift) {
    4103                         return function(date) {
    4104                                 var res = func(new Date(date.getTime() + shift));
    4105 
    4106                                 if (typeof res[1] === 'undefined')
    4107                                         return res;
    4108                                 return [ res[0], new Date(res[1].getTime() - shift) ];
    4109                         };
    4110                 }
    4111                 // }}}
    4112 
    4113                 /* Top-level parser {{{
    4114                  *
    4115                  * :param tokens: List of token objects.
    4116                  * :param at: Position where to start.
    4117                  * :param selectors: Reference to selector object.
    4118                  * :param nrule: Rule number starting with 0.
    4119                  * :returns: See selector code.
    4120                  */
    4121                 function parseGroup(tokens, at, selectors, nrule) {
    4122                         var rule_modifier_specified = false;
    4123 
    4124                         // console.log(tokens); // useful for debugging of tokenize
    4125                         while (at < tokens.length) {
    4126                                 // console.log('Parsing at position', at +':', tokens[at]);
    4127                                 if (matchTokens(tokens, at, 'weekday')) {
    4128                                         at = parseWeekdayRange(tokens, at, selectors);
    4129                                 } else if (matchTokens(tokens, at, '24/7')) {
    4130                                         selectors.time.push(function(date) { return [true]; });
    4131                                         // Not needed. If there is no selector it automatically matches everything.
    4132                                         // WRONG: This only works if there is no other selector in this selector group ...
    4133                                         at++;
    4134                                 } else if (matchTokens(tokens, at, 'holiday')) {
    4135                                         if (matchTokens(tokens, at+1, ','))
    4136                                                 at = parseHoliday(tokens, at, selectors, true);
    4137                                         else
    4138                                                 at = parseHoliday(tokens, at, selectors, false);
    4139                                         week_stable = false;
    4140                                 } else if (matchTokens(tokens, at, 'month', 'number')
    4141                                                 || matchTokens(tokens, at, 'month', 'weekday')
    4142                                                 || matchTokens(tokens, at, 'year', 'month', 'number')
    4143                                                 || matchTokens(tokens, at, 'year', 'event')
    4144                                                 || matchTokens(tokens, at, 'event')) {
    4145 
    4146                                         at = parseMonthdayRange(tokens, at, nrule);
    4147                                         week_stable = false;
    4148                                 } else if (matchTokens(tokens, at, 'year')) {
    4149                                         at = parseYearRange(tokens, at);
    4150                                         week_stable = false;
    4151                                 } else if (matchTokens(tokens, at, 'month')) {
    4152                                         at = parseMonthRange(tokens, at);
    4153                                         // week_stable = false; // Decided based on the actual value/tokens.
    4154                                 } else if (matchTokens(tokens, at, 'week')) {
    4155                                         tokens[at][3] = 'week';
    4156                                         at = parseWeekRange(tokens, at);
    4157 
    4158                                 } else if (at !== 0 && at !== tokens.length - 1 && tokens[at][0] === ':') {
    4159                                         /* Ignore colon if they appear somewhere else than as time separator.
    4160                                          * Except the start or end of the value.
    4161                                          * This provides compatibility with the syntax proposed by Netzwolf:
    4162                                          * http://wiki.openstreetmap.org/wiki/Key:opening_hours/specification#separator_for_readability
    4163                                          * Check for valid use of <separator_for_readability> is implemented in function getWarnings().
    4164                                          */
    4165 
    4166                                         if (!done_with_warnings && matchTokens(tokens, at-1, 'holiday'))
    4167                                                 parsing_warnings.push([nrule, at, 'Please don’t use ":" after ' + tokens[at-1][1] + '.']);
    4168 
    4169                                         at++;
    4170                                 } else if (matchTokens(tokens, at, 'number', 'timesep')
    4171                                                 || matchTokens(tokens, at, 'timevar')
    4172                                                 || matchTokens(tokens, at, '(', 'timevar')
    4173                                                 || matchTokens(tokens, at, 'number', '-')) {
    4174 
    4175                                         at = parseTimeRange(tokens, at, selectors, false);
    4176 
    4177                                 } else if (matchTokens(tokens, at, 'state')) {
    4178 
    4179                                         if (tokens[at][0] === 'open') {
    4180                                                 selectors.meaning = true;
    4181                                         } else if (tokens[at][0] === 'closed' || tokens[at][0] === 'off') {
    4182                                                 selectors.meaning = false;
    4183                                         } else {
    4184                                                 selectors.meaning = false;
    4185                                                 selectors.unknown = true;
    4186                                         }
    4187 
    4188                                         rule_modifier_specified = true;
    4189                                         at++;
    4190                                         if (typeof tokens[at] === 'object' && tokens[at][0] === ',') // additional rule
    4191                                                 at = [ at + 1 ];
    4192 
    4193                                 } else if (matchTokens(tokens, at, 'comment')) {
    4194                                         selectors.comment = tokens[at][0];
    4195                                         if (!rule_modifier_specified) {
    4196                                                 // Then it is unknown. Either with unknown explicitly
    4197                                                 // specified or just a comment.
    4198                                                 selectors.meaning = false;
    4199                                                 selectors.unknown = true;
    4200                                         }
    4201 
    4202                                         rule_modifier_specified = true;
    4203                                         at++;
    4204                                         if (typeof tokens[at] === 'object' && tokens[at][0] === ',') // additional rule
    4205                                                 at = [ at + 1 ];
    4206                                 } else if ((at === 0 || at === tokens.length - 1) && matchTokens(tokens, at, 'rule separator')) {
    4207                                         at++;
    4208                                         console.log("value: " + nrule);
    4209                                         // throw formatLibraryBugMessage('Not implemented yet.');
    4210                                 } else {
    4211                                         var warnings = getWarnings();
    4212                                         throw formatWarnErrorMessage(nrule, at, 'Unexpected token: "' + tokens[at][1]
    4213                                                 + '" This means that the syntax is not valid at that point or it is currently not supported.')
    4214                                                 + (warnings ? (' ' + warnings.join('; ')) : '');
    4215                                 }
    4216 
    4217                                 if (typeof at === 'object') { // additional rule
    4218                                         tokens[at[0] - 1][1] = 'rule separator';
    4219                                         break;
    4220                                 }
    4221                         }
    4222 
    4223                         return at;
    4224                 }
    4225 
    4226                 function get_last_token_pos_in_token_group(tokens, at, last_at) {
    4227                         for (at++; at < last_at; at++) {
    4228                                 if (typeof tokens[at] !== 'undefined') {
    4229                                         if (typeof tokens[at][3] === 'string'
    4230                                                         || tokens[at][1] === 'comment'
    4231                                                         || tokens[at][1] === 'state'){
    4232 
    4233                                                         return at - 1;
    4234                                         }
    4235                                 }
    4236                         }
    4237                         return last_at;
    4238                 }
    4239                 // }}}
    4240 
    4241                 // helper functions for sub parser {{{
    4242 
    4243                 /* For given date, returns date moved to the start of the day with an offset specified in minutes. {{{
    4244                  * For example, if date is 2014-05-19_18:17:12, dateAtDayMinutes would
    4245                  * return 2014-05-19_02:00:00 for minutes=120.
    4246                  *
    4247                  * :param date: Date object.
    4248                  * :param minutes: Minutes used as offset starting from midnight of current day.
    4249                  * :returns: Moved date object.
    4250                  */
    4251                 function dateAtDayMinutes(date, minutes) {
    4252                         return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, minutes);
    4253                 }
    4254                 // }}}
    4255 
    4256                 /* For given date, returns date moved to the specific day of week {{{
    4257                  *
    4258                  * :param date: Date object.
    4259                  * :param weekday: Integer number for day of week. Starting with zero (Sunday).
    4260                  * :returns: Moved date object.
    4261                  */
    4262                 function dateAtNextWeekday(date, weekday) {
    4263                         var delta = weekday - date.getDay();
    4264                         return new Date(date.getFullYear(), date.getMonth(), date.getDate() + delta + (delta < 0 ? 7 : 0));
    4265                 }
    4266                 // }}}
    4267 
    4268                 /* Function to determine whether an array contains a value {{{
    4269                  * Source: http://stackoverflow.com/a/1181586
    4270                  *
    4271                  * :param needle: Element to find.
    4272                  * :returns: Index of element if present, if not present returns -1.
    4273                  */
    4274                 function indexOf(needle) {
    4275                         if(typeof Array.prototype.indexOf === 'function') {
    4276                                 indexOf = Array.prototype.indexOf;
    4277                         } else {
    4278                                 indexOf = function(needle) {
    4279                                         var i = -1, index = -1;
    4280                                         for(i = 0; i < this.length; i++) {
    4281                                                 if(this[i] === needle) {
    4282                                                         index = i;
    4283                                                         break;
    4284                                                 }
    4285                                         }
    4286                                         return index;
    4287                                 };
    4288                         }
    4289                         return indexOf.call(this, needle);
    4290                 }
    4291                 // }}}
    4292 
    4293                 /* Numeric list parser (1,2,3-4,-1) {{{
    4294                  * Used in weekday parser above.
    4295                  *
    4296                  * :param tokens: List of token objects.
    4297                  * :param at: Position where to start.
    4298                  * :param func: Function func(from, to, at).
    4299                  * :returns: Position at which the token does not belong to the list any more.
    4300                  */
    4301                 function parseNumRange(tokens, at, func) {
    4302                         for (; at < tokens.length; at++) {
    4303                                 if (matchTokens(tokens, at, 'number', '-', 'number')) {
    4304                                         // Number range
    4305                                         func(tokens[at][0], tokens[at+2][0], at);
    4306                                         at += 3;
    4307                                 } else if (matchTokens(tokens, at, '-', 'number')) {
    4308                                         // Negative number
    4309                                         func(-tokens[at+1][0], -tokens[at+1][0], at);
    4310                                         at += 2;
    4311                                 } else if (matchTokens(tokens, at, 'number')) {
    4312                                         // Single number
    4313                                         func(tokens[at][0], tokens[at][0], at);
    4314                                         at++;
    4315                                 } else {
    4316                                         throw formatWarnErrorMessage(nrule, at + matchTokens(tokens, at, '-'),
    4317                                                 'Unexpected token in number range: ' + tokens[at][1]);
    4318                                 }
    4319 
    4320                                 if (!matchTokens(tokens, at, ','))
    4321                                         break;
    4322                         }
    4323 
    4324                         return at;
    4325                 }
    4326                 // }}}
    4327 
    4328                 /* List parser for constrained weekdays in month range {{{
    4329                  * e.g. Su[-1] which selects the last Sunday of the month.
    4330                  *
    4331                  * :param tokens: List of token objects.
    4332                  * :param at: Position where to start.
    4333                  * :returns: Array:
    4334                  *                      0. Constrained weekday number.
    4335                  *                      1. Position at which the token does not belong to the list any more (after ']' token).
    4336                  */
    4337                 function getConstrainedWeekday(tokens, at) {
    4338                         var number = 0;
    4339                         var endat = parseNumRange(tokens, at, function(from, to, at) {
    4340 
    4341                                 // bad number
    4342                                 if (from === 0 || from < -5 || from > 5)
    4343                                         throw formatWarnErrorMessage(nrule, at,
    4344                                                 'Number between -5 and 5 (except 0) expected');
    4345 
    4346                                 if (from === to) {
    4347                                         if (number !== 0)
    4348                                                 throw formatWarnErrorMessage(nrule, at,
    4349                                                         'You can not use more than one constrained weekday in a month range');
    4350                                         number = from;
    4351                                 } else {
    4352                                         throw formatWarnErrorMessage(nrule, at+2,
    4353                                                 'You can not use a range of constrained weekdays in a month range');
    4354                                 }
    4355                         });
    4356 
    4357                         if (!matchTokens(tokens, endat, ']'))
    4358                                 throw formatWarnErrorMessage(nrule, endat, '"]" expected.');
    4359 
    4360                         return [ number, endat + 1 ];
    4361                 }
    4362                 // }}}
    4363 
    4364                 // Check if period is ok. Period 0 or 1 don’t make much sense.
    4365                 function checkPeriod(at, period, period_type, parm_string) {
    4366                         if (done_with_warnings)
    4367                                 return;
    4368 
    4369                         if (period === 0) {
    4370                                 throw formatWarnErrorMessage(nrule, at,
    4371                                         'You can not use '+ period_type +' ranges with period equals zero.');
    4372                         } else if (period === 1) {
    4373                                 if (typeof parm_string === 'string' && parm_string === 'no_end_year')
    4374                                         parsing_warnings.push([nrule, at,
    4375                                                 'Please don’t use '+ period_type +' ranges with period equals one.'
    4376                                                 + ' If you want to express that a facility is open starting from a year without limit use "<year>+".']);
    4377                                 else
    4378                                         parsing_warnings.push([nrule, at,
    4379                                                 'Please don’t use '+ period_type +' ranges with period equals one.']);
    4380                         }
    4381                 }
    4382 
    4383                 /* Get date moved to constrained weekday (and moved for add_days. {{{
    4384                  * E.g. used for 'Aug Su[-1] -1 day'.
    4385                  *
    4386                  * :param year: Year as integer.
    4387                  * :param month: Month as integer starting with zero.
    4388                  * :param weekday: Integer number for day of week. Starting with zero (Sunday).
    4389                  * :param constrained_weekday: Position where to start.
    4390                  * :returns: Date object.
    4391                  */
    4392                 function getDateForConstrainedWeekday(year, month, weekday, constrained_weekday, add_days) {
    4393                         var tmp_date = dateAtNextWeekday(
    4394                                 new Date(year, month + (constrained_weekday[0] > 0 ? 0 : 1), 1), weekday);
    4395 
    4396                         tmp_date.setDate(tmp_date.getDate() + (constrained_weekday[0] + (constrained_weekday[0] > 0 ? -1 : 0)) * 7);
    4397 
    4398                         if (typeof add_days !== 'undefined' && add_days[1])
    4399                                 tmp_date.setDate(tmp_date.getDate() + add_days[0]);
    4400 
    4401                         return tmp_date;
    4402                 }
    4403                 // }}}
    4404 
    4405                 /* Check if date is valid. {{{
    4406                  *
    4407                  * :param month: Month as integer starting with zero.
    4408                  * :param date: Day of month as integer.
    4409                  * :returns: undefined. There is no real return value. This function just throws an exception if something is wrong.
    4410                  */
    4411                 function checkIfDateIsValid(month, day, nrule, at) {
    4412                         // May use this instead. The problem is that this does not give feedback as precise as the code which is used in this function.
    4413                         // var testDate = new Date(year, month, day);
    4414                         // if (testDate.getDate() !== day || testDate.getMonth() !== month || testDate.getFullYear() !== year) {
    4415                         //      console.error('date not valid');
    4416                         // }
    4417 
    4418                         // https://en.wikipedia.org/wiki/Month#Julian_and_Gregorian_calendars
    4419                         if (day < 1 || day > 31)
    4420                                 throw formatWarnErrorMessage(nrule, at, 'Day must be between 1 and 31.');
    4421                         if ((month===3 || month===5 || month===8 || month===10) && day===31)
    4422                                 throw formatWarnErrorMessage(nrule, at, 'Month ' + months[month] + " doesn't have 31 days.!");
    4423                         if (month === 1 && day === 30)
    4424                                 throw formatWarnErrorMessage(nrule, at, 'Month ' + months[1]+ " either has 28 or 29 days (leap years).");
    4425                 }
    4426                 // }}}
    4427                 // }}}
    4428 
    4429                 /* Time range parser (10:00-12:00,14:00-16:00) {{{
    4430                  *
    4431                  * :param tokens: List of token objects.
    4432                  * :param at: Position where to start.
    4433                  * :param selectors: Reference to selector object.
    4434                  * :param extended_open_end: Used for combined time range with open end.
    4435                  * extended_open_end: <time> - <time> +
    4436                  *            param at is here A (if extended_open_end is true)
    4437                  * :returns: Position at which the token does not belong to the selector anymore.
    4438                  */
    4439                 function parseTimeRange(tokens, at, selectors, extended_open_end) {
    4440                         if (!extended_open_end)
    4441                                 tokens[at][3] = 'time';
    4442 
    4443                         for (; at < tokens.length; at++) {
    4444                                 var has_time_var_calc = [], has_normal_time = []; // element 0: start time, 1: end time
    4445                                         has_normal_time[0]   = matchTokens(tokens, at, 'number', 'timesep', 'number');
    4446                                         has_time_var_calc[0] = matchTokens(tokens, at, '(', 'timevar');
    4447                                 var minutes_from,
    4448                                         minutes_to;
    4449                                 if (has_normal_time[0] || matchTokens(tokens, at, 'timevar') || has_time_var_calc[0]) {
    4450                                         // relying on the fact that always *one* of them is true
    4451 
    4452                                         var is_point_in_time = false; // default no time range
    4453                                         var has_open_end     = false; // default no open end
    4454                                         var timevar_add      = [ 0, 0 ];
    4455                                         var timevar_string   = [];    // capture timevar string like 'sunrise' to calculate it for the current date.
    4456                                         var point_in_time_period;
    4457 
    4458                                         // minutes_from
    4459                                         if (has_normal_time[0]) {
    4460                                                 minutes_from = getMinutesByHoursMinutes(tokens, nrule, at+has_time_var_calc[0]);
    4461                                         } else {
    4462                                                 timevar_string[0] = tokens[at+has_time_var_calc[0]][0];
    4463                                                 minutes_from = word_value_replacement[timevar_string[0]];
    4464 
    4465                                                 if (has_time_var_calc[0]) {
    4466                                                         timevar_add[0] = parseTimevarCalc(tokens, at);
    4467                                                         minutes_from += timevar_add[0];
    4468                                                 }
    4469                                         }
    4470 
    4471                                         var at_end_time = at+(has_normal_time[0] ? 3 : (has_time_var_calc[0] ? 7 : 1))+1; // after '-'
    4472                                         if (!matchTokens(tokens, at_end_time - 1, '-')) { // not time range
    4473                                                 if (matchTokens(tokens, at_end_time - 1, '+')) {
    4474                                                         has_open_end = true;
    4475                                                 } else {
    4476                                                         if (oh_mode === 0) {
    4477                                                                 throw formatWarnErrorMessage(nrule,
    4478                                                                         at+(
    4479                                                                                 has_normal_time[0] ? (
    4480                                                                                         typeof tokens[at+3] === 'object' ? 3 : 2
    4481                                                                                 ) : (
    4482                                                                                         has_time_var_calc[0] ? 2 : (
    4483                                                                                                         typeof tokens[at+1] !== 'undefined' ? 1 : 0
    4484                                                                                                 )
    4485                                                                                 )
    4486                                                                         ),
    4487                                                                         'hyphen (-) or open end (+) in time range '
    4488                                                                         + (has_time_var_calc[0] ? 'calculation ' : '') + 'expected.'
    4489                                                                         + ' For working with points in time, the mode for ' + library_name + ' has to be altered.'
    4490                                                                         + ' Maybe wrong tag?');
    4491                                                         } else {
    4492                                                                 minutes_to = minutes_from + 1;
    4493                                                                 is_point_in_time = true;
    4494                                                         }
    4495                                                 }
    4496                                         }
    4497 
    4498                                         // minutes_to
    4499                                         if (has_open_end) {
    4500                                                 if (extended_open_end === 1)
    4501                                                         minutes_from += minutes_in_day;
    4502                                                 if (minutes_from >= 22 * 60)
    4503                                                         minutes_to = minutes_from +  8 * 60;
    4504                                                 else if (minutes_from >= 17 * 60)
    4505                                                         minutes_to = minutes_from + 10 * 60;
    4506                                                 else
    4507                                                         minutes_to = minutes_in_day;
    4508                                         } else if (!is_point_in_time) {
    4509                                                 has_normal_time[1] = matchTokens(tokens, at_end_time, 'number', 'timesep', 'number');
    4510                                                 has_time_var_calc[1]      = matchTokens(tokens, at_end_time, '(', 'timevar');
    4511                                                 if (!has_normal_time[1] && !matchTokens(tokens, at_end_time, 'timevar') && !has_time_var_calc[1]) {
    4512                                                         throw formatWarnErrorMessage(nrule, at_end_time - (typeof tokens[at_end_time] !== 'undefined' ? 0 : 1),
    4513                                                                         'Time range does not continue as expected');
    4514                                                 } else {
    4515                                                         if (has_normal_time[1]) {
    4516                                                                 minutes_to = getMinutesByHoursMinutes(tokens, nrule, at_end_time);
    4517                                                         } else {
    4518                                                                 timevar_string[1] = tokens[at_end_time+has_time_var_calc[1]][0];
    4519                                                                 minutes_to = word_value_replacement[timevar_string[1]];
    4520                                                         }
    4521 
    4522                                                         if (has_time_var_calc[1]) {
    4523                                                                 timevar_add[1] = parseTimevarCalc(tokens, at_end_time);
    4524                                                                 minutes_to += timevar_add[1];
    4525                                                         }
    4526                                                 }
    4527                                         }
    4528 
    4529                                         at = at_end_time + (is_point_in_time ? -1 :
    4530                                                         (has_normal_time[1] ? 3 : (has_time_var_calc[1] ? 7 : !has_open_end))
    4531                                                 );
    4532 
    4533                                         if (matchTokens(tokens, at, '/', 'number')) {
    4534                                                 if (matchTokens(tokens, at + 2, 'timesep', 'number')) { // /hours:minutes
    4535                                                         point_in_time_period = getMinutesByHoursMinutes(tokens, nrule, at + 1);
    4536                                                         at += 4;
    4537                                                 } else { // /minutes
    4538                                                         point_in_time_period = tokens[at + 1][0];
    4539                                                         at += 2;
    4540                                                         if (matchTokens(tokens, at, 'timesep'))
    4541                                                                 throw formatWarnErrorMessage(nrule, at,
    4542                                                                         'Time period does not continue as expected. Exampe "/01:30".');
    4543                                                 }
    4544 
    4545                                                 // Check at this later state in the if condition to get the correct position.
    4546                                                 if (oh_mode === 0)
    4547                                                         throw formatWarnErrorMessage(nrule, at - 1,
    4548                                                                 'opening_hours is running in "time range mode". Found point in time.');
    4549 
    4550                                                 is_point_in_time = true;
    4551                                         } else if (matchTokens(tokens, at, '+')) {
    4552                                                 parseTimeRange(tokens, at_end_time, selectors, minutes_to < minutes_from ? 1 : true);
    4553                                                 at++;
    4554                                         } else if (oh_mode === 1 && !is_point_in_time) {
    4555                                                 throw formatWarnErrorMessage(nrule, at_end_time,
    4556                                                         'opening_hours is running in "points in time mode". Found time range.');
    4557                                         }
    4558 
    4559                                         if (typeof lat !== 'undefined') { // lon will also be defined (see above)
    4560                                                 if (!has_normal_time[0] || !(has_normal_time[1] || has_open_end || is_point_in_time) )
    4561                                                         week_stable = false;
    4562                                         } else { // we can not calculate exact times so we use the already applied constants (word_value_replacement).
    4563                                                 timevar_string = [];
    4564                                         }
    4565 
    4566                                         // Normalize minutes into range.
    4567                                         if (!extended_open_end && minutes_from >= minutes_in_day)
    4568                                                 throw formatWarnErrorMessage(nrule, at_end_time - 2,
    4569                                                         'Time range starts outside of the current day');
    4570                                         if (minutes_to < minutes_from || ((has_normal_time[0] && has_normal_time[1]) && minutes_from === minutes_to))
    4571                                                 minutes_to += minutes_in_day;
    4572                                         if (minutes_to > minutes_in_day * 2)
    4573                                                 throw formatWarnErrorMessage(nrule, at_end_time + (has_normal_time[1] ? 4 : (has_time_var_calc[1] ? 7 : 1)) - 2,
    4574                                                         'Time spanning more than two midnights not supported');
    4575 
    4576                                         // This shortcut makes always-open range check faster.
    4577                                         if (minutes_from === 0 && minutes_to === minutes_in_day) {
    4578                                                 selectors.time.push(function(date) { return [true]; });
    4579                                         } else {
    4580                                                 if (minutes_to > minutes_in_day) { // has_normal_time[1] must be true
    4581                                                         selectors.time.push(function(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period, extended_open_end) { return function(date) {
    4582                                                                 var ourminutes = date.getHours() * 60 + date.getMinutes();
    4583 
    4584                                                                 if (timevar_string[0]) {
    4585                                                                         var date_from = SunCalc.getTimes(date, lat, lon)[timevar_string[0]];
    4586                                                                         minutes_from  = date_from.getHours() * 60 + date_from.getMinutes() + timevar_add[0];
    4587                                                                 }
    4588                                                                 if (timevar_string[1]) {
    4589                                                                         var date_to = SunCalc.getTimes(date, lat, lon)[timevar_string[1]];
    4590                                                                         minutes_to  = date_to.getHours() * 60 + date_to.getMinutes() + timevar_add[1];
    4591                                                                         minutes_to += minutes_in_day;
    4592                                                                         // Needs to be added because it was added by
    4593                                                                         // normal times: if (minutes_to < minutes_from)
    4594                                                                         // above the selector construction.
    4595                                                                 } else if (is_point_in_time && typeof point_in_time_period !== 'number') {
    4596                                                                         minutes_to = minutes_from + 1;
    4597                                                                 }
    4598 
    4599                                                                 if (typeof point_in_time_period === 'number') {
    4600                                                                         if (ourminutes < minutes_from) {
    4601                                                                                 return [false, dateAtDayMinutes(date, minutes_from)];
    4602                                                                         } else if (ourminutes <= minutes_to) {
    4603                                                                                 for (var cur_min = minutes_from; ourminutes + point_in_time_period >= cur_min; cur_min += point_in_time_period) {
    4604                                                                                         if (cur_min === ourminutes) {
    4605                                                                                                 return [true, dateAtDayMinutes(date, ourminutes + 1)];
    4606                                                                                         } else if (ourminutes < cur_min) {
    4607                                                                                                 return [false, dateAtDayMinutes(date, cur_min)];
    4608                                                                                         }
    4609                                                                                 }
    4610                                                                         }
    4611                                                                         return [false, dateAtDayMinutes(date, minutes_in_day)];
    4612                                                                 } else {
    4613                                                                         if (ourminutes < minutes_from)
    4614                                                                                 return [false, dateAtDayMinutes(date, minutes_from)];
    4615                                                                         else
    4616                                                                                 return [true, dateAtDayMinutes(date, minutes_to), has_open_end, extended_open_end];
    4617                                                                 }
    4618                                                         }}(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period, extended_open_end));
    4619 
    4620                                                         selectors.wraptime.push(function(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period, extended_open_end) { return function(date) {
    4621                                                                 var ourminutes = date.getHours() * 60 + date.getMinutes();
    4622 
    4623                                                                 if (timevar_string[0]) {
    4624                                                                         var date_from = SunCalc.getTimes(date, lat, lon)[timevar_string[0]];
    4625                                                                         minutes_from  = date_from.getHours() * 60 + date_from.getMinutes() + timevar_add[0];
    4626                                                                 }
    4627                                                                 if (timevar_string[1]) {
    4628                                                                         var date_to = SunCalc.getTimes(date, lat, lon)[timevar_string[1]];
    4629                                                                         minutes_to  = date_to.getHours() * 60 + date_to.getMinutes() + timevar_add[1];
    4630                                                                         // minutes_in_day does not need to be added.
    4631                                                                         // For normal times in it was added in: if (minutes_to < // minutes_from)
    4632                                                                         // above the selector construction and
    4633                                                                         // subtracted in the selector construction call
    4634                                                                         // which returns the selector function.
    4635                                                                 }
    4636 
    4637                                                                 if (typeof point_in_time_period === 'number') {
    4638                                                                         if (ourminutes <= minutes_to) {
    4639                                                                                 for (var cur_min = 0; ourminutes + point_in_time_period >= cur_min; cur_min += point_in_time_period) {
    4640                                                                                         if (cur_min === ourminutes) {
    4641                                                                                                 return [true, dateAtDayMinutes(date, ourminutes + 1)];
    4642                                                                                         } else if (ourminutes < cur_min) {
    4643                                                                                                 return [false, dateAtDayMinutes(date, cur_min)];
    4644                                                                                         }
    4645                                                                                 }
    4646                                                                         }
    4647                                                                 } else {
    4648                                                                         if (ourminutes < minutes_to)
    4649                                                                                 return [true, dateAtDayMinutes(date, minutes_to), has_open_end, extended_open_end];
    4650                                                                 }
    4651                                                                 return [false, undefined];
    4652                                                         }}(minutes_from, minutes_to - minutes_in_day, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period, extended_open_end));
    4653                                                 } else {
    4654                                                         selectors.time.push(function(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period, extended_open_end) { return function(date) {
    4655                                                                 var ourminutes = date.getHours() * 60 + date.getMinutes();
    4656 
    4657                                                                 if (timevar_string[0]) {
    4658                                                                         var date_from = SunCalc.getTimes(date, lat, lon)[timevar_string[0]];
    4659                                                                         minutes_from  = date_from.getHours() * 60 + date_from.getMinutes() + timevar_add[0];
    4660                                                                 }
    4661                                                                 if (timevar_string[1]) {
    4662                                                                         var date_to = SunCalc.getTimes(date, lat, lon)[timevar_string[1]];
    4663                                                                         minutes_to  = date_to.getHours() * 60 + date_to.getMinutes() + timevar_add[1];
    4664                                                                 } else if (is_point_in_time && typeof point_in_time_period !== 'number') {
    4665                                                                         minutes_to = minutes_from + 1;
    4666                                                                 }
    4667 
    4668                                                                 if (typeof point_in_time_period === 'number') {
    4669                                                                         if (ourminutes < minutes_from) {
    4670                                                                                 return [false, dateAtDayMinutes(date, minutes_from)];
    4671                                                                         } else if (ourminutes <= minutes_to) {
    4672                                                                                 for (var cur_min = minutes_from; ourminutes + point_in_time_period >= cur_min; cur_min += point_in_time_period) {
    4673                                                                                         if (cur_min === ourminutes) {
    4674                                                                                                 return [true, dateAtDayMinutes(date, ourminutes + 1)];
    4675                                                                                         } else if (ourminutes < cur_min) {
    4676                                                                                                 return [false, dateAtDayMinutes(date, cur_min)];
    4677                                                                                         }
    4678                                                                                 }
    4679                                                                         }
    4680                                                                         return [false, dateAtDayMinutes(date, minutes_in_day)];
    4681                                                                 } else {
    4682                                                                         if (ourminutes < minutes_from)
    4683                                                                                 return [false, dateAtDayMinutes(date, minutes_from)];
    4684                                                                         else if (ourminutes < minutes_to)
    4685                                                                                 return [true, dateAtDayMinutes(date, minutes_to), has_open_end];
    4686                                                                         else
    4687                                                                                 return [false, dateAtDayMinutes(date, minutes_from + minutes_in_day)];
    4688                                                                 }
    4689                                                         }}(minutes_from, minutes_to, timevar_string, timevar_add, has_open_end, is_point_in_time, point_in_time_period, extended_open_end));
    4690                                                 }
    4691                                         }
    4692 
    4693                                 } else if (matchTokens(tokens, at, 'number', '-', 'number')) { // "Mo 09-18" (Please don’t use this) -> "Mo 09:00-18:00".
    4694                                         minutes_from = tokens[at][0]   * 60;
    4695                                         minutes_to   = tokens[at+2][0] * 60;
    4696                                         if (!done_with_warnings)
    4697                                                 parsing_warnings.push([nrule, at + 2,
    4698                                                         'Time range without minutes specified. Not very explicit!'
    4699                                                         + ' Please use this syntax instead "'
    4700                                                         + (tokens[at][0]   < 10 ? '0' : '') + tokens[at][0]   + ':00-'
    4701                                                         + (tokens[at+2][0] < 10 ? '0' : '') + tokens[at+2][0] + ':00".']);
    4702 
    4703                                         if (minutes_from >= minutes_in_day)
    4704                                                 throw formatWarnErrorMessage(nrule, at,
    4705                                                         'Time range starts outside of the current day');
    4706                                         if (minutes_to < minutes_from)
    4707                                                 minutes_to += minutes_in_day;
    4708                                         if (minutes_to > minutes_in_day * 2)
    4709                                                 throw formatWarnErrorMessage(nrule, at + 2,
    4710                                                         'Time spanning more than two midnights not supported');
    4711 
    4712                                         if (minutes_to > minutes_in_day) {
    4713                                                 selectors.time.push(function(minutes_from, minutes_to) { return function(date) {
    4714                                                         var ourminutes = date.getHours() * 60 + date.getMinutes();
    4715 
    4716                                                         if (ourminutes < minutes_from)
    4717                                                                 return [false, dateAtDayMinutes(date, minutes_from)];
    4718                                                         else
    4719                                                                 return [true, dateAtDayMinutes(date, minutes_to)];
    4720                                                 }}(minutes_from, minutes_to));
    4721 
    4722                                                 selectors.wraptime.push(function(minutes_from, minutes_to) { return function(date) {
    4723                                                         var ourminutes = date.getHours() * 60 + date.getMinutes();
    4724 
    4725                                                         if (ourminutes < minutes_to)
    4726                                                                 return [true, dateAtDayMinutes(date, minutes_to)];
    4727                                                         else
    4728                                                                 return [false, undefined];
    4729                                                 }}(minutes_from, minutes_to - minutes_in_day));
    4730                                         } else {
    4731                                                 selectors.time.push(function(minutes_from, minutes_to) { return function(date) {
    4732                                                         var ourminutes = date.getHours() * 60 + date.getMinutes();
    4733 
    4734                                                         if (ourminutes < minutes_from)
    4735                                                                 return [false, dateAtDayMinutes(date, minutes_from)];
    4736                                                         else if (ourminutes < minutes_to)
    4737                                                                 return [true, dateAtDayMinutes(date, minutes_to), has_open_end];
    4738                                                         else
    4739                                                                 return [false, dateAtDayMinutes(date, minutes_from + minutes_in_day)];
    4740                                                 }}(minutes_from, minutes_to));
    4741                                         }
    4742 
    4743                                         at += 3;
    4744                                 } else { // additional rule
    4745                                         if (matchTokens(tokens, at, '('))
    4746                                                 throw formatWarnErrorMessage(nrule, at, 'Missing variable time (e.g. sunrise) after: "' + tokens[at][1] + '"');
    4747                                         if (matchTokens(tokens, at, 'number', 'timesep'))
    4748                                                 throw formatWarnErrorMessage(nrule, at+1, 'Missing minutes in time range after: "' + tokens[at+1][1] + '"');
    4749                                         if (matchTokens(tokens, at, 'number'))
    4750                                                 throw formatWarnErrorMessage(nrule, at + (typeof tokens[at+1] !== 'undefined' ? 1 : 0),
    4751                                                                 'Missing time separator in time range after: "' + tokens[at][1] + '"');
    4752                                         return [ at ];
    4753                                 }
    4754 
    4755                                 if (!matchTokens(tokens, at, ','))
    4756                                         break;
    4757                         }
    4758 
    4759                         return at;
    4760                 }
    4761                 // }}}
    4762 
    4763                 /* Helpers for time range parser {{{ */
    4764 
    4765                 /* Get time in minutes from <hour>:<minute> (tokens). {{{
    4766                  * Only used if throwing an error is wanted.
    4767                  *
    4768                  * :param tokens: List of token objects.
    4769                  * :param nrule: Rule number starting with 0.
    4770                  * :param at: Position at which the time begins.
    4771                  * :returns: Time in minutes.
    4772                  */
    4773                 function getMinutesByHoursMinutes(tokens, nrule, at) {
    4774                         if (tokens[at+2][0] > 59)
    4775                                 throw formatWarnErrorMessage(nrule, at+2,
    4776                                                 'Minutes are greater than 59.');
    4777                         return tokens[at][0] * 60 + tokens[at+2][0];
    4778                 }
    4779                 // }}}
    4780 
    4781                 /* Get time in minutes from "(sunrise-01:30)" {{{
    4782                  * Extract the added or subtracted time from "(sunrise-01:30)"
    4783                  * returns time in minutes e.g. -90.
    4784                  *
    4785                  * :param tokens: List of token objects.
    4786                  * :param at: Position where the specification for the point in time could be.
    4787                  * :returns: Time in minutes on suggest, throws an exception otherwise.
    4788                 */
    4789                 function parseTimevarCalc(tokens, at) {
    4790                         var error;
    4791                         if (matchTokens(tokens, at+2, '+') || matchTokens(tokens, at+2, '-')) {
    4792                                 if (matchTokens(tokens, at+3, 'number', 'timesep', 'number')) {
    4793                                         if (matchTokens(tokens, at+6, ')')) {
    4794                                                 var add_or_subtract = tokens[at+2][0] === '+' ? '1' : '-1';
    4795                                                 var minutes = getMinutesByHoursMinutes(tokens, nrule, at+3) * add_or_subtract;
    4796                                                 if (minutes === 0)
    4797                                                         parsing_warnings.push([ nrule, at+5, 'Adding zero in a variable time calculation does not change the variable time.'
    4798                                                                         + ' Please omit the calculation (example: "sunrise-(sunset-00:00)").' ]
    4799                                                                 );
    4800                                                 return minutes;
    4801                                         } else {
    4802                                                 error = [ at+6, '. Missing ")".'];
    4803                                         }
    4804                                 } else {
    4805                                         error = [ at+5, ' (time).'];
    4806                                 }
    4807                         } else {
    4808                                 error = [ at+2, '. "+" or "-" expected.'];
    4809                         }
    4810 
    4811                         if (error)
    4812                                 throw formatWarnErrorMessage(nrule, error[0],
    4813                                         'Calculcation with variable time is not in the right syntax' + error[1]);
    4814                 }
    4815                 /* }}} */
    4816                 /* }}} */
    4817 
    4818                 /* Weekday range parser (Mo,We-Fr,Sa[1-2,-1],PH). {{{
    4819                  *
    4820                  * :param tokens: List of token objects.
    4821                  * :param at: Position where the weekday tokens could be.
    4822                  * :param selectors: Reference to selector object.
    4823                  * :returns: Position at which the token does not belong to the selector anymore.
    4824                  */
    4825                 function parseWeekdayRange(tokens, at, selectors, in_holiday_selector) {
    4826                         if (!in_holiday_selector) {
    4827                                 in_holiday_selector = true;
    4828                                 tokens[at][3] = 'weekday';
    4829                         }
    4830 
    4831                         for (; at < tokens.length; at++) {
    4832                                 if (matchTokens(tokens, at, 'weekday', '[')) {
    4833                                         // Conditional weekday (Mo[3])
    4834                                         var numbers = [];
    4835 
    4836                                         // Get list of constraints
    4837                                         var endat = parseNumRange(tokens, at+2, function(from, to, at) {
    4838 
    4839                                                 // bad number
    4840                                                 if (from === 0 || from < -5 || from > 5)
    4841                                                         throw formatWarnErrorMessage(nrule, at,
    4842                                                                 'Number between -5 and 5 (except 0) expected');
    4843 
    4844                                                 if (from === to) {
    4845                                                         numbers.push(from);
    4846                                                 } else if (from < to) {
    4847                                                         for (var i = from; i <= to; i++) {
    4848                                                                 // bad number
    4849                                                                 if (i === 0 || i < -5 || i > 5)
    4850                                                                         throw formatWarnErrorMessage(nrule, at+2,
    4851                                                                                 'Number between -5 and 5 (except 0) expected.');
    4852 
    4853                                                                 numbers.push(i);
    4854                                                         }
    4855                                                 } else {
    4856                                                         throw formatWarnErrorMessage(nrule, at+2,
    4857                                                                 'Bad range: ' + from + '-' + to);
    4858                                                 }
    4859                                         });
    4860 
    4861                                         if (!matchTokens(tokens, endat, ']'))
    4862                                                 throw formatWarnErrorMessage(nrule, endat, '"]" or more numbers expected.');
    4863 
    4864                                         var add_days = getMoveDays(tokens, endat+1, 6, 'constrained weekdays');
    4865                                         week_stable = false;
    4866 
    4867                                         // Create selector for each list element.
    4868                                         for (var nnumber = 0; nnumber < numbers.length; nnumber++) {
    4869 
    4870                                                 selectors.weekday.push(function(weekday, number, add_days) { return function(date) {
    4871                                                         var date_num = getValueForDate(date, false); // Year not needed to distinguish.
    4872                                                         var start_of_this_month = new Date(date.getFullYear(), date.getMonth(), 1);
    4873                                                         var start_of_next_month = new Date(date.getFullYear(), date.getMonth() + 1, 1);
    4874 
    4875                                                         var target_day_this_month;
    4876 
    4877                                                         target_day_this_month = getDateForConstrainedWeekday(date.getFullYear(), date.getMonth(), weekday, [ number ]);
    4878 
    4879                                                         var target_day_with_added_days_this_month = new Date(target_day_this_month.getFullYear(),
    4880                                                                 target_day_this_month.getMonth(), target_day_this_month.getDate() + add_days);
    4881 
    4882                                                         // The target day with added days can be before this month
    4883                                                         if (target_day_with_added_days_this_month.getTime() < start_of_this_month.getTime()) {
    4884                                                                 // but in this case, the target day without the days added needs to be in this month
    4885                                                                 if (target_day_this_month.getTime() >= start_of_this_month.getTime()) {
    4886                                                                         // so we calculate it for the month
    4887                                                                         // following this month and hope that the
    4888                                                                         // target day will actually be this month.
    4889 
    4890                                                                         target_day_with_added_days_this_month = dateAtNextWeekday(
    4891                                                                                 new Date(date.getFullYear(), date.getMonth() + (number > 0 ? 0 : 1) + 1, 1), weekday);
    4892                                                                         target_day_this_month.setDate(target_day_with_added_days_this_month.getDate()
    4893                                                                                 + (number + (number > 0 ? -1 : 0)) * 7 + add_days);
    4894                                                                 } else {
    4895                                                                         // Calculated target day is not inside this month
    4896                                                                         // therefore the specified weekday (e.g. fifth Sunday)
    4897                                                                         // does not exist this month. Try it next month.
    4898                                                                         return [false, start_of_next_month];
    4899                                                                 }
    4900                                                         } else if (target_day_with_added_days_this_month.getTime() >= start_of_next_month.getTime()) {
    4901                                                                 // The target day is in the next month. If the target day without the added days is not in this month
    4902                                                                 if (target_day_this_month.getTime() >= start_of_next_month.getTime())
    4903                                                                         return [false, start_of_next_month];
    4904                                                         }
    4905 
    4906                                                         var target_day_with_added_moved_days_this_month;
    4907                                                         if (add_days > 0) {
    4908                                                                 target_day_with_added_moved_days_this_month = dateAtNextWeekday(
    4909                                                                         new Date(date.getFullYear(), date.getMonth() + (number > 0 ? 0 : 1) -1, 1), weekday);
    4910                                                                 target_day_with_added_moved_days_this_month.setDate(target_day_with_added_moved_days_this_month.getDate()
    4911                                                                         + (number + (number > 0 ? -1 : 0)) * 7 + add_days);
    4912 
    4913                                                                 if (date_num === getValueForDate(target_day_with_added_moved_days_this_month, false))
    4914                                                                         return [true, dateAtDayMinutes(date, minutes_in_day)];
    4915                                                         } else if (add_days < 0) {
    4916                                                                 target_day_with_added_moved_days_this_month = dateAtNextWeekday(
    4917                                                                         new Date(date.getFullYear(), date.getMonth() + (number > 0 ? 0 : 1) + 1, 1), weekday);
    4918                                                                 target_day_with_added_moved_days_this_month.setDate(target_day_with_added_moved_days_this_month.getDate()
    4919                                                                         + (number + (number > 0 ? -1 : 0)) * 7 + add_days);
    4920 
    4921                                                                 if (target_day_with_added_moved_days_this_month.getTime() >= start_of_next_month.getTime()) {
    4922                                                                         if (target_day_with_added_days_this_month.getTime() >= start_of_next_month.getTime())
    4923                                                                                 return [false, target_day_with_added_moved_days_this_month];
    4924                                                                 } else {
    4925                                                                         if (target_day_with_added_days_this_month.getTime() < start_of_next_month.getTime()
    4926                                                                                 && getValueForDate(target_day_with_added_days_this_month, false) === date_num)
    4927                                                                                 return [true, dateAtDayMinutes(date, minutes_in_day)];
    4928 
    4929                                                                         target_day_with_added_days_this_month = target_day_with_added_moved_days_this_month;
    4930                                                                 }
    4931                                                         }
    4932 
    4933                                                         // we hit the target day
    4934                                                         if (date.getDate() === target_day_with_added_days_this_month.getDate()) {
    4935                                                                 return [true, dateAtDayMinutes(date, minutes_in_day)];
    4936                                                         }
    4937 
    4938                                                         // we're before target day
    4939                                                         if (date.getDate() < target_day_with_added_days_this_month.getDate()) {
    4940                                                                 return [false, target_day_with_added_days_this_month];
    4941                                                         }
    4942 
    4943                                                         // we're after target day, set check date to next month
    4944                                                         return [false, start_of_next_month];
    4945                                                 }}(tokens[at][0], numbers[nnumber], add_days[0]));
    4946                                         }
    4947 
    4948                                         at = endat + 1 + add_days[1];
    4949                                 } else if (matchTokens(tokens, at, 'weekday')) {
    4950                                         // Single weekday (Mo) or weekday range (Mo-Fr)
    4951                                         var is_range = matchTokens(tokens, at+1, '-', 'weekday');
    4952 
    4953                                         var weekday_from = tokens[at][0];
    4954                                         var weekday_to = is_range ? tokens[at+2][0] : weekday_from;
    4955 
    4956                                         var inside = true;
    4957 
    4958                                         // handle reversed range
    4959                                         if (weekday_to < weekday_from) {
    4960                                                 var tmp = weekday_to;
    4961                                                 weekday_to = weekday_from - 1;
    4962                                                 weekday_from = tmp + 1;
    4963                                                 inside = false;
    4964                                         }
    4965 
    4966                                         if (weekday_to < weekday_from) { // handle full range
    4967                                                 selectors.weekday.push(function(date) { return [true]; });
    4968                                                 // Not needed. If there is no selector it automatically matches everything.
    4969                                                 // WRONG: This only works if there is no other selector in this selector group ...
    4970                                         } else {
    4971                                                 selectors.weekday.push(function(weekday_from, weekday_to, inside) { return function(date) {
    4972                                                         var ourweekday = date.getDay();
    4973 
    4974                                                         if (ourweekday < weekday_from || ourweekday > weekday_to) {
    4975                                                                 return [!inside, dateAtNextWeekday(date, weekday_from)];
    4976                                                         } else {
    4977                                                                 return [inside, dateAtNextWeekday(date, weekday_to + 1)];
    4978                                                         }
    4979                                                 }}(weekday_from, weekday_to, inside));
    4980                                         }
    4981 
    4982                                         at += is_range ? 3 : 1;
    4983                                 } else if (matchTokens(tokens, at, 'holiday')) {
    4984                                         week_stable = false;
    4985                                         return parseHoliday(tokens, at, selectors, true, in_holiday_selector);
    4986                                 } else if (matchTokens(tokens, at - 1, ',')) { // additional rule
    4987                                         throw formatWarnErrorMessage(
    4988                                                 nrule,
    4989                                                 at - 1,
    4990                                                 'An additional rule does not make sense here. Just use a ";" as rule separator.'
    4991                                                 + ' See https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification#explain:additional_rule_separator');
    4992                                 } else {
    4993                                         throw formatWarnErrorMessage(nrule, at, 'Unexpected token in weekday range: ' + tokens[at][1]);
    4994                                 }
    4995 
    4996                                 if (!matchTokens(tokens, at, ','))
    4997                                         break;
    4998                         }
    4999 
    5000                         return at;
    5001                 }
    5002                 // }}}
    5003 
    5004                 /* Get the number of days a date should be moved (if any). {{{
    5005                  *
    5006                  * :param tokens: List of token objects.
    5007                  * :param at: Position where the date moving tokens could be.
    5008                  * :param max_differ: Maximal number of days to move (could also be zero if there are no day move tokens).
    5009                  * :returns: Array:
    5010                  *                      0. Days to add.
    5011                  *                      1. How many tokens.
    5012                  */
    5013                 function getMoveDays(tokens, at, max_differ, name) {
    5014                         var add_days = [ 0, 0 ]; // [ 'days to add', 'how many tokens' ]
    5015                         add_days[0] = matchTokens(tokens, at, '+') || (matchTokens(tokens, at, '-') ? -1 : 0);
    5016                         if (add_days[0] !== 0 && matchTokens(tokens, at+1, 'number', 'calcday')) {
    5017                                 // continues with '+ 5 days' or something like that
    5018                                 if (tokens[at+1][0] > max_differ)
    5019                                         throw formatWarnErrorMessage(nrule, at+2,
    5020                                                 'There should be no reason to differ more than ' + max_differ + ' days from a ' + name + '. If so tell us …');
    5021                                 add_days[0] *= tokens[at+1][0];
    5022                                 if (add_days[0] === 0 && !done_with_warnings)
    5023                                         parsing_warnings.push([ nrule, at+2, 'Adding 0 does not change the date. Please omit this.' ]);
    5024                                 add_days[1] = 3;
    5025                         } else {
    5026                                 add_days[0] = 0;
    5027                         }
    5028                         return add_days;
    5029                 }
    5030                 // }}}
    5031 
    5032                 /* Holiday parser for public and school holidays (PH,SH) {{{
    5033                  *
    5034                  * :param tokens: List of token objects.
    5035                  * :param at: Position where to start.
    5036                  * :param selectors: Reference to selector object.
    5037                  * :param push_to_weekday: Will push the selector into the weekday selector array which has the desired side effect of working in conjunction with the weekday selectors (either the holiday match or the weekday), which is the normal and expected behavior.
    5038                  * :returns: Position at which the token does not belong to the selector anymore.
    5039                  */
    5040                 function parseHoliday(tokens, at, selectors, push_to_weekday, in_holiday_selector) {
    5041                         if (!in_holiday_selector) {
    5042 
    5043                                 if (push_to_weekday)
    5044                                         tokens[at][3] = 'weekday';
    5045                                 else
    5046                                         tokens[at][3] = 'holiday'; // Could also be holiday but this is not important here.
    5047                         }
    5048 
    5049                         for (; at < tokens.length; at++) {
    5050                                 if (matchTokens(tokens, at, 'holiday')) {
    5051                                         if (tokens[at][0] === 'PH') {
    5052                                                 var applying_holidays = getMatchingHoliday(tokens[at][0]);
    5053 
    5054                                                 // Only allow moving one day in the past or in the future.
    5055                                                 // This makes implementation easier because only one holiday is assumed to be moved to the next year.
    5056                                                 var add_days = getMoveDays(tokens, at+1, 1, 'public holiday');
    5057 
    5058                                                 var selector = function(applying_holidays, add_days) { return function(date) {
    5059 
    5060                                                         var holidays = getApplyingHolidaysForYear(applying_holidays, date.getFullYear(), add_days);
    5061                                                         // Needs to be calculated each time because of movable days.
    5062 
    5063                                                         var date_num = getValueForDate(date, true);
    5064 
    5065                                                         for (var i = 0; i < holidays.length; i++) {
    5066                                                                 var next_holiday_date_num = getValueForDate(holidays[i][0], true);
    5067 
    5068                                                                 if (date_num < next_holiday_date_num) {
    5069 
    5070                                                                         if (add_days[0] > 0) {
    5071                                                                                 // Calculate the last holiday from previous year to tested against it.
    5072                                                                                 var holidays_last_year = getApplyingHolidaysForYear(applying_holidays, date.getFullYear() - 1, add_days);
    5073                                                                                 var last_holiday_last_year = holidays_last_year[holidays_last_year.length - 1];
    5074                                                                                 var last_holiday_last_year_num = getValueForDate(last_holiday_last_year[0], true);
    5075 
    5076                                                                                 if (date_num < last_holiday_last_year_num ) {
    5077                                                                                         return [ false, last_holiday_last_year[0] ];
    5078                                                                                 } else if (date_num === last_holiday_last_year_num) {
    5079                                                                                         return [true, dateAtDayMinutes(last_holiday_last_year[0], minutes_in_day),
    5080                                                                                                 'Day after ' +last_holiday_last_year[1] ];
    5081                                                                                 }
    5082                                                                         }
    5083 
    5084                                                                         return [ false, holidays[i][0] ];
    5085                                                                 } else if (date_num === next_holiday_date_num) {
    5086                                                                         return [true, new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1),
    5087                                                                                 (add_days[0] > 0 ? 'Day after ' : (add_days[0] < 0 ? 'Day before ' : '')) + holidays[i][1] ];
    5088                                                                 }
    5089                                                         }
    5090 
    5091                                                         if (add_days[0] < 0) {
    5092                                                                 // Calculate the first holiday from next year to tested against it.
    5093                                                                 var holidays_next_year = getApplyingHolidaysForYear(applying_holidays, date.getFullYear() + 1, add_days);
    5094                                                                 var first_holidays_next_year = holidays_next_year[0];
    5095                                                                 var first_holidays_next_year_num = getValueForDate(first_holidays_next_year[0], true);
    5096                                                                 if (date_num === first_holidays_next_year_num) {
    5097                                                                         return [true, dateAtDayMinutes(first_holidays_next_year[0], minutes_in_day),
    5098                                                                                 'Day before ' + first_holidays_next_year[1] ];
    5099                                                                 }
    5100                                                         }
    5101 
    5102                                                         // continue next year
    5103                                                         return [ false, new Date(holidays[0][0].getFullYear() + 1,
    5104                                                                         holidays[0][0].getMonth(),
    5105                                                                         holidays[0][0].getDate()) ];
    5106 
    5107                                                 }}(applying_holidays, add_days);
    5108 
    5109                                                 if (push_to_weekday)
    5110                                                         selectors.weekday.push(selector);
    5111                                                 else
    5112                                                         selectors.holiday.push(selector);
    5113 
    5114                                                 at += 1 + add_days[1];
    5115                                         } else if (tokens[at][0] === 'SH') {
    5116                                                 var applying_holidays = getMatchingHoliday(tokens[at][0]);
    5117 
    5118                                                 var holidays = []; // needs to be sorted each time because of movable days
    5119 
    5120                                                 var selector = function(applying_holidays) { return function(date) {
    5121                                                         var date_num = getValueForDate(date);
    5122 
    5123                                                         // Iterate over holiday array containing the different holiday ranges.
    5124                                                         for (var i = 0; i < applying_holidays.length; i++) {
    5125 
    5126                                                                 var holiday = getSHForYear(applying_holidays[i], date.getFullYear());
    5127 
    5128                                                                 for (var h = 0; h < holiday.length; h+=4) {
    5129                                                                         var holiday_to_plus = new Date(date.getFullYear(), holiday[2+h] - 1, holiday[3+h] + 1);
    5130                                                                         var holiday_from = (holiday[0+h] - 1) * 100 + holiday[1+h];
    5131                                                                         var holiday_to   = (holiday[2+h] - 1) * 100 + holiday[3+h];
    5132                                                                         holiday_to_plus  = getValueForDate(holiday_to_plus);
    5133 
    5134                                                                         var holiday_ends_next_year = holiday_to < holiday_from;
    5135 
    5136                                                                         if (date_num < holiday_from) { // date is before selected holiday
    5137 
    5138                                                                                 // check if we are in the holidays from the last year spanning into this year
    5139                                                                                 var last_year_holiday = getSHForYear(applying_holidays[applying_holidays.length - 1], date.getFullYear() - 1, false);
    5140                                                                                 if (typeof last_year_holiday !== 'undefined') {
    5141                                                                                         var last_year_holiday_from = (last_year_holiday[last_year_holiday.length - 4] - 1) * 100
    5142                                                                                                 + last_year_holiday[last_year_holiday.length - 3]; // e.g. 1125
    5143                                                                                         var last_year_holiday_to   = (last_year_holiday[last_year_holiday.length - 2] - 1) * 100
    5144                                                                                                 + last_year_holiday[last_year_holiday.length - 1]; // e.g. 0005
    5145 
    5146                                                                                         if (last_year_holiday_to < last_year_holiday_from && date_num < last_year_holiday_to)
    5147                                                                                                 return [ true, new Date(date.getFullYear(),
    5148                                                                                                         last_year_holiday[last_year_holiday.length - 2] - 1,
    5149                                                                                                         last_year_holiday[last_year_holiday.length - 1] + 1),
    5150                                                                                                         applying_holidays[applying_holidays.length - 1].name ];
    5151                                                                                         else
    5152                                                                                                 return [ false, new Date(date.getFullYear(), holiday[0+h] - 1, holiday[1+h]) ];
    5153                                                                                 } else { // school holidays for last year are not defined.
    5154                                                                                         return [ false, new Date(date.getFullYear(), holiday[0+h] - 1, holiday[1+h]) ];
    5155                                                                                 }
    5156                                                                         } else if (holiday_from <= date_num && (date_num < holiday_to_plus || holiday_ends_next_year)) {
    5157                                                                                 return [ true, new Date(date.getFullYear() + holiday_ends_next_year, holiday[2+h] - 1, holiday[3+h] + 1),
    5158                                                                                         applying_holidays[i].name ];
    5159                                                                         } else if (holiday_to_plus === date_num) { // selected holiday end is equal to month and day
    5160                                                                                 if (h + 4 < holiday.length) { // next holiday is next date range of the same holidays
    5161                                                                                         h += 4;
    5162                                                                                         return [ false, new Date(date.getFullYear(), holiday[0+h] - 1, holiday[1+h]) ];
    5163                                                                                 } else {
    5164                                                                                         if (i + 1 === applying_holidays.length) { // last holidays are handled, continue all over again
    5165                                                                                                 var holiday = getSHForYear(applying_holidays[0], date.getFullYear() + 1);
    5166                                                                                                 return [ false, new Date(date.getFullYear() + !holiday_ends_next_year, holiday[0+h] - 1, holiday[1+h]) ];
    5167                                                                                         } else { // return the start of the next holidays
    5168                                                                                                         var holiday = getSHForYear(applying_holidays[i+1], date.getFullYear());
    5169                                                                                                         return [ false, new Date(date.getFullYear(), holiday[0] - 1, holiday[1]) ];
    5170                                                                                         }
    5171                                                                                 }
    5172                                                                         }
    5173                                                                 }
    5174                                                         }
    5175                                                         return [ false ];
    5176                                                 }}(applying_holidays);
    5177 
    5178                                                 if (push_to_weekday)
    5179                                                         selectors.weekday.push(selector);
    5180                                                 else
    5181                                                         selectors.holiday.push(selector);
    5182                                                 at += 1; // FIXME: test
    5183                                         }
    5184                                 } else if (matchTokens(tokens, at, 'weekday')) {
    5185                                         return parseWeekdayRange(tokens, at, selectors, true);
    5186                                 } else if (matchTokens(tokens, at - 1, ',')) { // additional rule
    5187                                         throw formatWarnErrorMessage(
    5188                                                 nrule,
    5189                                                 at - 1,
    5190                                                 'An additional rule does not make sense here. Just use a ";" as rule separator.'
    5191                                                 + ' See https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification#explain:additional_rule_separator');
    5192                                 } else {
    5193                                         throw formatWarnErrorMessage(nrule, at, 'Unexpected token (holiday parser): ' + tokens[at][1]);
    5194                                 }
    5195 
    5196                                 if (!matchTokens(tokens, at, ','))
    5197                                         break;
    5198                         }
    5199 
    5200                         return at;
    5201                 }
    5202 
    5203                 // Helpers for holiday parsers {{{
    5204 
    5205                 /* Returns a number for a date which can then be used to compare just the dates (without the time). {{{
    5206                  * This is necessary because a selector could be called for the middle of the day and we need to tell if it matches that day.
    5207                  * Example: Returns 20150015 for Jan 01 2015
    5208                  *
    5209                  * :param date: Date object.
    5210                  * :param include_year: Boolean. If true include the year.
    5211                  * :returns: Number for the date.
    5212                  */
    5213                 function getValueForDate(date, include_year) {
    5214                         // Implicit because undefined evaluates to false.
    5215                         // include_year = typeof include_year !== 'undefined' ? include_year : false;
    5216 
    5217                         return (include_year ? date.getFullYear() * 10000 : 0) + date.getMonth() * 100 + date.getDate();
    5218                 }
    5219                 // }}}
    5220 
    5221                 // return the school holiday definition e.g. [ 5, 25, /* to */ 6, 5 ],
    5222                 // for the specified year
    5223                 function getSHForYear(SH_hash, year, fatal) {
    5224                         if (typeof fatal === 'undefined')
    5225                                 fatal = true;
    5226 
    5227                         var holiday = SH_hash[year];
    5228                         if (typeof holiday === 'undefined') {
    5229                                 holiday = SH_hash['default']; // applies for any year without explicit definition
    5230                                 if (typeof holiday === 'undefined') {
    5231                                         if (fatal) {
    5232                                                 throw formatLibraryBugMessage('School holiday ' + SH_hash.name + ' has no definition for the year ' + year + '.'
    5233                                                                 + ' You can also add them: ' + repository_url);
    5234                                         } else {
    5235                                                 return undefined;
    5236                                         }
    5237                                 }
    5238                         }
    5239                         return holiday;
    5240                 }
    5241 
    5242                 // Return closed holiday definition available.
    5243                 // First try to get the state, if missing get the country wide holidays
    5244                 // (which can be limited to some states).
    5245                 function getMatchingHoliday(type_of_holidays) {
    5246                         if (typeof location_cc !== 'undefined') {
    5247                                 if (holidays.hasOwnProperty(location_cc)) {
    5248                                         if (typeof location_state !== 'undefined'
    5249                                                         && holidays[location_cc][location_state]
    5250                                                         && holidays[location_cc][location_state][type_of_holidays]) {
    5251                                                 // if holidays for the state are specified use it
    5252                                                 // and ignore lesser specific ones (for the country)
    5253                                                 return holidays[location_cc][location_state][type_of_holidays];
    5254                                         } else if (holidays[location_cc][type_of_holidays]) {
    5255                                                 // holidays are only defined country wide
    5256                                                 var matching_holiday = {}; // holidays in the country wide scope can be limited to certain states
    5257                                                 for (var holiday_name in holidays[location_cc][type_of_holidays]) {
    5258                                                         if (typeof holidays[location_cc][type_of_holidays][holiday_name][2] === 'object') {
    5259                                                                 if (-1 !== holidays[location_cc][type_of_holidays][holiday_name][2].indexOf(location_state))
    5260                                                                         matching_holiday[holiday_name] = holidays[location_cc][type_of_holidays][holiday_name];
    5261                                                         } else {
    5262                                                                 matching_holiday[holiday_name] = holidays[location_cc][type_of_holidays][holiday_name];
    5263                                                         }
    5264                                                 }
    5265                                                 if (Object.keys(matching_holiday).length === 0)
    5266                                                 throw formatLibraryBugMessage('There are no holidays ' + type_of_holidays + ' defined for country ' + location_cc + '.'
    5267                                                                 + ' You can also add them: ' + repository_url);
    5268                                                 return matching_holiday;
    5269                                         } else {
    5270                                                 throw formatLibraryBugMessage('Holidays ' + type_of_holidays + ' are not defined for country ' + location_cc
    5271                                                                 + ' and state ' + location_state + '.'
    5272                                                                 + ' You can also add them: ' + repository_url);
    5273                                         }
    5274                                 } else {
    5275                                         throw formatLibraryBugMessage('No holidays are defined for country ' + location_cc + '.'
    5276                                                         + ' You can also add them: ' + repository_url);
    5277                                 }
    5278                         } else { /* We have no idea which holidays do apply because the country code was not provided. */
    5279                                 throw 'Country code missing which is needed to select the correct holidays (see README how to provide it)';
    5280                         }
    5281                 }
    5282 
    5283                 function getMovableEventsForYear(Y) {
    5284                         // calculate easter
    5285                         var C = Math.floor(Y/100);
    5286                         var N = Y - 19*Math.floor(Y/19);
    5287                         var K = Math.floor((C - 17)/25);
    5288                         var I = C - Math.floor(C/4) - Math.floor((C - K)/3) + 19*N + 15;
    5289                         I = I - 30*Math.floor((I/30));
    5290                         I = I - Math.floor(I/28)*(1 - Math.floor(I/28)*Math.floor(29/(I + 1))*Math.floor((21 - N)/11));
    5291                         var J = Y + Math.floor(Y/4) + I + 2 - C + Math.floor(C/4);
    5292                         J = J - 7*Math.floor(J/7);
    5293                         var L = I - J;
    5294                         var M = 3 + Math.floor((L + 40)/44);
    5295                         var D = L + 28 - 31*Math.floor(M/4);
    5296 
    5297                         // calculate orthodox easter
    5298                         var oA = Y % 4;
    5299                         var oB = Y % 7;
    5300                         var oC = Y % 19;
    5301                         var oD = (19*oC + 15) % 30;
    5302                         var oE = (2*oA+4*oB - oD + 34) % 7;
    5303                         var oF = oD+oE;
    5304 
    5305                         var oDate;
    5306                         if (oF < 9) {
    5307                                 oDate = new Date(Y, 4-1, oF+4);
    5308                         } else {
    5309                                 if ((oF+4)<31) {
    5310                                         oDate = new Date(Y, 4-1, oF+4);
    5311                                 } else {
    5312                                         oDate = new Date(Y, 5-1, oF-26);
    5313                                 }
    5314                         }
    5315 
    5316                         // calculate last Sunday in February
    5317                         var lastFebruaryDay = new Date(Y, 2, 0);
    5318                         var lastFebruarySunday = lastFebruaryDay.getDate() - lastFebruaryDay.getDay();
    5319 
    5320                         // calculate Victoria Day. last Monday before or on May 24
    5321                         var may_24 = new Date(Y, 4, 24);
    5322                         var victoriaDay = 24  - ((6 + may_24.getDay()) % 7);
    5323 
    5324                         // calculate Canada Day. July 1st unless 1st is on Sunday, then July 2.
    5325                         var july_1 = new Date(Y, 6, 1);
    5326                         var canadaDay = july_1.getDay() === 0 ? 2 : 1;
    5327 
    5328                         function firstWeekdayOfMonth(month, weekday){
    5329                                 var first = new Date(Y, month, 1);
    5330                                 return 1 + ((7 + weekday - first.getDay()) % 7);
    5331                         }
    5332 
    5333                         function lastWeekdayOfMonth(month, weekday){
    5334                                 var last = new Date(Y, month+1, 0);
    5335                                 var offset=((7 + last.getDay() - weekday) % 7);
    5336                                 return last.getDate() - offset;
    5337                         }
    5338 
    5339                         return {
    5340                                 'easter'                :  new Date(Y, M - 1, D),
    5341                                 'orthodox easter'       :  oDate,
    5342                                 'victoriaDay'           :  new Date(Y,  4, victoriaDay),
    5343                                 'canadaDay'             :  new Date(Y,  6, canadaDay),
    5344                                 'firstJanuaryMonday'    :  new Date(Y,  0, firstWeekdayOfMonth(0, 1)),
    5345                                 'firstFebruaryMonday'   :  new Date(Y,  1, firstWeekdayOfMonth(1, 1)),
    5346                                 'lastFebruarySunday'    :  new Date(Y,  1, lastFebruarySunday),
    5347                                 'firstMarchMonday'      :  new Date(Y,  2, firstWeekdayOfMonth(2, 1)),
    5348                                 'firstAprilMonday'      :  new Date(Y,  3, firstWeekdayOfMonth(3, 1)),
    5349                                 'firstMayMonday'        :  new Date(Y,  4, firstWeekdayOfMonth(4, 1)),
    5350                                 'firstJuneMonday'       :  new Date(Y,  5, firstWeekdayOfMonth(5, 1)),
    5351                                 'firstJulyMonday'       :  new Date(Y,  6, firstWeekdayOfMonth(6, 1)),
    5352                                 'firstAugustMonday'     :  new Date(Y,  7, firstWeekdayOfMonth(7, 1)),
    5353                                 'firstSeptemberMonday'  :  new Date(Y,  8, firstWeekdayOfMonth(8, 1)),
    5354                                 'firstSeptemberSunday'  :  new Date(Y,  8, firstWeekdayOfMonth(8, 0)),
    5355                                 'firstOctoberMonday'    :  new Date(Y,  9, firstWeekdayOfMonth(9, 1)),
    5356                                 'firstNovemberMonday'   :  new Date(Y, 10, firstWeekdayOfMonth(10, 1)),
    5357                                 'firstMarchTuesday'     :  new Date(Y,  2, firstWeekdayOfMonth(2, 2)),
    5358                                 'firstAugustTuesday'    :  new Date(Y,  7, firstWeekdayOfMonth(7, 2)),
    5359                                 'firstAugustFriday'     :  new Date(Y,  7, firstWeekdayOfMonth(7, 5)),
    5360                                 'firstNovemberThursday' :  new Date(Y, 10, firstWeekdayOfMonth(10, 4)),
    5361                                 'lastMayMonday'         :  new Date(Y,  4, lastWeekdayOfMonth(4, 1)),
    5362                                 'lastMarchMonday'       :  new Date(Y,  2, lastWeekdayOfMonth(2, 1)),
    5363                                 'lastAprilMonday'       :  new Date(Y,  3, lastWeekdayOfMonth(3, 1)),
    5364                                 'lastAprilFriday'       :  new Date(Y,  3, lastWeekdayOfMonth(3, 5)),
    5365                                 'lastOctoberFriday'     :  new Date(Y,  9, lastWeekdayOfMonth(9, 5)),
    5366                         };
    5367                 }
    5368 
    5369                 function getApplyingHolidaysForYear(applying_holidays, year, add_days) {
    5370                         var movableDays = getMovableEventsForYear(year);
    5371 
    5372                         var sorted_holidays = [];
    5373                         var next_holiday;
    5374 
    5375                         for (var holiday_name in applying_holidays) {
    5376                                 if (typeof applying_holidays[holiday_name][0] === 'string') {
    5377                                         var selected_movableDay = movableDays[applying_holidays[holiday_name][0]];
    5378                                         if (!selected_movableDay)
    5379                                                 throw 'Movable day ' + applying_holidays[holiday_name][0] + ' can not not be calculated.'
    5380                                                         + ' Please add the formula how to calculate it.';
    5381                                         next_holiday = new Date(selected_movableDay.getFullYear(),
    5382                                                         selected_movableDay.getMonth(),
    5383                                                         selected_movableDay.getDate()
    5384                                                         + applying_holidays[holiday_name][1]
    5385                                                 );
    5386                                         if (year !== next_holiday.getFullYear())
    5387                                                 throw 'The movable day ' + applying_holidays[holiday_name][0] + ' plus '
    5388                                                         + applying_holidays[holiday_name][1]
    5389                                                         + ' days is not in the year of the movable day anymore. Currently not supported.';
    5390                                 } else {
    5391                                         next_holiday = new Date(year,
    5392                                                         applying_holidays[holiday_name][0] - 1,
    5393                                                         applying_holidays[holiday_name][1]
    5394                                                 );
    5395                                 }
    5396                                 if (add_days[0])
    5397                                         next_holiday.setDate(next_holiday.getDate() + add_days[0]);
    5398 
    5399                                 sorted_holidays.push([ next_holiday, holiday_name ]);
    5400                         }
    5401 
    5402                         sorted_holidays = sorted_holidays.sort(function(a,b){
    5403                                 if (a[0].getTime() < b[0].getTime()) return -1;
    5404                                 if (a[0].getTime() > b[0].getTime()) return 1;
    5405                                 return 0;
    5406                         });
    5407 
    5408                         return sorted_holidays;
    5409                 }
    5410                 // }}}
    5411                 // }}}
    5412 
    5413                 /* Year range parser (2013,2016-2018,2020/2). {{{
    5414                  *
    5415                  * :param tokens: List of token objects.
    5416                  * :param at: Position where to start.
    5417                  * :returns: Position at which the token does not belong to the selector anymore.
    5418                  */
    5419                 function parseYearRange(tokens, at) {
    5420                         tokens[at][3] = 'year';
    5421                         for (; at < tokens.length; at++) {
    5422                                 if (matchTokens(tokens, at, 'year')) {
    5423                                         var is_range   = false,
    5424                                                 has_period,
    5425                                                 period;
    5426                                         if (matchTokens(tokens, at+1, '-', 'year', '/', 'number')) {
    5427                                                 is_range   = true;
    5428                                                 has_period = true;
    5429                                                 period = parseInt(tokens[at+4][0]);
    5430                                                 checkPeriod(at+4, period, 'year');
    5431                                         } else {
    5432                                                 is_range   = matchTokens(tokens, at+1, '-', 'year');
    5433                                                 has_period = matchTokens(tokens, at+1, '/', 'number');
    5434                                                 if (has_period) {
    5435                                                         period = parseInt(tokens[at+2][0]);
    5436                                                         checkPeriod(at+2, period, 'year', 'no_end_year');
    5437                                                 } else if (matchTokens(tokens, at+1, '+')) {
    5438                                                         period = 1;
    5439                                                         has_period = 2;
    5440                                                 }
    5441                                         }
    5442 
    5443                                         var year_from = parseInt(tokens[at][0]);
    5444                                         // error checking {{{
    5445                                                 if (is_range && tokens[at+2][0] <= year_from) {
    5446                                                         // handle reversed range
    5447                                                         if (tokens[at+2][0] === year_from) {
    5448                                                                 throw formatWarnErrorMessage(nrule, at,
    5449                                                                                 'A year range in which the start year is equal to the end year does not make sense.'
    5450                                                                                 + ' Please remove the end year. E.g. "' + year_from + ' May 23"');
    5451                                                         } else {
    5452                                                                 throw formatWarnErrorMessage(nrule, at,
    5453                                                                                 'A year range in which the start year is greater than the end year does not make sense.'
    5454                                                                                 + ' Please turn it over.');
    5455                                                         }
    5456                                                 }
    5457                                         // }}}
    5458 
    5459                                         selectors.year.push(function(tokens, at, year_from, is_range, has_period, period) { return function(date) {
    5460                                                 var ouryear = date.getFullYear();
    5461                                                 var year_to = is_range ? parseInt(tokens[at+2][0]) : year_from;
    5462 
    5463                                                 if (ouryear < year_from ){
    5464                                                         return [false, new Date(year_from, 0, 1)];
    5465                                                 } else if (has_period) {
    5466                                                         if (year_from <= ouryear) {
    5467                                                                 if (is_range && ouryear > year_to)
    5468                                                                         return [false];
    5469                                                                 if (period > 0) {
    5470                                                                         if ((ouryear - year_from) % period === 0) {
    5471                                                                                 return [true, new Date(ouryear + 1, 0, 1)];
    5472                                                                         } else {
    5473                                                                                 return [false, new Date(ouryear + period - 1, 0, 1)];
    5474                                                                         }
    5475                                                                 }
    5476                                                         }
    5477                                                 } else if (is_range) {
    5478                                                         if (ouryear <= year_to)
    5479                                                                 return [true, new Date(year_to + 1, 0, 1)];
    5480                                                 } else if (ouryear === year_from) {
    5481                                                         return [true];
    5482                                                 }
    5483 
    5484                                                 return [false];
    5485 
    5486                                         }}(tokens, at, year_from, is_range, has_period, period));
    5487 
    5488                                         at += 1 + (is_range ? 2 : 0) + (has_period ? (has_period === 2 ? 1 : 2) : 0);
    5489                                 } else if (matchTokens(tokens, at - 1, ',')) { // additional rule
    5490                                         throw formatWarnErrorMessage(
    5491                                                 nrule,
    5492                                                 at - 1,
    5493                                                 'An additional rule does not make sense here. Just use a ";" as rule separator.'
    5494                                                 + ' See https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification#explain:additional_rule_separator');
    5495                                 } else {
    5496                                         throw formatWarnErrorMessage(nrule, at, 'Unexpected token in year range: ' + tokens[at][1]);
    5497                                 }
    5498 
    5499                                 if (!matchTokens(tokens, at, ','))
    5500                                         break;
    5501                         }
    5502 
    5503                         return at;
    5504                 }
    5505                 // }}}
    5506 
    5507                 /* Week range parser (week 11-20, week 1-53/2). {{{
    5508                  *
    5509                  * :param tokens: List of token objects.
    5510                  * :param at: Position where to start.
    5511                  * :returns: Position at which the token does not belong to the selector anymore.
    5512                  */
    5513                 function parseWeekRange(tokens, at) {
    5514                         for (; at < tokens.length; at++) {
    5515                                 if (matchTokens(tokens, at, 'week')) {
    5516                                         at++;
    5517                                 }
    5518                                 if (matchTokens(tokens, at, 'number')) {
    5519                                         var is_range = matchTokens(tokens, at+1, '-', 'number'), period = 0;
    5520                                         var week_from = tokens[at][0];
    5521                                         var week_to   = is_range ? tokens[at+2][0] : week_from;
    5522                                         if (week_from > week_to) {
    5523                                                 throw formatWarnErrorMessage(nrule, at+2,
    5524                                                         'You have specified a week range in reverse order or leaping over a year. This is (currently) not supported.');
    5525                                         }
    5526                                         if (week_from < 1) {
    5527                                                 throw formatWarnErrorMessage(nrule, at,
    5528                                                         'You have specified a week date less then one. A valid week date range is 1-53.');
    5529                                         }
    5530                                         if (week_to > 53) {
    5531                                                 throw formatWarnErrorMessage(nrule, is_range ? at+2 : at,
    5532                                                         'You have specified a week date greater then 53. A valid week date range is 1-53.');
    5533                                         }
    5534                                         if (is_range) {
    5535                                                 period = matchTokens(tokens, at+3, '/', 'number');
    5536                                                 if (period) {
    5537                                                         period = tokens[at+4][0];
    5538                                                         if (period < 2) {
    5539                                                                 throw formatWarnErrorMessage(nrule, at+4,
    5540                                                                         'You have specified a week period which is less than two.'
    5541                                                                         + ' If you want to select the whole range from week ' + week_from + ' to week ' + week_to + ' then just omit the "/' + period + '".');
    5542                                                         } else if (period > 26) {
    5543                                                                 throw formatWarnErrorMessage(nrule, at+4,
    5544                                                                         'You have specified a week period which is greater than 26.'
    5545                                                                         + ' 26.5 is the half of the maximum 53 week dates per year so a week date period greater than 26 would only apply once per year.'
    5546                                                                         + ' Please specify the week selector as "week ' + week_from + '" if that is what you want to express.');
    5547                                                         }
    5548                                                 }
    5549                                         }
    5550 
    5551                                         if (week_stable && (!(week_from <= 1 && week_to >= 53) || period)) {
    5552                                                 week_stable = false;
    5553                                         }
    5554 
    5555                                         if (!period && week_from === 1 && week_to === 53) {
    5556                                                 /* Shortcut and work around bug. */
    5557                                                 selectors.week.push(function(date) { return [true]; });
    5558                                         } else {
    5559 
    5560                                                 selectors.week.push(function(week_from, week_to, is_range, period) { return function(date) {
    5561                                                         var ourweek = getWeekNumber(date);
    5562 
    5563                                                         // console.log("week_from: %s, week_to: %s", week_from, week_to);
    5564                                                         // console.log("ourweek: %s, date: %s", ourweek, date);
    5565 
    5566                                                         // before range
    5567                                                         if (ourweek < week_from) {
    5568                                                                 // console.log("Before: " + getNextDateOfISOWeek(week_from, date));
    5569                                                                 return [false, getNextDateOfISOWeek(week_from, date)];
    5570                                                         }
    5571 
    5572                                                         // we're after range, set check date to next year
    5573                                                         if (ourweek > week_to) {
    5574                                                                 // console.log("After");
    5575                                                                 return [false, getNextDateOfISOWeek(week_from, date)];
    5576                                                         }
    5577 
    5578                                                         // we're in range
    5579                                                         if (period) {
    5580                                                                 var in_period = (ourweek - week_from) % period === 0;
    5581                                                                 if (in_period) {
    5582                                                                         return [true, getNextDateOfISOWeek(ourweek + 1, date)];
    5583                                                                 } else {
    5584                                                                         return [false, getNextDateOfISOWeek(ourweek + period - 1, date)];
    5585                                                                 }
    5586                                                         }
    5587 
    5588                                                         // console.log("Match");
    5589                                                         return [true, getNextDateOfISOWeek(week_to === 53 ? 1 : week_to + 1, date)];
    5590                                                 }}(week_from, week_to, is_range, period));
    5591                                         }
    5592 
    5593                                         at += 1 + (is_range ? 2 : 0) + (period ? 2 : 0);
    5594                                 } else if (matchTokens(tokens, at - 1, ',')) { // additional rule
    5595                                         throw formatWarnErrorMessage(
    5596                                                 nrule,
    5597                                                 at - 1,
    5598                                                 'An additional rule does not make sense here. Just use a ";" as rule separator.'
    5599                                                 + ' See https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification#explain:additional_rule_separator');
    5600                                 } else {
    5601                                         throw formatWarnErrorMessage(nrule, at, 'Unexpected token in week range: ' + tokens[at][1]);
    5602                                 }
    5603 
    5604                                 if (!matchTokens(tokens, at, ','))
    5605                                         break;
    5606                         }
    5607 
    5608                         return at;
    5609                 }
    5610 
    5611                 // http://stackoverflow.com/a/6117889
    5612                 /* For a given date, get the ISO week number
    5613                  *
    5614                  * Based on information at:
    5615                  *
    5616                  *    http://www.merlyn.demon.co.uk/weekcalc.htm#WNR
    5617                  *
    5618                  * Algorithm is to find nearest thursday, it's year
    5619                  * is the year of the week number. Then get weeks
    5620                  * between that date and the first day of that year.
    5621                  *
    5622                  * Note that dates in one year can be weeks of previous
    5623                  * or next year, overlap is up to 3 days.
    5624                  *
    5625                  * e.g. 2014/12/29 is Monday in week  1 of 2015
    5626                  *      2012/1/1   is Sunday in week 52 of 2011
    5627                  */
    5628                 function getWeekNumber(d) {
    5629                     // Copy date so don't modify original
    5630                     d = new Date(+d);
    5631                     d.setHours(0,0,0);
    5632                     // Set to nearest Thursday: current date + 4 - current day number
    5633                     // Make Sunday's day number 7
    5634                     d.setDate(d.getDate() + 4 - (d.getDay()||7));
    5635                     // Get first day of year
    5636                     var yearStart = new Date(d.getFullYear(),0,1);
    5637                     // Calculate full weeks to nearest Thursday
    5638                     return Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7)
    5639                 }
    5640                 // http://stackoverflow.com/a/16591175
    5641                 function getDateOfISOWeek(w, y) {
    5642                         var simple = new Date(y, 0, 1 + (w - 1) * 7);
    5643                         var dow = simple.getDay();
    5644                         var ISOweekStart = simple;
    5645                         if (dow <= 4)
    5646                                 ISOweekStart.setDate(simple.getDate() - simple.getDay() + 1);
    5647                         else
    5648                                 ISOweekStart.setDate(simple.getDate() + 8 - simple.getDay());
    5649                         return ISOweekStart;
    5650                 }
    5651                 function getNextDateOfISOWeek(week, date) {
    5652                         var next_date;
    5653                         for (var i = -1; i <= 1; i++) {
    5654                                 next_date = getDateOfISOWeek(week, date.getFullYear() + i);
    5655                                 if (next_date.getTime() > date.getTime()) {
    5656                                         return next_date;
    5657                                 }
    5658                         }
    5659                         throw formatLibraryBugMessage();
    5660                 }
    5661                 // }}}
    5662 
    5663                 /* Month range parser (Jan,Feb-Mar). {{{
    5664                  *
    5665                  * :param tokens: List of token objects.
    5666                  * :param at: Position where to start.
    5667                  * :param push_to_monthday: Will push the selector into the monthday selector array which has the desired side effect of working in conjunction with the monthday selectors (either the month match or the monthday).
    5668                  * :returns: Position at which the token does not belong to the selector anymore.
    5669                  */
    5670                 function parseMonthRange(tokens, at, push_to_monthday, in_selector) {
    5671                         if (!in_selector)
    5672                                 tokens[at][3] = 'month';
    5673 
    5674                         for (; at < tokens.length; at++) {
    5675                                 // Use parseMonthdayRange if '<month> <daynum>' and not '<month> <hour>:<minute>'
    5676                                 if (matchTokens(tokens, at, 'month', 'number') && !matchTokens(tokens, at+2, 'timesep', 'number')) {
    5677                                         return parseMonthdayRange(tokens, at, nrule, true);
    5678                                 } else if (matchTokens(tokens, at, 'month')) {
    5679                                         // Single month (Jan) or month range (Feb-Mar)
    5680                                         var is_range = matchTokens(tokens, at+1, '-', 'month');
    5681 
    5682                                         var month_from = tokens[at][0];
    5683                                         var month_to = is_range ? tokens[at+2][0] : month_from;
    5684 
    5685                                         if (is_range && week_stable) {
    5686                                                 if (month_from !== (month_to + 1) % 12)
    5687                                                         week_stable = false;
    5688                                         } else {
    5689                                                 week_stable = false;
    5690                                         }
    5691 
    5692                                         var inside = true;
    5693 
    5694                                         // handle reversed range
    5695                                         if (month_to < month_from) {
    5696                                                 var tmp = month_to;
    5697                                                 month_to = month_from - 1;
    5698                                                 month_from = tmp + 1;
    5699                                                 inside = false;
    5700                                         }
    5701 
    5702                                         var selector = function(tokens, at, month_from, month_to, is_range, inside) { return function(date) {
    5703                                                 var ourmonth = date.getMonth();
    5704 
    5705                                                 // handle full range
    5706                                                 if (month_to < month_from)
    5707                                                         return [!inside];
    5708 
    5709                                                 if (ourmonth < month_from || ourmonth > month_to) {
    5710                                                         return [!inside, dateAtNextMonth(date, month_from)];
    5711                                                 } else {
    5712                                                         return [inside, dateAtNextMonth(date, month_to + 1)];
    5713                                                 }
    5714                                         }}(tokens, at, month_from, month_to, is_range, inside);
    5715 
    5716                                         if (push_to_monthday === true)
    5717                                                 selectors.monthday.push(selector);
    5718                                         else
    5719                                                 selectors.month.push(selector);
    5720 
    5721                                         at += is_range ? 3 : 1;
    5722                                 } else {
    5723                                         throw formatWarnErrorMessage(nrule, at, 'Unexpected token in month range: ' + tokens[at][1]);
    5724                                 }
    5725 
    5726                                 if (!matchTokens(tokens, at, ','))
    5727                                         break;
    5728                         }
    5729 
    5730                         return at;
    5731                 }
    5732 
    5733                 function dateAtNextMonth(date, month) {
    5734                         return new Date(date.getFullYear(), month < date.getMonth() ? month + 12 : month);
    5735                 }
    5736                 // }}}
    5737 
    5738                 /* Month day range parser (Jan 26-31; Jan 26-Feb 26). {{{
    5739                  *
    5740                  * :param tokens: List of token objects.
    5741                  * :param at: Position where to start.
    5742                  * :param nrule: Rule number starting with 0.
    5743                  * :param push_to_month: Will push the selector into the month selector array which has the desired side effect of working in conjunction with the month selectors (either the month match or the monthday).
    5744                  * :returns: Position at which the token does not belong to the selector anymore.
    5745                  */
    5746                 function parseMonthdayRange(tokens, at, nrule, push_to_month) {
    5747                         if (!push_to_month)
    5748                                 tokens[at][3] = 'month';
    5749 
    5750                         for (; at < tokens.length; at++) {
    5751                                 var has_year = [], has_month = [], has_event = [], has_calc = [], has_constrained_weekday = [];
    5752                                 has_year[0]  = matchTokens(tokens, at, 'year');
    5753                                 has_month[0] = matchTokens(tokens, at+has_year[0], 'month', 'number');
    5754                                 has_event[0] = matchTokens(tokens, at+has_year[0], 'event');
    5755 
    5756                                 if (has_event[0])
    5757                                         has_calc[0] = getMoveDays(tokens, at+has_year[0]+1, 200, 'event like easter');
    5758 
    5759                                 var at_range_sep;
    5760                                 if (matchTokens(tokens, at+has_year[0], 'month', 'weekday', '[')) {
    5761                                         has_constrained_weekday[0] = getConstrainedWeekday(tokens, at+has_year[0]+3);
    5762                                         has_calc[0] = getMoveDays(tokens, has_constrained_weekday[0][1], 6, 'constrained weekdays');
    5763                                         at_range_sep = has_constrained_weekday[0][1] + (typeof has_calc[0] !== 'undefined' && has_calc[0][1] ? 3 : 0);
    5764                                 } else {
    5765                                         at_range_sep = at+has_year[0]
    5766                                                 + (has_event[0]
    5767                                                         ? (typeof has_calc[0] !== 'undefined' && has_calc[0][1] ? 4 : 1)
    5768                                                         : 2);
    5769                                 }
    5770 
    5771                                 var at_sec_event_or_month;
    5772                                 if ((has_month[0] || has_event[0] || has_constrained_weekday[0]) && matchTokens(tokens, at_range_sep, '-')) {
    5773                                         has_year[1] = matchTokens(tokens, at_range_sep+1, 'year');
    5774                                         at_sec_event_or_month = at_range_sep+1+has_year[1];
    5775                                         has_month[1] = matchTokens(tokens, at_sec_event_or_month, 'month', 'number');
    5776                                         if (!has_month[1]) {
    5777                                                 has_event[1] = matchTokens(tokens, at_sec_event_or_month, 'event');
    5778                                                 if (has_event[1]) {
    5779                                                         has_calc[1] = getMoveDays(tokens, at_sec_event_or_month+1, 366, 'event like easter');
    5780                                                 } else if (matchTokens(tokens, at_sec_event_or_month, 'month', 'weekday', '[')) {
    5781                                                         has_constrained_weekday[1] = getConstrainedWeekday(tokens, at_sec_event_or_month+3);
    5782                                                         has_calc[1] = getMoveDays(tokens, has_constrained_weekday[1][1], 6, 'constrained weekdays');
    5783                                                 }
    5784                                         }
    5785                                 }
    5786 
    5787                                 // monthday range like Jan 26-Feb 26 {{{
    5788                                 if (has_year[0] === has_year[1] && (has_month[1] || has_event[1] || has_constrained_weekday[1])) {
    5789 
    5790                                         if (has_month[0])
    5791                                                 checkIfDateIsValid(tokens[at+has_year[0]][0], tokens[at+has_year[0]+1][0], nrule, at+has_year[0]+1);
    5792                                         if (has_month[1])
    5793                                                 checkIfDateIsValid(tokens[at_sec_event_or_month][0], tokens[at_sec_event_or_month+1][0], nrule, at_sec_event_or_month+1);
    5794 
    5795                                         var selector = function(tokens, at, nrule, has_year, has_event, has_calc, at_sec_event_or_month, has_constrained_weekday) { return function(date) {
    5796                                                 var start_of_next_year = new Date(date.getFullYear() + 1, 0, 1);
    5797 
    5798                                                 var movableDays,
    5799                                                         from_date;
    5800                                                 if (has_event[0]) {
    5801                                                         movableDays = getMovableEventsForYear(has_year[0] ? parseInt(tokens[at][0]) : date.getFullYear());
    5802                                                         from_date = movableDays[tokens[at+has_year[0]][0]];
    5803 
    5804                                                         if (typeof has_calc[0] !== 'undefined' && has_calc[0][1]) {
    5805                                                                 var from_year_before_calc = from_date.getFullYear();
    5806                                                                 from_date.setDate(from_date.getDate() + has_calc[0][0]);
    5807                                                                 if (from_year_before_calc !== from_date.getFullYear())
    5808                                                                         throw formatWarnErrorMessage(nrule, at+has_year[0]+has_calc[0][1]*3,
    5809                                                                                 'The movable day ' + tokens[at+has_year[0]][0] + ' plus ' + has_calc[0][0]
    5810                                                                                 + ' days is not in the year of the movable day anymore. Currently not supported.');
    5811                                                         }
    5812                                                 } else if (has_constrained_weekday[0]) {
    5813                                                         from_date = getDateForConstrainedWeekday((has_year[0] ? tokens[at][0] : date.getFullYear()), // year
    5814                                                                 tokens[at+has_year[0]][0], // month
    5815                                                                 tokens[at+has_year[0]+1][0], // weekday
    5816                                                                 has_constrained_weekday[0],
    5817                                                                 has_calc[0]);
    5818                                                 } else {
    5819                                                         from_date = new Date((has_year[0] ? tokens[at][0] : date.getFullYear()),
    5820                                                                 tokens[at+has_year[0]][0], tokens[at+has_year[0]+1][0]);
    5821                                                 }
    5822 
    5823                                                 var to_date;
    5824                                                 if (has_event[1]) {
    5825                                                         movableDays = getMovableEventsForYear(has_year[1]
    5826                                                                                 ? parseInt(tokens[at_sec_event_or_month-1][0])
    5827                                                                                 : date.getFullYear());
    5828                                                         to_date = movableDays[tokens[at_sec_event_or_month][0]];
    5829 
    5830                                                         if (typeof has_calc[1] !== 'undefined' && has_calc[1][1]) {
    5831                                                                 var to_year_before_calc = to_date.getFullYear();
    5832                                                                 to_date.setDate(to_date.getDate() + has_calc[1][0]);
    5833                                                                 if (to_year_before_calc !== to_date.getFullYear())
    5834                                                                         throw formatWarnErrorMessage(nrule, at_sec_event_or_month+has_calc[1][1],
    5835                                                                                 'The movable day ' + tokens[at_sec_event_or_month][0] + ' plus ' + has_calc[1][0]
    5836                                                                                 + ' days is not in the year of the movable day anymore. Currently not supported.');
    5837                                                         }
    5838                                                 } else if (has_constrained_weekday[1]) {
    5839                                                         to_date = getDateForConstrainedWeekday((has_year[1] ? tokens[at_sec_event_or_month-1][0] : date.getFullYear()), // year
    5840                                                                 tokens[at_sec_event_or_month][0],   // month
    5841                                                                 tokens[at_sec_event_or_month+1][0], // weekday
    5842                                                                 has_constrained_weekday[1],
    5843                                                                 has_calc[1]);
    5844                                                 } else {
    5845                                                         to_date = new Date((has_year[1] ? tokens[at_sec_event_or_month-1][0] : date.getFullYear()),
    5846                                                                 tokens[at_sec_event_or_month][0], tokens[at_sec_event_or_month+1][0] + 1);
    5847                                                 }
    5848 
    5849                                                 var inside = true;
    5850 
    5851                                                 if (to_date < from_date) {
    5852                                                         var tmp = to_date;
    5853                                                         to_date = from_date;
    5854                                                         from_date = tmp;
    5855                                                         inside = false;
    5856                                                 }
    5857 
    5858                                                 if (date.getTime() < from_date.getTime()) {
    5859                                                         return [!inside, from_date];
    5860                                                 } else if (date.getTime() < to_date.getTime()) {
    5861                                                         return [inside, to_date];
    5862                                                 } else {
    5863                                                         if (has_year[0]) {
    5864                                                                 return [!inside];
    5865                                                         } else {
    5866                                                                 return [!inside, start_of_next_year];
    5867                                                         }
    5868                                                 }
    5869                                         }}(tokens, at, nrule, has_year, has_event, has_calc, at_sec_event_or_month, has_constrained_weekday);
    5870 
    5871                                         if (push_to_month === true)
    5872                                                 selectors.month.push(selector);
    5873                                         else
    5874                                                 selectors.monthday.push(selector);
    5875 
    5876                                         at = (has_constrained_weekday[1]
    5877                                                         ? has_constrained_weekday[1][1]
    5878                                                         : at_sec_event_or_month + (has_event[1] ? 1 : 2))
    5879                                                 + (typeof has_calc[1] !== 'undefined' ? has_calc[1][1] : 0);
    5880 
    5881                                         // }}}
    5882                                         // Monthday range like Jan 26-31 {{{
    5883                                 } else if (has_month[0]) {
    5884 
    5885                                         has_year = has_year[0];
    5886                                         var year = tokens[at][0]; // Could be month if has no year. Tested later.
    5887                                         var month = tokens[at+has_year][0];
    5888 
    5889                                         var first_round = true;
    5890 
    5891                                         do {
    5892                                                 var range_from = tokens[at+1 + has_year][0];
    5893                                                 var is_range = matchTokens(tokens, at+2+has_year, '-', 'number');
    5894                                                 var period = undefined;
    5895                                                 var range_to = tokens[at+has_year+(is_range ? 3 : 1)][0] + 1;
    5896                                                 if (is_range && matchTokens(tokens, at+has_year+4, '/', 'number')) {
    5897                                                         period = tokens[at+has_year+5][0];
    5898                                                         checkPeriod(at+has_year+5, period, 'day');
    5899                                                 }
    5900 
    5901                                                 if (first_round) {
    5902                                                         var at_timesep_if_monthRange = at + has_year + 1 // at month number
    5903                                                                 + (is_range ? 2 : 0) + (period ? 2 : 0)
    5904                                                                 + !(is_range || period); // if not range nor has period, add one
    5905 
    5906                                                         // Check for '<month> <timespan>'
    5907                                                         if (matchTokens(tokens, at_timesep_if_monthRange, 'timesep', 'number')
    5908                                                                         && (matchTokens(tokens, at_timesep_if_monthRange+2, '+')
    5909                                                                                 || matchTokens(tokens, at_timesep_if_monthRange+2, '-')
    5910                                                                                 || oh_mode !== 0)) {
    5911                                                                                         return parseMonthRange(tokens, at, true, true);
    5912                                                         }
    5913                                                 }
    5914 
    5915                                                 // error checking {{{
    5916                                                 if (range_to < range_from)
    5917                                                         throw formatWarnErrorMessage(nrule, at+has_year+3,
    5918                                                                         'Range in wrong order. From day is greater than to day.');
    5919 
    5920                                                 checkIfDateIsValid(month, range_from, nrule, at+1 + has_year);
    5921                                                 checkIfDateIsValid(month, range_to - 1 /* added previously */,
    5922                                                         nrule, at+has_year+(is_range ? 3 : 1));
    5923                                                 // }}}
    5924 
    5925                                                 var selector = function(year, has_year, month, range_from, range_to, period) { return function(date) {
    5926                                                         var start_of_next_year = new Date(date.getFullYear() + 1, 0, 1);
    5927 
    5928                                                         var from_date = new Date(has_year ? year : date.getFullYear(),
    5929                                                                 month, range_from);
    5930                                                         if (month === 1 && range_from !== from_date.getDate()) // Only on leap years does this day exist.
    5931                                                                 return [false]; // If day 29 does not exist,
    5932                                                                                                 // then the date object adds one day to date
    5933                                                                                                 // and this selector should not match.
    5934                                                         var to_date   = new Date(from_date.getFullYear(),
    5935                                                                 month, range_to);
    5936                                                         if (month === 1 && is_range && range_to !== to_date.getDate()) // Only on leap years does this day exist.
    5937                                                                 return [false];
    5938 
    5939                                                         if (date.getTime() < from_date.getTime())
    5940                                                                 return [false, from_date];
    5941                                                         else if (date.getTime() >= to_date.getTime())
    5942                                                                 return [false, start_of_next_year];
    5943                                                         else if (!period)
    5944                                                                 return [true, to_date];
    5945 
    5946                                                         var nday = Math.floor((date.getTime() - from_date.getTime()) / msec_in_day);
    5947                                                         var in_period = nday % period;
    5948 
    5949                                                         if (in_period === 0)
    5950                                                                 return [true, new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)];
    5951                                                         else
    5952                                                                 return [false, new Date(date.getFullYear(), date.getMonth(), date.getDate() + period - in_period)];
    5953 
    5954                                                 }}(year, has_year, month, range_from, range_to, period);
    5955 
    5956                                                 if (push_to_month === true)
    5957                                                         selectors.month.push(selector);
    5958                                                 else
    5959                                                         selectors.monthday.push(selector);
    5960 
    5961                                                 at += 2 + has_year + (is_range ? 2 : 0) + (period ? 2 : 0);
    5962 
    5963                                                 first_round = false;
    5964                                         }
    5965                                         while (matchTokens(tokens, at, ',', 'number'))
    5966 
    5967 
    5968                                         // }}}
    5969                                         // Only event like easter {{{
    5970                                 } else if (has_event[0]) {
    5971 
    5972                                         var selector = function(tokens, at, nrule, has_year, add_days) { return function(date) {
    5973 
    5974                                                 // console.log('enter selector with date: ' + date);
    5975                                                 var movableDays = getMovableEventsForYear((has_year ? tokens[at][0] : date.getFullYear()));
    5976                                                 var event_date = movableDays[tokens[at+has_year][0]];
    5977                                                 if (!event_date)
    5978                                                         throw 'Movable day ' + tokens[at+has_year][0] + ' can not not be calculated.'
    5979                                                                 + ' Please add the formula how to calculate it.';
    5980 
    5981                                                 if (add_days[0]) {
    5982                                                         event_date.setDate(event_date.getDate() + add_days[0]);
    5983                                                         if (date.getFullYear() !== event_date.getFullYear())
    5984                                                                 throw formatWarnErrorMessage(nrule, at+has_year+add_days[1], 'The movable day ' + tokens[at+has_year][0] + ' plus '
    5985                                                                         + add_days[0]
    5986                                                                         + ' days is not in the year of the movable day anymore. Currently not supported.');
    5987                                                 }
    5988 
    5989                                                 if (date.getTime() < event_date.getTime())
    5990                                                         return [false, event_date];
    5991                                                 // else if (date.getTime() < event_date.getTime() + msec_in_day) // does not work because of daylight saving times
    5992                                                 else if (event_date.getMonth() * 100 + event_date.getDate() === date.getMonth() * 100 + date.getDate())
    5993                                                         return [true, new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1)];
    5994                                                 else
    5995                                                         return [false, new Date(date.getFullYear() + 1, 0, 1)];
    5996 
    5997                                         }}(tokens, at, nrule, has_year[0], has_calc[0]);
    5998 
    5999                                         if (push_to_month === true)
    6000                                                 selectors.month.push(selector);
    6001                                         else
    6002                                                 selectors.monthday.push(selector);
    6003 
    6004                                         at += has_year[0] + has_event[0] + (typeof has_calc[0][1] !== 'undefined' && has_calc[0][1] ? 3 : 0);
    6005                                         // }}}
    6006                                 } else if (has_constrained_weekday[0]) {
    6007                                         at = parseMonthRange(tokens, at);
    6008                                 } else if (matchTokens(tokens, at, 'month')) {
    6009                                         return parseMonthRange(tokens, at, true, true);
    6010                                 } else {
    6011                                         // throw 'Unexpected token in monthday range: "' + tokens[at] + '"';
    6012                                         return at;
    6013                                 }
    6014 
    6015                                 if (!matchTokens(tokens, at, ','))
    6016                                         break;
    6017                         }
    6018 
    6019                         return at;
    6020                 }
    6021                 // }}}
    6022 
    6023                 /* Main selector traversal function (return state array for date). {{{
    6024                  * Checks for given date which rule and those which state and comment applies.
    6025                  *
    6026                  * :param date: Date object.
    6027                  * :returns: Array:
    6028                  *                      0. resultstate: State: true for 'open', false for 'closed'.
    6029                  *                      1. changedate: Next change as date object.
    6030                  *                      2. unknown: true if state open is not sure.
    6031                  *                      3. comment: Comment which applies for this time range (from date to changedate).
    6032                  *                      4. match_rule: Rule number starting with 0 (nrule).
    6033                  */
    6034                 this.getStatePair = function(date) {
    6035                         var resultstate = false;
    6036                         var changedate;
    6037                         var unknown = false;
    6038                         var comment;
    6039                         var match_rule;
    6040 
    6041                         var date_matching_rules = [];
    6042 
    6043                         /* Go though all date selectors and check if they return something
    6044                          * else than closed for the given date.
    6045                          */
    6046                         for (var nrule = 0; nrule < rules.length; nrule++) {
    6047                                 var matching_date_rule = true;
    6048                                 // console.log(nrule, 'length',  rules[nrule].date.length);
    6049 
    6050                                 /* Try each date selector type. */
    6051                                 for (var ndateselector = 0; ndateselector < rules[nrule].date.length; ndateselector++) {
    6052                                         var dateselectors = rules[nrule].date[ndateselector];
    6053                                         // console.log(nrule, ndateselector);
    6054 
    6055                                         var has_matching_selector = false;
    6056                                         for (var datesel = 0; datesel < dateselectors.length; datesel++) {
    6057                                                 var res = dateselectors[datesel](date);
    6058                                                 if (res[0]) {
    6059                                                         has_matching_selector = true;
    6060 
    6061                                                         if (typeof res[2] === 'string') { // holiday name
    6062                                                                 comment = [ res[2], nrule ];
    6063                                                         }
    6064 
    6065                                                 }
    6066                                                 if (typeof changedate === 'undefined' || (typeof res[1] !== 'undefined' && res[1].getTime() < changedate.getTime()))
    6067                                                         changedate = res[1];
    6068                                         }
    6069 
    6070                                         if (!has_matching_selector) {
    6071                                                 matching_date_rule = false;
    6072                                                 // We can ignore other date selectors, as the state won't change
    6073                                                 // anyway until THIS selector matches (due to conjunction of date
    6074                                                 // selectors of different types).
    6075                                                 // This is also an optimization, if widest date selector types
    6076                                                 // are checked first.
    6077                                                 break;
    6078                                         }
    6079                                 }
    6080 
    6081                                 if (matching_date_rule) {
    6082                                         /* The following lines implement date overwriting logic (e.g. for
    6083                                          * "Mo-Fr 10:00-20:00; We 10:00-16:00", We rule overrides Mo-Fr rule partly (We).
    6084                                          *
    6085                                          * This is the only way to be consistent. I thought about ("22:00-02:00; Tu 12:00-14:00") letting Th override 22:00-02:00 partly:
    6086                                          * Like: Th 00:00-02:00,12:00-14:00 but this would result in including 22:00-00:00 for Th which is probably not what you want.
    6087                                          */
    6088                                         if ((rules[nrule].date.length > 0 || nrule > 0 && rules[nrule].meaning && rules[nrule-1].date.length === 0)
    6089                                                         && (rules[nrule].meaning || rules[nrule].unknown)
    6090                                                         && !rules[nrule].wrapped && !rules[nrule].additional && !rules[nrule].fallback
    6091                                                 ) {
    6092 
    6093                                                 // var old_date_matching_rules = date_matching_rules;
    6094                                                 date_matching_rules = [];
    6095                                                 // for (var nrule = 0; nrule < old_date_matching_rules.length; nrule++) {
    6096                                                 //      if (!rules[old_date_matching_rules[nrule]].wrapped)
    6097                                                 //              date_matching_rules.push(nrule);
    6098                                                 // }
    6099                                         }
    6100                                         date_matching_rules.push(nrule);
    6101                                 }
    6102                         }
    6103 
    6104                         // console.log(date_matching_rules);
    6105                         rule:
    6106                         for (var nrule = 0; nrule < date_matching_rules.length; nrule++) {
    6107                                 var rule = date_matching_rules[nrule];
    6108 
    6109                                 // console.log('Processing rule ' + rule + ': with date ' + date
    6110                                         // + ' and ' + rules[rule].time.length + ' time selectors (comment: "' + rules[rule].comment + '").');
    6111 
    6112                                 /* There is no time specified, state applies to the whole day. */
    6113                                 if (rules[rule].time.length === 0) {
    6114                                         // console.log('there is no time', date);
    6115                                         if (!rules[rule].fallback || (rules[rule].fallback && !(resultstate || unknown))) {
    6116                                                 resultstate = rules[rule].meaning;
    6117                                                 unknown     = rules[rule].unknown;
    6118                                                 match_rule  = rule;
    6119 
    6120                                                 // if (rules[rule].fallback)
    6121                                                         // break rule; // fallback rule matched, no need for checking the rest
    6122                                                 // WRONG: What if closing rules follow?
    6123                                         }
    6124                                 }
    6125 
    6126                                 for (var timesel = 0; timesel < rules[rule].time.length; timesel++) {
    6127                                         var res = rules[rule].time[timesel](date);
    6128 
    6129                                         // console.log('res:', res);
    6130                                         if (res[0]) {
    6131                                                 if (!rules[rule].fallback || (rules[rule].fallback && !(resultstate || unknown))) {
    6132                                                         resultstate = rules[rule].meaning;
    6133                                                         unknown     = rules[rule].unknown;
    6134                                                         match_rule  = rule;
    6135 
    6136                                                         /* Reset open end comment */
    6137                                                         if (typeof comment === 'object' && comment[0] === 'Specified as open end. Closing time was guessed.')
    6138                                                                 comment = undefined;
    6139 
    6140                                                         // open end
    6141                                                         if (res[2] === true && (resultstate || unknown)) {
    6142                                                                 comment = [ 'Specified as open end. Closing time was guessed.', match_rule ];
    6143 
    6144                                                                 resultstate = false;
    6145                                                                 unknown     = true;
    6146 
    6147                                                                 /* Hack to make second rule in '07:00+,12:00-16:00; 16:00-24:00 closed "needed because of open end"' obsolete {{{ */
    6148                                                                 if (typeof rules[rule].time[timesel+1] === 'function') {
    6149 
    6150                                                                         var next_res = rules[rule].time[timesel+1](date);
    6151                                                                         if (  !next_res[0]
    6152                                                                                 // && next_res[2]
    6153                                                                                 && typeof next_res[1] === 'object'
    6154                                                                                 // && getValueForDate(next_res[1], true) !== getValueForDate(date, true) // Just to be sure.
    6155                                                                                 && rules[rule].time[timesel](new Date(date.getTime() - 1))[0]
    6156                                                                                 /* To distinguish the following two values:
    6157                                                                                  *       'sunrise-14:00,14:00+',
    6158                                                                                  *   '07:00+,12:00-16:00',
    6159                                                                                  */
    6160                                                                                 ) {
    6161 
    6162                                                                                 // console.log("07:00+,12:00-16:00 matched.");
    6163 
    6164                                                                                 resultstate = false;
    6165                                                                                 unknown     = false;
    6166                                                                         }
    6167                                                                 }
    6168 
    6169                                                                 /* Hack to handle '17:00+,13:00-02:00' {{{ */
    6170                                                                 /* Not enabled. To complicated, just don‘t use them …
    6171                                                                  * It gets even crazier …
    6172                                                                  * Time wrapping over midnight is
    6173                                                                  * stored in the next internal rule:
    6174                                                                  * '17:00-00:00 unknown "Specified as open end. Closing time was guessed.", 13:00-00:00 open' // First internal rule.
    6175                                                                  * + ', ' overwritten part: 00:00-03:00 open + '00:00-02:00 open', // Second internal rule.
    6176                                                                  */
    6177                                                                 if (    false
    6178                                                                                 && typeof rules[rule-1] === 'object'
    6179                                                                                 && rules[rule].build_from_token_rule.toString() === rules[rule-1].build_from_token_rule.toString()
    6180                                                                                 && typeof rules[rule] === 'object'
    6181                                                                                 && rules[rule].build_from_token_rule.toString() === rules[rule].build_from_token_rule.toString()
    6182                                                                                 ) {
    6183 
    6184                                                                         var last_wrapping_time_selector = rules[rule].time[rules[rule].time.length - 1];
    6185                                                                         var last_w_res = last_wrapping_time_selector(new Date(date.getTime() - 1));
    6186                                                                         // console.log(last_w_res);
    6187 
    6188                                                                         if (    last_w_res[0]
    6189                                                                                         &&  typeof last_w_res[2] === 'undefined'
    6190                                                                                         && (typeof last_w_res[2] === 'undefined' || last_w_res[2] === false) // Do not match for 'Tu 23:59-40:00+'
    6191                                                                                         &&  typeof last_w_res[1] === 'object'
    6192                                                                                         && date.getTime() === last_w_res[1].getTime()
    6193                                                                                 ) {
    6194 
    6195                                                                                 // '05:00-06:00,17:00+,13:00-02:00',
    6196 
    6197                                                                                 // console.log("17:00+,13:00-02:00 matched.");
    6198                                                                                 // console.log(JSON.stringify(rules, null, '    '));
    6199 
    6200                                                                                 resultstate = false;
    6201                                                                                 unknown     = false;
    6202                                                                         }
    6203                                                                 /* }}} */
    6204                                                                 }
    6205                                                                 /* }}} */
    6206                                                         }
    6207 
    6208                                                         if (rules[rule].fallback) {
    6209                                                                 if (typeof changedate === 'undefined' || (typeof res[1] !== 'undefined' && res[1] < changedate))
    6210                                                                         changedate = res[1];
    6211 
    6212                                                                 // break rule; // Fallback rule matched, no need for checking the rest.
    6213                                                                 // WRONG: What if 'off' is used after fallback rule.
    6214                                                         }
    6215                                                 }
    6216                                         }
    6217                                         if (typeof changedate === 'undefined' || (typeof res[1] !== 'undefined' && res[1] < changedate))
    6218                                                 changedate = res[1];
    6219                                 }
    6220                         }
    6221 
    6222                         if (typeof rules[match_rule] === 'object' && typeof rules[match_rule].comment === 'string') {
    6223                                 /* Only use comment if one is explicitly specified. */
    6224                                 comment = rules[match_rule].comment;
    6225                         } else if (typeof comment === 'object') {
    6226                                 if (comment[1] === match_rule) {
    6227                                         comment = comment[0];
    6228                                 } else {
    6229                                         comment = undefined;
    6230                                 }
    6231                         }
    6232 
    6233                         // console.log('changedate', changedate, resultstate, comment, match_rule);
    6234                         return [ resultstate, changedate, unknown, comment, match_rule ];
    6235                 };
    6236                 // }}}
    6237 
    6238                 /* Generate prettified value for selector based on tokens. {{{
    6239                  *
    6240                  * :param tokens: List of token objects.
    6241                  * :param at: Position where to start.
    6242                  * :param last_at: Position where to stop.
    6243                  * :param conf: Configuration options.
    6244                  * :returns: Prettified value.
    6245                  */
    6246                 function prettifySelector(tokens, selector_start, selector_end, selector_type, conf) {
    6247 
    6248                         var value = '';
    6249                         var at = selector_start;
    6250                         while (at <= selector_end) {
    6251                                 // console.log('At: ' + at + ', token: ' + tokens[at]);
    6252                                 if (matchTokens(tokens, at, 'weekday')) {
    6253                                         if (!conf.leave_weekday_sep_one_day_betw
    6254                                                 && at - selector_start > 1 && (matchTokens(tokens, at-1, ',') || matchTokens(tokens, at-1, '-'))
    6255                                                 && matchTokens(tokens, at-2, 'weekday')
    6256                                                 && tokens[at][0] === (tokens[at-2][0] + 1) % 7) {
    6257                                                         value = value.substring(0, value.length - 1) + conf.sep_one_day_between;
    6258                                         }
    6259                                         value += weekdays[tokens[at][0]];
    6260                                 } else if (at - selector_start > 0 // e.g. '09:0' -> '09:00'
    6261                                                 && selector_type === 'time'
    6262                                                 && matchTokens(tokens, at-1, 'timesep')
    6263                                                 && matchTokens(tokens, at, 'number')) {
    6264                                         value += (tokens[at][0] < 10 ? '0' : '') + tokens[at][0].toString();
    6265                                 } else if (selector_type === 'time' // e.g. '9:00' -> ' 09:00'
    6266                                                 && conf.zero_pad_hour
    6267                                                 && at !== tokens.length
    6268                                                 && matchTokens(tokens, at, 'number')
    6269                                                 && matchTokens(tokens, at+1, 'timesep')) {
    6270                                         value += (
    6271                                                         tokens[at][0] < 10 ?
    6272                                                                 (tokens[at][0] === 0 && conf.one_zero_if_hour_zero ?
    6273                                                                  '' : '0') :
    6274                                                                 '') + tokens[at][0].toString();
    6275                                 } else if (selector_type === 'time' // e.g. '9-18' -> '09:00-18:00'
    6276                                                 && at + 2 <= selector_end
    6277                                                 && matchTokens(tokens, at, 'number')
    6278                                                 && matchTokens(tokens, at+1, '-')
    6279                                                 && matchTokens(tokens, at+2, 'number')) {
    6280                                         value += (tokens[at][0] < 10 ?
    6281                                                         (tokens[at][0] === 0 && conf.one_zero_if_hour_zero ? '' : '0')
    6282                                                         : '') + tokens[at][0].toString();
    6283                                         value += ':00-'
    6284                                                 + (tokens[at+2][0] < 10 ? '0' : '') + tokens[at+2][0].toString()
    6285                                                 + ':00';
    6286                                         at += 2;
    6287                                 } else if (matchTokens(tokens, at, 'comment')) {
    6288                                         value += '"' + tokens[at][0].toString() + '"';
    6289                                 } else if (matchTokens(tokens, at, 'closed')) {
    6290                                         value += (conf.leave_off_closed ? tokens[at][0] : conf.keyword_for_off_closed);
    6291                                 } else if (at - selector_start > 0 && matchTokens(tokens, at, 'number')
    6292                                                 && (matchTokens(tokens, at-1, 'month') && selector_type === 'month'
    6293                                                 ||  matchTokens(tokens, at-1, 'week')  && selector_type === 'week'
    6294                                                 )) {
    6295                                         value += ' '
    6296                                                 + (conf.zero_pad_month_and_week_numbers && tokens[at][0] < 10 ? '0' : '')
    6297                                                 + tokens[at][0];
    6298                                 } else if (at - selector_start > 0 && matchTokens(tokens, at, 'month')
    6299                                                 && matchTokens(tokens, at-1, 'year')) {
    6300                                         value += ' ' + months[[tokens[at][0]]];
    6301                                 } else if (at - selector_start > 0 && matchTokens(tokens, at, 'event')
    6302                                                 && matchTokens(tokens, at-1, 'year')) {
    6303                                         value += ' ' + tokens[at][0];
    6304                                 } else if (matchTokens(tokens, at, 'month')) {
    6305                                         value += months[[tokens[at][0]]];
    6306                                         if (at + 1 <= selector_end && matchTokens(tokens, at+1, 'weekday'))
    6307                                                 value += ' ';
    6308                                 } else if (at + 2 <= selector_end
    6309                                                 && (matchTokens(tokens, at, '-') || matchTokens(tokens, at, '+'))
    6310                                                 && matchTokens(tokens, at+1, 'number', 'calcday')) {
    6311                                         value += ' ' + tokens[at][0] + tokens[at+1][0] + ' day' + (Math.abs(tokens[at+1][0]) === 1 ? '' : 's');
    6312                                         at += 2;
    6313                                 } else if (at === selector_end
    6314                                                 && selector_type === 'weekday'
    6315                                                 && tokens[at][0] === ':') {
    6316                                         // Do nothing.
    6317                                 } else {
    6318                                         value += tokens[at][0].toString();
    6319                                 }
    6320                                 at++;
    6321                         }
    6322                         return value;
    6323                 }
    6324                 // }}}
    6325 
    6326                 //======================================================================
    6327                 // Public interface {{{
    6328                 // All functions below are considered public.
    6329                 //======================================================================
    6330 
    6331                 // Iterator interface {{{
    6332                 this.getIterator = function(date) {
    6333                         return new function(oh) {
    6334                                 if (typeof date === 'undefined')
    6335                                         date = new Date();
    6336 
    6337                                 var prevstate = [ undefined, date, undefined, undefined, undefined ];
    6338                                 var state = oh.getStatePair(date);
    6339 
    6340                                 /* getDate {{{ */
    6341                                 this.getDate = function() {
    6342                                         return prevstate[1];
    6343                                 };
    6344                                 /* }}} */
    6345 
    6346                                 /* setDate {{{ */
    6347                                 this.setDate = function(date) {
    6348                                         if (typeof date !== 'object')
    6349                                                 throw 'Date parameter needed.';
    6350 
    6351                                         prevstate = [ undefined, date, undefined, undefined, undefined ];
    6352                                         state     = oh.getStatePair(date);
    6353                                 };
    6354                                 /* }}} */
    6355 
    6356                                 /* getState: Check whether facility is `open' {{{ */
    6357                                 this.getState = function() {
    6358                                         return state[0];
    6359                                 };
    6360                                 /* }}} */
    6361 
    6362                                 /* getUnknown: Checks whether the opening state is conditional or unknown {{{ */
    6363                                 this.getUnknown = function() {
    6364                                         return state[2];
    6365                                 };
    6366                                 /* }}} */
    6367 
    6368                                 /* getStateString: Get state string. Either 'open', 'unknown' or 'closed' {{{ */
    6369                                 this.getStateString = function(past) {
    6370                                         return (state[0] ? 'open' : (state[2] ? 'unknown' : (past ? 'closed' : 'close')));
    6371                                 };
    6372                                 /* }}} */
    6373 
    6374                                 /* getComment: Get the comment, undefined in none {{{ */
    6375                                 this.getComment = function() {
    6376                                         return state[3];
    6377                                 };
    6378                                 /* }}} */
    6379 
    6380                                 /* getMatchingRule: Get the rule which matched thus deterrents the current state {{{ */
    6381                                 this.getMatchingRule = function() {
    6382                                         if (typeof state[4] === 'undefined')
    6383                                                 return undefined;
    6384 
    6385                                         return rules[state[4]].build_from_token_rule[2];
    6386                                 };
    6387                                 /* }}} */
    6388 
    6389                                 /* advance: Advances to the next position {{{ */
    6390                                 this.advance = function(datelimit) {
    6391                                         if (typeof datelimit === 'undefined')
    6392                                                 datelimit = new Date(prevstate[1].getTime() + msec_in_day * 366 * 5);
    6393                                         else if (datelimit.getTime() <= prevstate[1].getTime())
    6394                                                 return false; // The limit for advance needs to be after the current time.
    6395 
    6396                                         do {
    6397                                                 // open range, we won't be able to advance
    6398                                                 if (typeof state[1] === 'undefined')
    6399                                                         return false;
    6400 
    6401                                                 // console.log('\n' + 'previous check time:', prevstate[1]
    6402                                                         // + ', current check time:',
    6403                                                         // // (state[1].getHours() < 10 ? '0' : '') + state[1].getHours() +
    6404                                                         // // ':'+(state[1].getMinutes() < 10 ? '0' : '')+ state[1].getMinutes(), state[1].getDate(),
    6405                                                         // state[1],
    6406                                                         // (state[0] ? 'open' : (state[2] ? 'unknown' : 'closed')) + ', comment:', state[3]);
    6407 
    6408                                                 // We're going backwards or staying at place.
    6409                                                 // This always indicates coding error in a selector code.
    6410                                                 if (state[1].getTime() <= prevstate[1].getTime())
    6411                                                         throw 'Fatal: infinite loop in nextChange';
    6412 
    6413                                                 // don't advance beyond limits (same as open range)
    6414                                                 if (state[1].getTime() >= datelimit.getTime())
    6415                                                         return false;
    6416 
    6417                                                 // do advance
    6418                                                 prevstate = state;
    6419                                                 state = oh.getStatePair(prevstate[1]);
    6420                                         } while (state[0] === prevstate[0] && state[2] === prevstate[2] && state[3] === prevstate[3]);
    6421                                         return true;
    6422                                 };
    6423                                 /* }}} */
    6424                         }(this);
    6425                 };
    6426                 // }}}
    6427 
    6428                 // Simple API {{{
    6429 
    6430                 this.getState = function(date) {
    6431                         var it = this.getIterator(date);
    6432                         return it.getState();
    6433                 };
    6434 
    6435                 this.getUnknown = function(date) {
    6436                         var it = this.getIterator(date);
    6437                         return it.getUnknown();
    6438                 };
    6439 
    6440                 this.getStateString = function(date, past) {
    6441                         var it = this.getIterator(date);
    6442                         return it.getStateString(past);
    6443                 };
    6444 
    6445                 this.getComment = function(date) {
    6446                         var it = this.getIterator(date);
    6447                         return it.getComment();
    6448                 };
    6449 
    6450                 this.getMatchingRule = function(date) {
    6451                         var it = this.getIterator(date);
    6452                         return it.getMatchingRule();
    6453                 };
    6454 
    6455                 /* Not available for iterator API {{{ */
    6456                 /* getWarnings: Get warnings, empty list if none {{{ */
    6457                 this.getWarnings = function() {
    6458                         var it = this.getIterator();
    6459                         return getWarnings(it);
    6460                 };
    6461                 /* }}} */
    6462 
    6463                 /* prettifyValue: Get a nicely formated value {{{ */
    6464                 this.prettifyValue = function(argument_hash) {
    6465                         this.getWarnings();
    6466                         /* getWarnings has to be run before prettifyValue because some
    6467                          * decisions if a certain aspect makes sense to prettify or not
    6468                          * are based on the warnings.
    6469                          * Basically, both functions depend on each other in some way :(
    6470                          * See done_with_selector_reordering.
    6471                          */
    6472                         return prettifyValue(argument_hash);
    6473                 };
    6474                 /* }}} */
    6475 
    6476                 /* getNextChange: Get time of next status change {{{ */
    6477                 this.getNextChange = function(date, maxdate) {
    6478                         var it = this.getIterator(date);
    6479                         if (!it.advance(maxdate))
    6480                                 return undefined;
    6481                         return it.getDate();
    6482                 };
    6483                 /* }}} */
    6484 
    6485                 /* isWeekStable: Checks whether open intervals are same for every week. {{{ */
    6486                 this.isWeekStable = function() {
    6487                         return week_stable;
    6488                 };
    6489                 /* }}} */
    6490                 /* }}} */
    6491                 /* }}} */
    6492 
    6493                 // High-level API {{{
    6494 
    6495                 /* getOpenIntervals: Get array of open intervals between two dates {{{ */
    6496                 this.getOpenIntervals = function(from, to) {
    6497                         var res = [];
    6498 
    6499                         var it = this.getIterator(from);
    6500 
    6501                         if (it.getState() || it.getUnknown())
    6502                                 res.push([from, undefined, it.getUnknown(), it.getComment()]);
    6503 
    6504                         while (it.advance(to)) {
    6505                                 if (it.getState() || it.getUnknown()) {
    6506                                         if (res.length !== 0 && typeof res[res.length - 1][1] === 'undefined') {
    6507                                                 // last state was also open or unknown
    6508                                                 res[res.length - 1][1] = it.getDate();
    6509                                         }
    6510                                         res.push([it.getDate(), undefined, it.getUnknown(), it.getComment()]);
    6511                                 } else {
    6512                                         if (res.length !== 0 && typeof res[res.length - 1][1] === 'undefined') {
    6513                                                 // only use the first time as closing/change time and ignore closing times which might follow
    6514                                                 res[res.length - 1][1] = it.getDate();
    6515                                         }
    6516                                 }
    6517                         }
    6518 
    6519                         if (res.length > 0 && typeof res[res.length - 1][1] === 'undefined')
    6520                                 res[res.length - 1][1] = to;
    6521 
    6522                         return res;
    6523                 };
    6524                 /* }}} */
    6525 
    6526                 /* getOpenDuration: Get total number of milliseconds a facility is open,unknown within a given date range {{{ */
    6527                 this.getOpenDuration = function(from, to) {
    6528                 // console.log('-----------');
    6529 
    6530                         var open    = 0;
    6531                         var unknown = 0;
    6532 
    6533                         var it = this.getIterator(from);
    6534                         var prevdate    = (it.getState() || it.getUnknown()) ? from : undefined;
    6535                         var prevstate   = it.getState();
    6536                         var prevunknown = it.getUnknown();
    6537 
    6538                         while (it.advance(to)) {
    6539                                 if (it.getState() || it.getUnknown()) {
    6540 
    6541                                         if (typeof prevdate !== 'undefined') {
    6542                                                 // last state was also open or unknown
    6543                                                 if (prevunknown) //
    6544                                                         unknown += it.getDate().getTime() - prevdate.getTime();
    6545                                                 else if (prevstate)
    6546                                                         open    += it.getDate().getTime() - prevdate.getTime();
    6547                                         }
    6548 
    6549                                         prevdate    = it.getDate();
    6550                                         prevstate   = it.getState();
    6551                                         prevunknown = it.getUnknown();
    6552                                         // console.log('if', prevdate, open / (1000 * 60 * 60), unknown / (1000 * 60 * 60));
    6553                                 } else {
    6554                                         // console.log('else', prevdate);
    6555                                         if (typeof prevdate !== 'undefined') {
    6556                                                 if (prevunknown)
    6557                                                         unknown += it.getDate().getTime() - prevdate.getTime();
    6558                                                 else
    6559                                                         open    += it.getDate().getTime() - prevdate.getTime();
    6560                                                 prevdate = undefined;
    6561                                         }
    6562                                 }
    6563                         }
    6564 
    6565                         if (typeof prevdate !== 'undefined') {
    6566                                 if (prevunknown)
    6567                                         unknown += to.getTime() - prevdate.getTime();
    6568                                 else
    6569                                         open    += to.getTime() - prevdate.getTime();
    6570                         }
    6571 
    6572                         return [ open, unknown ];
    6573                 };
    6574                 /* }}} */
    6575                 /* }}} */
    6576                 /* }}} */
    6577         };
    6578 }));
    6579 // vim: set ts=4 sw=4 tw=0 noet foldmarker={{{,}}} foldlevel=0 foldmethod=marker :
     19(function(root,factory){var holidays={fr:{PH:{"Jour de l'an":[1,1],"Vendredi saint":["easter",-2,["Moselle","Bas-Rhin","Haut-Rhin","Guadeloupe","Martinique","Polynésie française"]],"Lundi de Pâques":["easter",1],"Saint-Pierre-Chanel":[4,28,["Wallis-et-Futuna"]],"Fête du Travail":[5,1],"Fête de la Victoire":[5,8],"Abolition de l'esclavage (Martinique)":[5,22,["Martinique"]],"Abolition de l'esclavage (Guadeloupe)":[5,27,["Guadeloupe"]],"Jeudi de l'Ascension":["easter",39],"Lundi de Pentecôte":["easter",50],"Abolition de l'esclavage (Guyane)":[6,10,["Guyane"]],"Fête de l'autonomie":[6,29,["Polynésie française"]],"Fête nationale":[7,14],"Fête Victor Schoelcher":[7,21,["Guadeloupe","Martinique"]],"Fête du Territoire":[7,29,["Wallis-et-Futuna"]],Assomption:[8,15],"Fête de la citoyenneté":[9,24,["Nouvelle-Calédonie"]],Toussaint:[11,1],Armistice:[11,11],"Abolition de l'esclavage (Réunion)":[12,20,["Réunion"]],"Noël":[12,25],"Saint-Étienne ":[12,26,["Moselle","Bas-Rhin","Haut-Rhin"]]}},de:{PH:{Neujahrstag:[1,1],"Heilige Drei Könige":[1,6,["Baden-Württemberg","Bayern","Sachsen-Anhalt"]],"Tag der Arbeit":[5,1],Karfreitag:["easter",-2],Ostersonntag:["easter",0,["Brandenburg"]],Ostermontag:["easter",1],"Christi Himmelfahrt":["easter",39],Pfingstsonntag:["easter",49,["Brandenburg"]],Pfingstmontag:["easter",50],Fronleichnam:["easter",60,["Baden-Württemberg","Bayern","Hessen","Nordrhein-Westfalen","Rheinland-Pfalz","Saarland"]],"Mariä Himmelfahrt":[8,15,["Saarland"]],"Tag der Deutschen Einheit":[10,3],Reformationstag:[10,31,["Brandenburg","Mecklenburg-Vorpommern","Sachsen","Sachsen-Anhalt","Thüringen"]],Allerheiligen:[11,1,["Baden-Württemberg","Bayern","Nordrhein-Westfalen","Rheinland-Pfalz","Saarland"]],"1. Weihnachtstag":[12,25],"2. Weihnachtstag":[12,26]},"Baden-Württemberg":{SH:[{name:"Osterferien",2005:[3,24,3,24,3,29,4,2],2006:[4,18,4,22],2007:[4,2,4,14],2008:[3,17,3,28],2009:[4,9,4,9,4,14,4,17],2010:[4,1,4,1,4,6,4,10],2011:[4,21,4,21,4,26,4,30],2012:[4,2,4,13],2013:[3,25,4,5],2014:[4,14,4,25],2015:[3,30,4,10],2016:[3,29,4,2],2017:[4,10,4,21]},{name:"Pfingstferien",2005:[5,17,5,28],2006:[5,29,6,10],2007:[5,29,6,9],2008:[5,13,5,23],2009:[5,25,6,6],2010:[5,25,6,5],2011:[6,14,6,25],2012:[5,29,6,9],2013:[5,21,6,1],2014:[6,10,6,21],2015:[5,26,6,6],2016:[5,17,5,28],2017:[6,6,6,16]},{name:"Sommerferien",2005:[7,28,9,10],2006:[8,3,9,16],2007:[7,26,9,8],2008:[7,24,9,6],2009:[7,30,9,12],2010:[7,29,9,11],2011:[7,28,9,10],2012:[7,26,9,8],2013:[7,25,9,7],2014:[7,31,9,13],2015:[7,30,9,12],2016:[7,28,9,10],2017:[7,27,9,9]},{name:"Herbstferien",2005:[11,2,11,4],2006:[10,30,11,3],2007:[10,29,11,3],2008:[10,27,10,31],2009:[10,26,10,31],2010:[11,2,11,6],2011:[10,31,10,31,11,2,11,4],2012:[10,29,11,2],2013:[10,28,10,30],2014:[10,27,10,30],2015:[11,2,11,6],2016:[11,2,11,4]},{name:"Weihnachtsferien",2005:[12,22,1,5],2006:[12,27,1,5],2007:[12,24,1,5],2008:[12,22,1,10],2009:[12,23,1,9],2010:[12,23,1,8],2011:[12,23,1,5],2012:[12,24,1,5],2013:[12,23,1,4],2014:[12,22,1,5],2015:[12,23,1,9],2016:[12,23,1,7]}]},"Mecklenburg-Vorpommern":{SH:[{name:"Winterferien",2010:[2,6,2,20],2011:[2,7,2,19],2012:[2,6,2,17],2013:[2,4,2,15],2014:[2,3,2,15],2015:[2,2,2,14],2016:[2,1,2,13],2017:[2,6,2,18]},{name:"Osterferien",2010:[3,29,4,7],2011:[4,16,4,27],2012:[4,2,4,11],2013:[3,25,4,3],2014:[4,14,4,23],2015:[3,30,4,8],2016:[3,21,3,30],2017:[4,10,4,19]},{name:"Pfingstferien",2010:[5,21,5,22],2011:[6,10,6,14],2012:[5,25,5,29],2013:[5,17,5,21],2014:[6,6,6,10],2015:[5,22,5,26],2016:[5,14,5,17],2017:[6,2,6,6]},{name:"Sommerferien",2010:[7,12,8,21],2011:[7,4,8,13],2012:[6,23,8,4],2013:[6,22,8,3],2014:[7,14,8,23],2015:[7,20,8,29],2016:[7,25,9,3],2017:[7,24,9,2]},{name:"Herbstferien",2010:[10,18,10,23],2011:[10,17,10,21],2012:[10,1,10,5],2013:[10,14,10,19],2014:[10,20,10,25],2015:[10,24,10,30],2016:[10,24,10,28]},{name:"Weihnachtsferien",2010:[12,23,12,31],2011:[12,23,1,3],2012:[12,21,1,4],2013:[12,23,1,3],2014:[12,22,1,2],2015:[12,21,1,2],2016:[12,22,1,2]}]},Hessen:{SH:[{name:"Osterferien",2010:[3,29,4,10],2011:[4,18,4,30],2012:[4,2,4,14],2013:[3,25,4,6],2014:[4,14,4,26],2015:[3,30,4,11],2016:[3,29,4,9],2017:[4,3,4,15],2018:[3,26,4,7]},{name:"Sommerferien",2010:[7,5,8,14],2011:[6,27,8,5],2012:[7,2,8,10],2013:[7,8,8,16],2014:[7,28,9,5],2015:[7,27,9,5],2016:[7,18,8,26],2017:[7,3,8,11]},{name:"Herbstferien",2010:[10,11,10,22],2011:[10,10,10,22],2012:[10,15,10,27],2013:[10,14,10,26],2014:[10,20,11,1],2015:[10,19,10,31],2016:[10,17,10,29],2017:[10,9,10,21]},{name:"Weihnachtsferien",2010:[12,20,1,7],2011:[12,21,1,6],2012:[12,24,1,12],2013:[12,23,1,11],2014:[12,22,1,10],2015:[12,23,1,9],2016:[12,22,1,7],2017:[12,24,1,13]}]},"Schleswig-Holstein":{SH:[{name:"Osterferien",2010:[4,3,4,17],2011:[4,15,4,30],2012:[3,30,4,13],2013:[3,25,4,9],2014:[4,16,5,2],2015:[4,1,4,17],2016:[3,24,4,9],2017:[4,7,4,21]},{name:"Sommerferien",2010:[7,12,8,21],2011:[7,4,8,13],2012:[6,25,8,4],2013:[6,24,8,3],2014:[7,14,8,23],2015:[7,20,8,29],2016:[7,25,9,3],2017:[7,24,9,2]},{name:"Pfingstferien",2011:[6,3,6,4],2012:[5,18,5,18],2013:[5,10,5,10],2014:[5,30,5,30],2015:[5,15,5,15],2016:[5,6,5,6],2017:[5,26,5,26]},{name:"Herbstferien",2010:[10,11,10,23],2011:[10,10,10,22],2012:[10,4,10,19],2013:[10,4,10,18],2014:[10,13,10,25],2015:[10,19,10,31],2016:[10,17,10,29]},{name:"Weihnachtsferien",2010:[12,23,1,7],2011:[12,23,1,6],2012:[12,24,1,5],2013:[12,23,1,6],2014:[12,22,1,6],2015:[12,21,1,6],2016:[12,23,1,6]}]},Berlin:{SH:[{name:"Winterferien",2010:[2,1,2,6],2011:[1,31,2,5],2012:[1,30,2,4],2013:[2,4,2,9],2014:[2,3,2,8],2015:[2,2,2,7],2016:[2,1,2,6],2017:[1,30,2,4]},{name:"Osterferien",2010:[3,31,4,10],2011:[4,18,4,30],2012:[4,2,4,14,4,30,4,30],2013:[3,25,4,6],2014:[4,14,4,26,5,2,5,2],2015:[3,30,4,11],2016:[3,21,4,2],2017:[4,10,4,22]},{name:"Pfingstferien",2010:[5,14,5,14,5,25,5,25],2011:[6,3,6,3],2012:[5,18,5,18],2013:[5,10,5,10,5,21,5,21],2014:[5,30,5,30],2015:[5,15,5,15],2016:[5,6,5,6,5,17,5,17],2017:[5,26,5,26]},{name:"Sommerferien",2010:[7,7,8,21],2011:[6,29,8,12],2012:[6,20,8,3],2013:[6,19,8,2],2014:[7,9,8,22],2015:[7,15,8,28],2016:[7,20,9,2],2017:[7,19,9,1]},{name:"Herbstferien",2010:[10,11,10,23],2011:[10,4,10,14],2012:[10,1,10,13],2013:[9,30,10,12],2014:[10,20,11,1],2015:[10,19,10,31],2016:[10,17,10,28]},{name:"Weihnachtsferien",2010:[12,23,1,1],2011:[12,23,1,3],2012:[12,24,1,4],2013:[12,23,1,3],2014:[12,22,1,2],2015:[12,23,1,2],2016:[12,23,1,3]}]},Saarland:{SH:[{name:"Winterferien",2010:[2,15,2,20],2011:[3,7,3,12],2012:[2,20,2,25],2013:[2,11,2,16],2014:[3,3,3,8],2015:[2,16,2,21]},{name:"Osterferien",2010:[3,29,4,10],2011:[4,18,4,30],2012:[4,2,4,14],2013:[3,25,4,6],2014:[4,14,4,26],2015:[3,30,4,11]},{name:"Sommerferien",2010:[7,5,8,14],2011:[6,24,8,6],2012:[7,2,8,14],2013:[7,8,8,17],2014:[7,28,9,6],2015:[7,27,9,4],2016:[7,18,8,26],2017:[7,3,8,14]},{name:"Herbstferien",2010:[10,11,10,23],2011:[10,4,10,15],2012:[10,22,11,3],2013:[10,21,11,2],2014:[10,20,10,31]},{name:"Weihnachtsferien",2010:[12,20,1,1],2011:[12,23,1,4],2012:[12,24,1,5],2013:[12,20,1,4],2014:[12,22,1,7]}]},Bremen:{SH:[{name:"Winterferien",2010:[2,1,2,2],2011:[1,31,2,1],2012:[1,30,1,31],2013:[1,31,2,1],2014:[1,30,1,31],2015:[2,2,2,3],2016:[1,28,1,29],2017:[1,30,1,31]},{name:"Osterferien",2010:[3,19,4,6],2011:[4,16,4,30],2012:[3,26,4,11,4,30,4,30],2013:[3,16,4,2],2014:[4,3,4,22,5,2,5,2],2015:[3,25,4,10],2016:[3,18,4,2],2017:[4,10,4,22]},{name:"Pfingstferien",2010:[5,14,5,14,5,25,5,25],2011:[6,3,6,3,6,14,6,14],2012:[5,18,5,18,5,29,5,29],2013:[5,10,5,10,5,21,5,21],2014:[5,30,5,30,6,10,6,10],2015:[5,15,5,15,5,26,5,26],2016:[5,6,5,6,5,17,5,17],2017:[5,26,5,26,6,6,6,6]},{name:"Sommerferien",2010:[6,24,8,4],2011:[7,7,8,17],2012:[7,23,8,31],2013:[6,27,8,7],2014:[7,31,9,10],2015:[7,23,9,2],2016:[6,23,8,3],2017:[6,22,8,2]},{name:"Herbstferien",2010:[10,9,10,23],2011:[10,17,10,29],2012:[10,22,11,3],2013:[10,4,10,18],2014:[10,27,11,8],2015:[10,19,10,31],2016:[10,4,10,15]},{name:"Weihnachtsferien",2010:[12,22,1,5],2011:[12,23,1,4],2012:[12,24,1,5],2013:[12,23,1,3],2014:[12,22,1,5],2015:[12,23,1,6],2016:[12,21,1,6]}]},Bayern:{SH:[{name:"Winterferien",2010:[2,15,2,20],2011:[3,7,3,11],2012:[2,20,2,24],2013:[2,11,2,15],2014:[3,3,3,7],2015:[2,16,2,20],2016:[2,8,2,12],2017:[2,27,3,3]},{name:"Osterferien",2010:[3,29,4,10],2011:[4,18,4,30],2012:[4,2,4,14],2013:[3,25,4,6],2014:[4,14,4,26],2015:[3,30,4,11],2016:[3,21,4,1],2017:[4,10,4,22]},{name:"Pfingstferien",2010:[5,25,6,5],2011:[6,14,6,25],2012:[5,29,6,9],2013:[5,21,5,31],2014:[6,10,6,21],2015:[5,26,6,5],2016:[5,17,5,28],2017:[6,6,6,16]},{name:"Sommerferien",2010:[8,2,9,13],2011:[7,30,9,12],2012:[8,1,9,12],2013:[7,31,9,11],2014:[7,30,9,15],2015:[8,1,9,14],2016:[7,30,9,12],2017:[7,29,9,11]},{name:"Herbstferien",2010:[11,2,11,5],2011:[10,31,11,5],2012:[10,29,11,3],2013:[10,28,10,31],2014:[10,27,10,31],2015:[11,2,11,7],2016:[10,31,11,4]},{name:"Weihnachtsferien",2010:[12,24,1,7],2011:[12,27,1,5],2012:[12,24,1,5],2013:[12,23,1,4],2014:[12,24,1,5],2015:[12,24,1,5],2016:[12,24,1,5]}]},Niedersachsen:{SH:[{name:"Winterferien",2010:[2,1,2,2],2011:[1,31,2,1],2012:[1,30,1,31],2013:[1,31,2,1],2014:[1,30,1,31],2015:[2,2,2,3],2016:[1,28,1,29],2017:[1,30,1,31]},{name:"Osterferien",2010:[3,19,4,6],2011:[4,16,4,30],2012:[3,26,4,11,4,30,4,30],2013:[3,16,4,2],2014:[4,3,4,22,5,2,5,2],2015:[3,25,4,10],2016:[3,18,4,2],2017:[4,10,4,22]},{name:"Pfingstferien",2010:[5,14,5,14,5,25,5,25],2011:[6,3,6,3,6,14,6,14],2012:[5,18,5,18,5,29,5,29],2013:[5,10,5,10,5,21,5,21],2014:[5,30,5,30,6,10,6,10],2015:[5,15,5,15,5,26,5,26],2016:[5,6,5,6,5,17,5,17],2017:[5,26,5,26,6,6,6,6]},{name:"Sommerferien",2010:[6,24,8,4],2011:[7,7,8,17],2012:[7,23,8,31],2013:[6,27,8,7],2014:[7,31,9,10],2015:[7,23,9,2],2016:[6,23,8,3],2017:[6,22,8,2]},{name:"Herbstferien",2010:[10,9,10,23],2011:[10,17,10,29],2012:[10,22,11,3],2013:[10,4,10,18],2014:[10,27,11,8],2015:[10,19,10,31],2016:[10,4,10,15]},{name:"Weihnachtsferien",2010:[12,22,1,5],2011:[12,23,1,4],2012:[12,24,1,5],2013:[12,23,1,3],2014:[12,22,1,5],2015:[12,23,1,6],2016:[12,21,1,6]}]},"Nordrhein-Westfalen":{SH:[{name:"Osterferien",2010:[3,27,4,10],2011:[4,18,4,30],2012:[4,2,4,14],2013:[3,25,4,6],2014:[4,14,4,26],2015:[3,30,4,11],2016:[3,21,4,2],2017:[4,10,4,22]},{name:"Pfingstferien",2010:[5,25,5,25],2012:[5,29,5,29],2013:[5,21,5,21],2014:[6,10,6,10],2015:[5,26,5,26],2016:[5,17,5,17],2017:[6,6,6,6]},{name:"Sommerferien",2010:[7,15,8,27],2011:[7,25,9,6],2012:[7,9,8,21],2013:[7,22,9,3],2014:[7,7,8,19],2015:[6,29,8,11],2016:[7,11,8,23],2017:[7,17,8,29]},{name:"Herbstferien",2010:[10,11,10,23],2011:[10,24,11,5],2012:[10,8,10,20],2013:[10,21,11,2],2014:[10,6,10,18],2015:[10,5,10,17],2016:[10,10,10,21]},{name:"Weihnachtsferien",2010:[12,24,1,8],2011:[12,23,1,6],2012:[12,21,1,4],2013:[12,23,1,7],2014:[12,22,1,6],2015:[12,23,1,6],2016:[12,23,1,6]}]},Sachsen:{SH:[{name:"Winterferien",2010:[2,8,2,20],2011:[2,12,2,26],2012:[2,13,2,25],2013:[2,4,2,15],2014:[2,17,3,1],2015:[2,9,2,21],2016:[2,8,2,20],2017:[2,13,2,24]},{name:"Osterferien",2010:[4,1,4,10],2011:[4,22,4,30],2012:[4,6,4,14],2013:[3,29,4,6],2014:[4,18,4,26],2015:[4,2,4,11],2016:[3,25,4,2],2017:[4,13,4,22]},{name:"Pfingstferien",2010:[5,14,5,14],2011:[6,3,6,3],2012:[5,18,5,18],2013:[5,10,5,10,5,18,5,22],2014:[5,30,5,30],2015:[5,15,5,15],2016:[5,6,5,6],2017:[5,26,5,26]},{name:"Sommerferien",2010:[6,28,8,6],2011:[7,11,8,19],2012:[7,23,8,31],2013:[7,15,8,23],2014:[7,21,8,29],2015:[7,13,8,21],2016:[6,27,8,5],2017:[6,26,8,4]},{name:"Herbstferien",2010:[10,4,10,16],2011:[10,17,10,28],2012:[10,22,11,2],2013:[10,21,11,1],2014:[10,20,10,31],2015:[10,12,10,24],2016:[10,3,10,15]},{name:"Weihnachtsferien",2010:[12,23,1,1],2011:[12,23,1,2],2012:[12,22,1,2],2013:[12,21,1,3],2014:[12,22,1,3],2015:[12,21,1,2],2016:[12,23,1,2]}]},"Thüringen":{SH:[{name:"Winterferien",2010:[2,1,2,6],2011:[1,31,2,5],2012:[2,6,2,11],2013:[2,18,2,23],2014:[2,17,2,22],2015:[2,2,2,7],2016:[2,1,2,6],2017:[2,6,2,11]},{name:"Osterferien",2010:[3,29,4,9],2011:[4,18,4,30],2012:[4,2,4,13],2013:[3,25,4,6],2014:[4,19,5,2],2015:[3,30,4,11],2016:[3,24,4,2],2017:[4,10,4,21]},{name:"Sommerferien",2010:[6,24,8,4],2011:[7,11,8,19],2012:[7,23,8,31],2013:[7,15,8,23],2014:[7,21,8,29],2015:[7,13,8,21],2016:[6,27,8,10],2017:[6,26,8,9]},{name:"Pfingstferien",2011:[6,11,6,14],2012:[5,25,5,29],2013:[5,10,5,10],2014:[5,30,5,30],2015:[5,15,5,15],2016:[5,6,5,6],2017:[5,26,5,26]},{name:"Herbstferien",2010:[10,9,10,23],2011:[10,17,10,28],2012:[10,22,11,3],2013:[10,21,11,2],2014:[10,6,10,18],2015:[10,5,10,17],2016:[10,10,10,22]},{name:"Weihnachtsferien",2010:[12,23,1,1],2011:[12,23,1,1],2012:[12,24,1,5],2013:[12,23,1,4],2014:[12,22,1,3],2015:[12,23,1,2],2016:[12,23,12,31]}]},Hamburg:{SH:[{name:"Winterferien",2010:[1,29,1,29],2011:[1,31,1,31],2012:[1,30,1,30],2013:[2,1,2,1],2014:[1,31,1,31],2015:[1,30,1,30],2016:[1,29,1,29],2017:[1,30,1,30]},{name:"Osterferien",2010:[3,8,3,20],2011:[3,7,3,18],2012:[3,5,3,16],2013:[3,4,3,15],2014:[3,3,3,14],2015:[3,2,3,13],2016:[3,7,3,18],2017:[3,6,3,17]},{name:"Pfingstferien",2010:[5,14,5,22],2011:[4,26,4,29,6,3,6,3],2012:[4,30,5,4,5,18,5,18],2013:[5,2,5,10],2014:[4,28,5,2,5,30,5,30],2015:[5,11,5,15],2016:[5,6,5,6,5,17,5,20],2017:[5,22,5,26]},{name:"Sommerferien",2010:[7,8,8,18],2011:[6,30,8,10],2012:[6,21,8,1],2013:[6,20,7,31],2014:[7,10,8,20],2015:[7,16,8,26],2016:[7,21,8,31],2017:[7,20,8,30]},{name:"Herbstferien",2010:[10,4,10,15],2011:[10,4,10,14],2012:[10,1,10,12],2013:[9,30,10,11],2014:[10,13,10,24],2015:[10,19,10,30],2016:[10,17,10,28]},{name:"Weihnachtsferien",2010:[12,23,1,3],2011:[12,27,1,6],2012:[12,21,1,4],2013:[12,19,1,3],2014:[12,22,1,6],2015:[12,21,1,1],2016:[12,27,1,6]}]},"Sachsen-Anhalt":{SH:[{name:"Winterferien",2010:[2,8,2,13],2011:[2,5,2,12],2012:[2,4,2,11],2013:[2,1,2,8],2014:[2,1,2,12],2015:[2,2,2,14],2016:[2,1,2,10],2017:[2,4,2,11]},{name:"Osterferien",2010:[3,29,4,9],2011:[4,18,4,27],2012:[4,2,4,7],2013:[3,25,3,30],2014:[4,14,4,17],2015:[4,2,4,2],2016:[3,24,3,24],2017:[4,10,4,13]},{name:"Pfingstferien",2010:[5,14,5,22],2011:[6,14,6,18],2012:[5,18,5,25],2013:[5,10,5,18],2014:[5,30,6,7],2015:[5,15,5,23],2016:[5,6,5,14],2017:[5,26,5,26]},{name:"Sommerferien",2010:[6,24,8,4],2011:[7,11,8,24],2012:[7,23,9,5],2013:[7,15,8,28],2014:[7,21,9,3],2015:[7,13,8,26],2016:[6,27,8,10],2017:[6,26,8,9]},{name:"Herbstferien",2010:[10,18,10,23],2011:[10,17,10,22],2012:[10,29,11,2],2013:[10,21,10,25],2014:[10,27,10,30],2015:[10,17,10,24],2016:[10,4,10,15]},{name:"Weihnachtsferien",2010:[12,22,1,5],2011:[12,22,1,7],2012:[12,19,1,4],2013:[12,21,1,3],2014:[12,22,1,5],2015:[12,21,1,5],2016:[12,19,1,2]}]},"Rheinland-Pfalz":{SH:[{name:"Osterferien",2010:[3,26,4,9],2011:[4,18,4,29],2012:[3,29,4,13],2013:[3,20,4,5],2014:[4,11,4,25],2015:[3,26,4,10],2016:[3,18,4,1],2017:[4,10,4,21]},{name:"Sommerferien",2010:[7,5,8,13],2011:[6,27,8,5],2012:[7,2,8,10],2013:[7,8,8,16],2014:[7,28,9,5],2015:[7,27,9,4],2016:[7,18,8,26],2017:[7,3,8,11]},{name:"Herbstferien",2010:[10,11,10,22],2011:[10,4,10,14],2012:[10,1,10,12],2013:[10,4,10,18],2014:[10,20,10,31],2015:[10,19,10,30],2016:[10,10,10,21]},{name:"Weihnachtsferien",2010:[12,23,1,7],2011:[12,22,1,6],2012:[12,20,1,4],2013:[12,23,1,7],2014:[12,22,1,7],2015:[12,23,1,8],2016:[12,22,1,6]}]},Brandenburg:{SH:[{name:"Winterferien",2010:[2,1,2,6],2011:[1,31,2,5],2012:[1,30,2,4],2013:[2,4,2,9],2014:[2,3,2,8],2015:[2,2,2,7],2016:[2,1,2,6],2017:[1,30,2,4]},{name:"Osterferien",2010:[3,31,4,10],2011:[4,20,4,30],2012:[4,4,4,14,4,30,4,30],2013:[3,27,4,6],2014:[4,16,4,26,5,2,5,2],2015:[4,1,4,11],2016:[3,23,4,2],2017:[4,12,4,22]},{name:"Pfingstferien",2010:[5,14,5,14],2011:[6,3,6,3],2012:[5,18,5,18],2013:[5,10,5,10],2014:[5,30,5,30],2015:[5,15,5,15],2016:[5,6,5,6,5,17,5,17],2017:[5,26,5,26]},{name:"Sommerferien",2010:[7,8,8,21],2011:[6,30,8,13],2012:[6,21,8,3],2013:[6,20,8,2],2014:[7,10,8,22],2015:[7,16,8,28],2016:[7,21,9,3],2017:[7,20,9,1]},{name:"Herbstferien",2010:[10,11,10,23],2011:[10,4,10,14],2012:[10,1,10,13],2013:[9,30,10,12,11,1,11,1],2014:[10,20,11,1],2015:[10,19,10,30],2016:[10,17,10,28]},{name:"Weihnachtsferien",2010:[12,23,1,1],2011:[12,23,1,3],2012:[12,24,1,4],2013:[12,23,1,3],2014:[12,22,1,2],2015:[12,23,1,2],2016:[12,23,1,3]}]}},at:{PH:{Neujahrstag:[1,1],"Heilige Drei Könige":[1,6],Ostermontag:["easter",1],Staatsfeiertag:[5,1],"Christi Himmelfahrt":["easter",39],Pfingstmontag:["easter",50],Fronleichnam:["easter",60],"Mariä Himmelfahrt":[8,15],Nationalfeiertag:[10,26],Allerheiligen:[11,1],"Mariä Empfängnis":[12,8],Christtag:[12,25],Stefanitag:[12,26]}},ca:{PH:{"New Year's Day":[1,1],"Good Friday":["easter",-2],"Canada Day":["canadaDay",0],"Labour Day":["firstSeptemberMonday",0],"Christmas Day":[12,25]},Alberta:{PH:{"New Year's Day":[1,1],"Alberta Family Day":["firstFebruaryMonday",14],"Good Friday":["easter",-2],"Easter Monday":["easter",1],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"Heritage Day":["firstAugustMonday",0],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25],"Boxing Day":[12,26]}},"British Columbia":{PH:{"New Year's Day":[1,1],"Family Day":["firstFebruaryMonday",7],"Good Friday":["easter",-2],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"British Columbia Day":["firstAugustMonday",0],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25]}},Manitoba:{PH:{"New Year's Day":[1,1],"Louis Riel Day":["firstFebruaryMonday",14],"Good Friday":["easter",-2],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"Civic Holiday":["firstAugustMonday",0],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25]}},"New Brunswick":{PH:{"New Year's Day":[1,1],"Good Friday":["easter",-2],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"New Brunswick Day":["firstAugustMonday",0],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25],"Boxing Day":[12,26]}},"Newfoundland and Labrador":{PH:{"New Year's Day":[1,1],"Saint Patrick's Day":[3,17],"Good Friday":["easter",-2],"Saint George's Day":[4,23],"Discovery Day":[6,24],"Memorial Day":[7,1],"Orangemen's Day":[7,12],"Labour Day":["firstSeptemberMonday",0],"Armistice Day":[11,11],"Christmas Day":[12,25]}},"Northwest Territories":{PH:{"New Year's Day":[1,1],"Good Friday":["easter",-2],"Victoria Day":["victoriaDay",0],"National Aboriginal Day":[6,21],"Canada Day":["canadaDay",0],"Civic Holiday":["firstAugustMonday",0],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25]}},"Nova Scotia":{PH:{"New Year's Day":[1,1],"Good Friday":["easter",-2],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"Natal Day":["firstAugustMonday",0],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25],"Boxing Day":[12,26]}},Nunavut:{PH:{"New Year's Day":[1,1],"Good Friday":["easter",-2],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"Nunavut Day":[7,9],"Civic Holiday":["firstAugustMonday",0],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25]}},Ontario:{PH:{"New Year's Day":[1,1],"Family Day":["firstFebruaryMonday",14],"Good Friday":["easter",-2],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"August Civic Public Holiday":["firstAugustMonday",0],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25],"Boxing Day":[12,26]}},"Prince Edward Island":{PH:{"New Year's Day":[1,1],"Islander Day":["firstFebruaryMonday",14],"Good Friday":["easter",-2],"Easter Monday":["easter",1],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"Civic Holiday":["firstAugustMonday",0],"Gold Cup Parade Day":["firstAugustMonday",18],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25],"Boxing Day":[12,26]}},Quebec:{PH:{"Jour de l'an":[1,1],"Vendredi saint":["easter",-2],"Lundi de Pâques":["easter",1],"Journée nationale des patriotes":["victoriaDay",0],"Fête nationale du Québec":[6,24],"Fête du Canada":["canadaDay",0],"Fête du Travail":["firstSeptemberMonday",0],"Jour de l'Action de grâce":["firstOctoberMonday",7],"Noël":[12,25]}},Saskatchewan:{PH:{"New Year's Day":[1,1],"Family Day":["firstFebruaryMonday",14],"Good Friday":["easter",-2],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"Saskatchewan Day":["firstAugustMonday",0],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25]}},Yukon:{PH:{"New Year's Day":[1,1],"Heritage Day":["lastFebruarySunday",-2],"Good Friday":["easter",-2],"Easter Monday":["easter",1],"Victoria Day":["victoriaDay",0],"Canada Day":["canadaDay",0],"Discovery Day":["firstAugustMonday",14],"Labour Day":["firstSeptemberMonday",0],Thanksgiving:["firstOctoberMonday",7],"Remembrance Day":[11,11],"Christmas Day":[12,25],"Boxing Day":[12,26]}}},ru:{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12]},Tatarstan:{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"Ураза-байрам":[7,28],"День Республики Татарстан":[8,30],"Курбан-байрам":[10,4],"День Конституции Республики Татарстан":[11,6]}},Bashkortostan:{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"Ураза-байрам":[7,28],"Курбан-байрам":[10,4],"День Республики Башкирии":[10,11],"День Конституции Башкортостана":[12,24]}},Chuvashia:{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День Чувашской республики":[6,24]}},"Sakha Republic":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День Республики Саха":[4,27],"Ысыах":[6,23],"День государственности Республики Саха":[9,27]}},"Republic of Kalmykia":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"Цаган Сар":[1,14],"День принятия Степного Уложения (Конституции) Республики Калмыкия":[4,5],"День рождения Будды Шакьямун":[6,6],"Зул":[12,15],"День памяти жертв депортации калмыцкого народа":[12,28]}},Buryatia:{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"Сагаалган":[1,14]}},"Republic of Karelia":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День Республики Карелия":[6,8],"День освобождения Карелии от фашистских захватчиков":[9,30]}},"Удмуртская республика":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День Государственности Удмуртской Республики":[5,31]}},Adygea:{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"Ураза-байрам":[7,28],"Курбан-байрам":[10,4],"День образования Республики Адыгея":[10,5]}},"Republic of Dagestan":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День Конституции Республики Дагестан":[7,26],"Ураза-байрам":[7,28],"День единства народов Дагестана":[9,15],"Курбан-байрам":[10,4]}},Ingushetia:{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День образования Республики Ингушетия":[6,4],"Ураза-байрам":[7,28],"Курбан-байрам":[10,4]}},"Карачаево-Черкесская республика":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День возрождения карачаевского народа":[5,3],"Ураза-байрам":[7,28],"Курбан-байрам":[10,4]}},"Chechen Republic":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День мира в Чеченской Республике":[4,16],"Ураза-байрам":[7,28],"Курбан-байрам":[10,4]}},"Кабардино-Балкарская республика":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День возрождения балкарского народа":[3,28],"Черкесский день траура":[5,21],"Ураза-байрам":[7,28],"День государственности Кабардино-Балкарской Республики":[9,1],"Курбан-байрам":[10,4]}},"Altai Republic":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"Чага-Байрам":[1,14]}},Tuva:{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"Народный праздник Шагаа":[1,14],"День Республики Тыва":[8,15]}},"Saratov Oblast":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"Радоница":[4,29]}},"Bryansk Oblast":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"Радоница":[4,29],"День освобождения города Брянска":[9,17]}},"Komi Republic":{PH:{"1. Новогодние каникулы":[1,1],"2. Новогодние каникулы":[1,2],"3. Новогодние каникулы":[1,3],"4. Новогодние каникулы":[1,4],"5. Новогодние каникулы":[1,5],"6. Новогодние каникулы":[1,6],"Рождество Христово":[1,7],"8. Новогодние каникулы":[1,8],"День защитника Отечества":[2,23],"Международный женский день":[3,8],"День Победы":[5,9],"Праздник Весны и Труда":[5,1],"День народного единства":[11,4],"День России":[6,12],"День Республики Коми":[8,22]}}},ua:{PH:{"Новий рік":[1,1],"Різдво":[1,7],"Міжнародний жіночий день":[3,8],"Великдень":["orthodox easter",1],"День Праці 1":[5,1],"День Праці 2":[5,2],"День Перемоги":[5,9],"День Конституції України":[6,28],"День Незалежності України":[8,24]}},us:{PH:{"New Year's Day":[1,1],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],
     20"Christmas Day":[12,25]},Alabama:{PH:{"New Year's Day":[1,1],"Robert E. Lee/Martin Luther King Birthday":["firstJanuaryMonday",14],"George Washington/Thomas Jefferson Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Confederate Memorial Day":["firstAprilMonday",21],"Jefferson Davis' Birthday":["firstJuneMonday",0]}},Alaska:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Seward's Day":["lastMarchMonday",0],"Alaska Day":[10,18]}},Arizona:{PH:{"New Year's Day":[1,1],"Dr. Martin Luther King Jr./Civil Rights Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Arkansas:{PH:{"New Year's Day":[1,1],"Dr. Martin Luther King Jr. and Robert E. Lee's Birthdays":["firstJanuaryMonday",14],"George Washington's Birthday and Daisy Gatson Bates Day":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Eve":[12,24],"Christmas Day":[12,25]}},California:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"César Chávez Day":[3,31]}},Colorado:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Connecticut:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Lincoln's Birthday":[2,12],"Good Friday":["easter",-2]}},Delaware:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Day After Thanksgiving":["firstNovemberThursday",22],"Christmas Day":[12,25],"Good Friday":["easter",-2]}},"District of Columbia":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Emancipation Day":[4,16]}},Florida:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Friday after Thanksgiving":["firstNovemberThursday",22],"Christmas Day":[12,25]}},Georgia:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Robert E. Lee's Birthday":["firstNovemberThursday",22],"Washington's Birthday":[12,24],"Christmas Day":[12,25],"Confederate Memorial Day":["lastAprilMonday",0]}},Guam:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],"Guam Discovery Day":[3,5],"Good Friday":["easter",-2],"Liberation Day":[7,21],"All Souls' Day":[11,2],Thanksgiving:["firstNovemberThursday",21],"Lady of Camarin Day":[12,8],"Christmas Day":[12,25]}},Hawaii:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Prince Jonah Kuhio Kalanianaole Day":[3,26],"Kamehameha Day":[6,11],"Statehood Day":["firstAugustFriday",14],"Election Day":["firstNovemberMonday",1]}},Idaho:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr.-Idaho Human Rights Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Illinois:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Lincoln's Birthday":[2,12],"Casimir Pulaski Day":["firstMarchMonday",0],"Election Day":["firstNovemberMonday",1]}},Indiana:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Lincoln's Birthday":["firstNovemberThursday",22],"Christmas Day":[12,25],"Good Friday":["easter",-2],"Primary Election Day":["firstMayMonday",1],"Election Day":["firstNovemberMonday",1]}},Iowa:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Lincoln's Birthday":[2,12]}},Kansas:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Kentucky:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Eve":[12,24],"Christmas Day":[12,25],"New Year's Eve":[12,31],"Good Friday":["easter",-2]}},Louisiana:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Mardi Gras":["easter",-47],"Good Friday":["easter",-2],"Election Day":["firstNovemberMonday",1]}},Maine:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Patriots' Day":["firstAprilMonday",14]}},Maryland:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Native American Heritage Day":["firstNovemberThursday",22],"Christmas Day":[12,25]}},Massachusetts:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Patriots' Day":["firstAprilMonday",14]}},Michigan:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Eve":[12,24],"Christmas Day":[12,25],"New Year's Eve":[12,31]}},Minnesota:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Mississippi:{PH:{"New Year's Day":[1,1],"Martin Luther King's and Robert E. Lee's Birthdays":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Confederate Memorial Day":["lastAprilMonday",0]}},Missouri:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Truman Day":[5,8]}},Montana:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Election Day":["firstNovemberMonday",1],"Christmas Eve":[12,24],"New Year's Eve":[12,31]}},Nebraska:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Arbor Day":["lastAprilFriday",0]}},Nevada:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Nevada Day":["lastOctoberFriday",0],"Family Day":["firstNovemberThursday",22]}},"New Hampshire":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Civil Rights Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Day after Thanksgiving":["firstNovemberThursday",22],"Christmas Day":[12,25],"Election Day":["firstNovemberMonday",1]}},"New Jersey":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Lincoln's Birthday":[2,12],"Good Friday":["easter",-2],"Election Day":["firstNovemberMonday",1]}},"New Mexico":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Day after Thanksgiving":["firstNovemberThursday",22],"Christmas Day":[12,25]}},"New York":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Lincoln's Birthday":[2,12],"Election Day":["firstNovemberMonday",1]}},"North Carolina":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Day after Thanksgiving":["firstNovemberThursday",22],"Christmas Eve":[12,24],"Christmas Day":[12,25],"Day after Christmas":[12,26],"Good Friday":["easter",-2]}},"North Dakota":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Ohio:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Oklahoma:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Day after Thanksgiving":["firstNovemberThursday",22],"Christmas Day":[12,25]}},Oregon:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Pennsylvania:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Flag Day":[6,14]}},"Puerto Rico":{PH:{"Día de Año Nuevo":[1,1],"Día de Reyes":[1,6],"Natalicio de Eugenio María de Hostos":["firstJanuaryMonday",7],"Natalicio de Martin Luther King, Jr.":["firstJanuaryMonday",14],"Día de los Presidentes":["firstFebruaryMonday",14],"Día de la Abolición de Esclavitud":[3,22],"Viernes Santo":["easter",-2],"Natalicio de José de Diego":["firstAprilMonday",14],"Recordación de los Muertos de la Guerra":["lastMayMonday",0],"Día de la Independencia":[7,4],"Constitución de Puerto Rico":[7,25],"Natalicio de Dr. José Celso Barbosa":[7,27],"Día del Trabajo":["firstSeptemberMonday",0],"Día de la Raza Descubrimiento de América":["firstOctoberMonday",7],"Día del Veterano":[11,11],"Día del Descubrimiento de Puerto Rico":[11,19],"Día de Acción de Gracias":["firstNovemberThursday",21],"Noche Buena":[12,24],"Día de Navidad":[12,25]}},"Rhode Island":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Victory Day":["firstAugustMonday",7]}},"South Carolina":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Confederate Memorial Day":[5,10]}},"South Dakota":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Native American Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Tennessee:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Eve":[12,24],"Christmas Day":[12,25],"Good Friday":["easter",-2]}},Texas:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Friday after Thanksgiving":["firstNovemberThursday",22],"Christmas Eve":[12,24],"Christmas Day":[12,25],"Day after Christmas":[12,26]}},"United States Virgin Islands":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Virgin Islands-Puerto Rico Friendship Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Three Kings Day":[1,6],"Transfer Day":[3,31],"Holy Thursday":["easter",-3],"Good Friday":["easter",-2],"Easter Monday":["easter",1],"Emancipation Day":[7,3],"Hurricane Supplication Day":["firstJulyMonday",21],"Hurricane Thanksgiving":[10,25],"Liberty Day":[11,1],"Christmas Second Day":[12,26],"New Year's Eve":[12,31]}},Utah:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Pioneer Day":[7,24]}},Vermont:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Town Meeting Day":["firstMarchTuesday",0],"Battle of Bennington":["firstAugustMonday",14]}},Virginia:{PH:{"New Year's Day":[1,1],"Lee-Jackson Day":["firstJanuaryMonday",11],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},Washington:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}},"West Virginia":{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"West Virginia Day":[6,20],"Lincoln's Day":["firstNovemberThursday",22]}},Wisconsin:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25],"Primary Election Day":["firstAugustTuesday",7],"Election Day":["firstNovemberMonday",1]}},Wyoming:{PH:{"New Year's Day":[1,1],"Martin Luther King, Jr. Day":["firstJanuaryMonday",14],"Washington's Birthday":["firstFebruaryMonday",14],"Memorial Day":["lastMayMonday",0],"Independence Day":[7,4],"Labor Day":["firstSeptemberMonday",0],"Columbus Day":["firstOctoberMonday",7],"Veterans Day":[11,11],Thanksgiving:["firstNovemberThursday",21],"Christmas Day":[12,25]}}},si:{PH:{"novo leto":[1,1],"Prešernov dan, slovenski kulturni praznik":[2,8],"velikonočna nedelja":["easter",0],"velikonočni ponedeljek":["easter",1],"dan upora proti okupatorju":[4,27],"praznik dela 1":[5,1],"praznik dela 2":[5,2],"binkoštna nedelja - binkošti":["easter",49],"dan državnosti":[6,25],"Marijino vnebovzetje":[8,15],"dan reformacije":[10,31],"dan spomina na mrtve":[11,1],"božič":[12,25],"dan samostojnosti in enotnosti":[12,26]}},it:{PH:{Capodanno:[1,1],Epifania:[1,6],"Liberazione dal nazifascismo (1945)":[4,25],Pasqua:["easter",0],"Lunedì di Pasqua":["easter",1],"Festa del lavoro":[5,1],"Festa della Repubblica":[6,2],"Assunzione di Maria":[8,15],Ognissanti:[11,1],"Festa dell’unità nazionale":["firstSeptemberSunday",0],"Immacolata Concezione":[12,8],"Natale di Gesù":[12,25],"Santo Stefano":[12,26]}},cz:{PH:{"Den obnovy samostatného českého státu":[1,1],"Velikonoční pondělí":["easter",1],"Svátek práce":[5,1],"Den vítězství":[5,8],"Den slovanských věrozvěstů Cyrila a Metoděje":[7,5],"Den upálení mistra Jana Husa":[7,6],"Den české státnosti":[9,28],"Den vzniku samostatného československého státu":[10,28],"Den boje za svobodu a demokracii":[11,17],"Štědrý den":[12,24],"1. svátek vánoční":[12,25],"2. svátek vánoční":[12,26]}}};var word_error_correction={wrong_words:{'Assuming "<ok>" for "<ko>".':{daytime:"sunrise-sunset",spring:"Mar-May",summer:"Jun-Aug",autumn:"Sep-Nov",winter:"Dec-Feb",_:"-","=":"-"},'"<ko>" wird als "<ok>" interpertiert.':{"frühling":"Mar-May","frühjahr":"Mar-May",sommer:"Jun-Aug",herbst:"Sep-Nov"},'Bitte benutze die englische Schreibweise "<ok>" für "<ko>".':{"werktags?":"Mo-Fr"},'Bitte benutze "<ok>" für "<ko>". Beispiel: "Mo-Fr 08:00-12:00; Tu off".':{"ruhetage?":"off",geschlossen:"off",geschl:"off"},'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.':{gesloten:"off",feestdag:"PH",feestdagen:"PH"},'Assuming "<ok>" for "<ko>". Please avoid using "workday": https://wiki.openstreetmap.org/wiki/Talk:Key:opening_hours#need_syntax_for_holidays_and_workingdays':{wd:"Mo-Fr","on work days?":"Mo-Fr","weekdays?":"Mo-Fr",vardagar:"Mo-Fr"},'Please use something like "Mo off" instead "<ko>".':{except:"off"},'Please omit "<ko>" or use a colon instead: "12:00-14:00".':{h:""},'Please omit "<ko>".':{season:"",hs:"",hrs:"",hours:""},'Please omit "<ko>". The key must not be in the value.':{"opening_hours\\s*=":""},'Please omit "<ko>". You might want to express open end which can be specified as "12:00+" for example.':{from:""},'You can use notation "<ok>" for "<ko>" in the case that you want to express open end times. Example: "12:00+".':{"(:?bis|till?|-|–)? ?(?:open ?end|late)":"+"},'Please use notation "<ok>" for "<ko>". If the times are unsure or vary consider a comment e.g. 12:00-14:00 "only on sunshine".':{"~":"-","~":"-"},'Please use notation "<ok>" for "<ko>". Fallback rule: 12:00-14:00 || "call us"':{otherwise:"||"},'You can use notation "<ok>" for "?" temporally if the syntax will still be valid.':{"\\?":'unknown "please add this if known"'},'Please use notation "<ok>" for "<ko>". Although using "–" is typographical correct, the opening_hours syntax is defined with the normal hyphen. Correct typography should be done on application level …':{"–":"-"},'Please use notation "<ok>" for "<ko>".':{"→":"-","−":"-","—":"-","ー":"-",to:"-","до":"-",a:"-",as:"-","á":"-","ás":"-","às":"-",ate:"-","till?":"-",until:"-",through:"-",and:",","&":",",":":":","°°":":00",always:"24/7","always open":"24/7","always closed":"closed",nonstop:"24/7","24x7":"24/7",anytime:"24/7","all day":"24/7",daily:"Mo-Su",everyday:"Mo-Su","every day":"Mo-Su","all days":"Mo-Su","7j/7":"Mo-Su","7/7":"Mo-Su","7days":"Mo-Su","7 days":"Mo-Su","7 days a week":"Mo-Su","7 days/week":"Mo-Su","24 hours 7 days a week":"24/7","24 hours":"00:00-24:00",midday:"12:00",midnight:"00:00","(?:public )?holidays?":"PH","(?:one )?day after public holiday":"PH +1 day","(?:one )?day before public holiday":"PH -1 day","school ?holidays?":"SH","weekends?":"Sa,Su",daylight:"sunrise-sunset","(?:on|by)?(?:_| )?appointments?":'"on appointment"'},'Please use notation "<ok>" for "<ko>". Those characters look very similar but are not the same!':{"оff":"off"},'Please use time format in 24 hours notation ("<ko>"). If PM is used you might have to convert the hours to the 24 hours notation.':{pm:"","рм":"",am:"","ам":""},'Bitte verzichte auf "<ko>".':{uhr:"","geöffnet":"",zwischen:"",ist:"",durchgehend:"","öffnungszeit(?:en)?:?":""},'Bitte verzichte auf "<ko>". Sie möchten eventuell eine Öffnungszeit ohne vorgegebenes Ende (Open End) angeben. Beispiel: "12:00+"':{ab:"",von:""},'Es sieht so aus also möchten Sie zusätzliche Einschränkungen für eine Öffnungszeit geben. Falls sich dies nicht mit der Syntax ausdrücken lässt können Kommentare verwendet werden. Zusätzlich sollte eventuell das Schlüsselwort `open` benutzt werden. Bitte probiere "<ok>" für "<ko>".':{damen:'open "Damen"',herren:'open "Herren"'},'Bitte benutze die Schreibweise "<ok>" für "<ko>".':{bis:"-","täglich":"Mo-Su","(?:schul)?ferien":"SH","(?:an|nur)? ?sonn-?(?: und |/)feiertag(?:s|en?)?":"PH,Su","nach(?: |_)vereinbarung":'"Nach Vereinbarung"',"nach(?: |_)absprache":'"Nach Absprache"'},'Bitte benutze die Schreibweise "<ok>" für "<ko>". Es ist war typografisch korrekt aber laut der Spezifikation für opening_hours nicht erlaubt. Siehe auch: https://wiki.openstreetmap.org/wiki/DE:Key:opening_hours/specification.':{"„":'"',"“":'"',"”":'"'},'Please use notation "<ok>" for "<ko>". The used quote signs might be typographically correct but are not defined in the specification. See https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification.':{"«":'"',"»":'"',"‚":'"',"‘":'"',"’":'"',"「":'"',"」":'"',"『":'"',"』":'"'},'Please use notation "<ok>" for "<ko>". The used quote signs are not defined in the specification. See https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification.':{"'":'"'},'You might want to use comments instead of brackets (which are not valid in this context). If you do, replace "<ok>" with "<ko>".':{},'Bitte benutze die Schreibweise "<ok>" als Ersatz für "<ko>".':{und:",",u:",",auch:","},'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".':{"(?:an )?feiertag(?:s|en?)?":"PH"},'S\'il vous plaît utiliser "<ok>" pour "<ko>".':{"fermé":"off",et:",","à":"-","jours fériés":"PH"}},month:{"default":{jan:0,feb:1,mar:2,apr:3,may:4,jun:5,jul:6,aug:7,sep:8,oct:9,nov:10,dec:11},'Please use the English abbreviation "<ok>" for "<ko>".':{"jänner":0,january:0,february:1,march:2,april:3,june:5,july:6,august:7,september:8,sept:8,october:9,november:10,december:11},'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".':{januar:0,februar:1,"märz":2,maerz:2,mai:4,juni:5,juli:6,okt:9,oktober:9,dez:11,dezember:11},'S\'il vous plaît utiliser l\'abréviation "<ok>" pour "<ko>".':{janvier:0,"février":1,"fév":1,mars:2,avril:3,avr:3,mai:4,juin:5,juillet:6,"août":7,"aoû":7,septembre:8,octobre:9,novembre:10,"décembre":11},'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.':{januari:0,februari:1,maart:2,mei:4,augustus:7}},calcday:{"default":{day:"day",days:"days"}},weekday:{"default":{su:0,mo:1,tu:2,we:3,th:4,fr:5,sa:6},'Assuming "<ok>" for "<ko>"':{m:1,w:3,f:5},'Please use the abbreviation "<ok>" for "<ko>".':{sun:0,sunday:0,"sundays?":0,mon:1,"mondays?":1,"tues?":2,"tuesdays?":2,"weds?":3,"wednesdays?":3,thu:4,"thurs?":4,"thursdays?":4,fri:5,"fridays?":5,sat:6,"saturdays?":6},'Bitte benutze die englische Abkürzung "<ok>" für "<ko>". Could also mean Saturday in Polish …':{so:0},'Bitte benutze die englische Abkürzung "<ok>" für "<ko>".':{son:0,"sonn-":0,"sonntags?":0,"montags?":1,di:2,"die?":2,"dienstags?":2,mi:3,"mit?":3,"mittwochs?":3,"don?":4,"donnerstags?":4,fre:5,"freitags?":5,sam:6,"samstags?":6},'S\'il vous plaît utiliser l\'abréviation "<ok>" pour "<ko>".':{dim:0,dimanche:0,"lun?":1,lundi:1,mardi:2,mer:3,mercredi:3,"jeu?":4,jeudi:4,"ven?":5,vendredi:5,samedi:6},'Neem de engelse afkorting "<ok>" voor "<ko>" alstublieft.':{"zon?":0,zontag:0,zondag:0,maandag:1,din:2,dinsdag:2,"woe?":3,woensdag:3,donderdag:4,"vri?":5,vrijdag:5,"zat?":6,zaterdag:6},'Please use the English abbreviation "<ok>" for "<ko>".':{
     21"neděle":0,ne:0,"pondělí":1,po:1,"úterý":2,"út":2,"středa":3,st:3,"čtvrtek":4,"čt":4,"pátek":5,"pá":5,sobota:6},'Please use the English abbreviation "<ok>" (Spanish) for "<ko>".':{martes:0,"miércoles":1,jueves:2,viernes:3,"sábado":4,domingo:5,lunes:6},'Please use the English abbreviation "<ok>" (Indonesian) for "<ko>".':{selasa:0,rabu:1,kami:2,jumat:3,sabtu:4,minggu:5,senin:6},'Please use the English abbreviation "<ok>" (Swedish) for "<ko>".':{"söndag":0,"söndagar":0,"måndag":1,ma:1,tisdag:2,onsdag:3,torsdag:4,fredag:5,"lördag":6,"lördagar":6},'Please use the English abbreviation "<ok>" (Polish) for "<ko>".':{niedziela:0,niedz:0,n:0,ndz:0,"poniedziałek":1,poniedzialek:1,pon:1,pn:1,wtorek:2,wt:2,"środa":3,sroda:3,"śr":3,sr:3,czwartek:4,czw:4,cz:4,"piątek":5,piatek:5,pt:5,sobota:6,sob:6},'Please use the English abbreviation "<ok>" (Russian) for "<ko>".':{"воскресенье":0,"Вс":0,"voskresen'ye":0,"понедельник":1,"Пн":1,"ponedel'nik":1,"вторник":2,vtornik:2,"среда":3,sreda:3,"четверг":4,chetverk:4,"пятница":5,pyatnitsa:5,"суббота":6,subbota:6},'Please use the English abbreviation "<ok>" (Danish) for "<ko>".':{"søndag":0,mandag:1,tirsdag:2,onsdag:3,torsdag:4,fredag:5,"lørdag":6}},timevar:{"default":{sunrise:"sunrise",sunset:"sunset",dawn:"dawn",dusk:"dusk"},'Please use notation "<ok>" for "<ko>".':{sundown:"sunset"},'Bitte benutze die Schreibweise "<ok>" für "<ko>".':{"morgendämmerung":"dawn","abenddämmerung":"dusk",sonnenaufgang:"sunrise",sonnenuntergang:"sunset"}},event:{"default":{easter:"easter"},'Bitte benutze die Schreibweise "<ok>" für "<ko>".':{ostern:"easter"}}};var lang={"unexpected token":'Unexpected token: "__token__" This means that the syntax is not valid at that point or it is currently not supported.',"no string":"The value (first parameter) is not a string.",nothing:"The value contains nothing meaningful which can be parsed.","nothing useful":"This rule does not contain anything useful. Please remove this empty rule.","programmers joke":"Might it be possible that you are a programmer and adding a semicolon after each statement is hardwired in your muscle memory ;) ?"+" The thing is that the semicolon in the opening_hours syntax is defined as rule separator."+" So for compatibility reasons you should omit this last semicolon.","interpreted as year":"The number __number__ will be interpreted as year."+' This is probably not intended. Times can be specified as "12:00".',"rule before fallback empty":"Rule before fallback rule does not contain anything useful","hour min seperator":'Please use ":" as hour/minute-separator',"warnings severity":'The parameter optional_conf_parm["warnings_severity"] must be an integer number between 0 and 7 (inclusive).'+" Given __severity__"+", expected one of the following numbers: __allowed__.","optional conf parm type":"The optional_conf_parm parameter is of unknown type."+" Given __given__","conf param tag key missing":'The optional_conf_parm["tag_key"] is missing, required by optional_conf_parm["map_value"].',"conf param mode invalid":'The optional_conf_parm["mode"] parameter is a invalid number.'+" Gave __given__"+", expected one of the following numbers: __allowed__.","conf param unkown type":'The optional_conf_parm["__key__"] parameter is of unknown type.'+" Given __given__"+", expected __expected__.","library bug":'An error occurred during evaluation of the value "__value__".'+" Please file a bug report here: __url__.__message__","use multi":'You have used __count__ __part2__ Rules can be separated by ";".',"selector multi 2a":"__what__ in one rule. You may only use one in one rule.","selector multi 2b":"not connected __what__ in one rule. This is probably an error."+" Equal selector types can (and should) always be written in conjunction separated by comma."+' Example for time ranges "12:00-13:00,15:00-18:00".'+' Example for weekdays "Mo-We,Fr".',"selector state":"state keywords",comments:"comments","holiday ranges":"holiday ranges",months:"months",weekdays:"weekdays",ranges:"ranges","default state":"This rule which changes the default state (which is closed) for all following rules is not the first rule."+" The rule will overwrite all previous rules."+" It can be legitimate to change the default state to open for example"+" and then only specify for which times the facility is closed.",vague:"This rule is not very explicit because there is no time selector being used."+" Please add a time selector to this rule or use a comment to make it more explicit.","empty comment":"You have used an empty comment."+" Please either write something in the comment or use the keyword unknown instead.",separator_for_readability:"You have used the optional symbol <separator_for_readability> in the wrong place."+" Please check the syntax specification to see where it could be used or remove it.","strange 24/7":'You used 24/7 in a way that is probably not interpreted as "24 hours 7 days a week".'+' For correctness you might want to use "open" or "closed"'+" for this rule and then write your exceptions which should achieve the same goal and is more clear"+' e.g. "open; Mo 12:00-14:00 off".',"public holiday":"There was no PH (public holiday) specified. This is not very explicit.__part2__"+' Please either append a "PH off" rule if the amenity is closed on all public holidays'+' or use something like "Sa,Su,PH 12:00-16:00" to say that on Saturdays, Sundays and on public holidays the amenity is open 12:00-16:00.'+" If you are not certain try to find it out. If you can’t then do not add PH to the value and ignore this warning.","public holiday part2":' Unfortunately the tag key (e.g. "opening_hours", or "lit") is unknown to opening_hours.js. '+"This warning only applies to the key __keys__. If your value is for that key than read on. If not you can ignore the following.",switched:'The selector "__first__" was switched with'+' the selector "__second__"'+" for readablitity and compatibiltity reasons.","no colon after":'Please don’t use ":" after __token__.',"number -5 to 5":"Number between -5 and 5 (except 0) expected.","one weekday constraint":"You can not use more than one constrained weekday in a month range","range contrainted weekdays":"You can not use a range of constrained weekdays in a month range",expected:'"__symbol__" expected.',"range zero":"You can not use __type__ ranges with period equals zero.","period one year+":"Please don’t use __type__ ranges with period equals one."+' If you want to express that a facility is open starting from a year without limit use "<year>+".',"period one":"Please don’t use __type__ ranges with period equals one.","month 31":"The day for __month__ must be between 1 and 31.","month 30":"Month __month__ doesn't have 31 days. The last day of __month__ is day 30.","month feb":"Month __month__ either has 28 or 29 days (leap years).","point in time":"hyphen (-) or open end (+) in time range __calc__expected."+" For working with points in time, the mode for __libraryname__ has to be altered."+" Maybe wrong tag?",calculation:"calculation","time range continue":"Time range does not continue as expected","period continue":'Time period does not continue as expected. Example "/01:30".',"time range mode":'__libraryname__ is running in "time range mode". Found point in time.',"point in time mode":'__libraryname__ is running in "points in time mode". Found time range.',"outside current day":"Time range starts outside of the current day","two midnights":"Time spanning more than two midnights not supported","without minutes":"Time range without minutes specified. Not very explicit!"+' Please use this syntax instead "__syntax__".',"outside day":"Time range starts outside of the current day","zero calculation":"Adding zero in a variable time calculation does not change the variable time."+' Please omit the calculation (example: "sunrise-(sunset-00:00)").',"calculation syntax":"Calculation with variable time is not in the right syntax",missing:'Missing "__symbol__"',"(time)":"(time)","bad range":"Bad range: __from__-__to__","] or more numbers":'"]" or more numbers expected.',"additional rule no sense":'An additional rule does not make sense here. Just use a ";" as rule separator.'+" See https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification#explain:additional_rule_separator","unexpected token weekday range":"Unexpected token in weekday range: __token__","max differ":"There should be no reason to differ more than __maxdiffer__ days from a __name__. If so tell us …","adding 0":"Adding 0 does not change the date. Please omit this.","unexpected token holiday":"Unexpected token (holiday parser): __token__","no SH defintion":"School holiday __name__ has no definition for the year __year__"+" You can also add them: __repository_url__","no PH definition":"There are no holidays __name__ defined for country __cc__."+" You can also add them: __repository_url__","no PH definition state":"There are no holidays __name__ defined for country __cc__ and state __state__."+" You can also add them: __repository_url__","no country code":"Country code missing which is needed to select the correct holidays (see README how to provide it)","movable no formular":"Movable day __name__ can not not be calculated."+" Please add the formula how to calculate it.","movable not in year":"The movable day __name__ plus __days__"+" days is not in the year of the movable day anymore. Currently not supported.","year range one year":"A year range in which the start year is equal to the end year does not make sense."+' Please remove the end year. E.g. "__year__ May 23"',"year range reverse":"A year range in which the start year is greater than the end year does not make sense."+" Please turn it over.","year past":"The year is in the past.","unexpected token year range":"Unexpected token in year range: __token__","week range reverse":"You have specified a week range in reverse order or leaping over a year. This is (currently) not supported.","week negative":"You have specified a week date less then one. A valid week date range is 1-53.","week exceed":"You have specified a week date greater then 53. A valid week date range is 1-53.","week period less than 2":"You have specified a week period which is less than two."+' If you want to select the whole range from week __weekfrom__ to week __weekto__ then just omit the "/__period__".',"week period greater than 26":"You have specified a week period which is greater than 26."+" 26.5 is the half of the maximum 53 week dates per year so a week date period greater than 26 would only apply once per year."+' Please specify the week selector as "week __weekfrom__" if that is what you want to express.',"unexpected token week range":"Unexpected token in week range: __token__","unexpected token month range":"Unexpected token in month range: __token__","day range reverse":"Range in wrong order. From day is greater than to day.","open end":"Specified as open end. Closing time was guessed.","date parameter needed":"Date parameter needed."};if(typeof exports==="object"){var SunCalc=require("suncalc");try{var moment=require("moment")}catch(er){}try{var i18n=require("./locales/core")}catch(er){}module.exports=factory(SunCalc,moment,i18n,holidays,word_error_correction,lang)}else{root.opening_hours=factory(root.SunCalc,root.moment,root.i18n,holidays,word_error_correction,lang)}})(this,function(SunCalc,moment,i18n,holidays,word_error_correction,lang){var t=function(str,variables){if(typeof i18n==="object"&&typeof i18n.t==="function"){if(["de"].indexOf(i18n.lng())!==-1){return i18n.t("opening_hours:texts."+str,variables)}}var text=lang[str];if(typeof text==="undefined"){text=str}return text.replace(/__([^_]*)__/g,function(match,c){return typeof variables[c]!=="undefined"?variables[c]:match})};return function(value,nominatiomJSON,optional_conf_parm){var word_value_replacement={dawn:60*5+30,sunrise:60*6,sunset:60*18,dusk:60*18+30};var months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];var weekdays=["Su","Mo","Tu","We","Th","Fr","Sa"];var default_prettify_conf={zero_pad_hour:true,one_zero_if_hour_zero:false,leave_off_closed:true,keyword_for_off_closed:"off",rule_sep_string:" ",print_semicolon:true,leave_weekday_sep_one_day_betw:true,sep_one_day_between:",",zero_pad_month_and_week_numbers:false,locale:"en"};var osm_tag_defaults={opening_hours:{mode:0,warn_for_PH_missing:true},collection_times:{mode:2},"opening_hours:.+":{mode:0},".+:opening_hours":{mode:0},".+:opening_hours:.+":{mode:0},smoking_hours:{mode:0},service_times:{mode:2},happy_hours:{mode:0},lit:{mode:0,map:{yes:'sunset-sunrise open "specified as yes: At night (unknown time schedule or daylight detection)"',automatic:'unknown "specified as automatic: When someone enters the way the lights are turned on."',no:'off "specified as no: There are no lights installed."',interval:'unknown "specified as interval"',limited:'unknown "specified as limited"'}}};var minutes_in_day=60*24;var msec_in_day=1e3*60*minutes_in_day;var msec_in_week=msec_in_day*7;var library_name="opening_hours.js";var repository_url="https://github.com/ypid/"+library_name;var issues_url=repository_url+"/issues?state=open";var location_cc,location_state,lat,lon;if(typeof nominatiomJSON==="object"){if(typeof nominatiomJSON.address!=="undefined"){if(typeof nominatiomJSON.address.country_code!=="undefined"){location_cc=nominatiomJSON.address.country_code}if(typeof nominatiomJSON.address.state!=="undefined"){location_state=nominatiomJSON.address.state}else if(typeof nominatiomJSON.address.county!=="undefined"){location_state=nominatiomJSON.address.county}}if(typeof nominatiomJSON.lon!=="undefined"){lat=nominatiomJSON.lat;lon=nominatiomJSON.lon}}else if(typeof nominatiomJSON!=="undefined"){throw"The nominatiomJSON parameter is of unknown type."+" Given "+typeof nominatiomJSON+", expected object."}var warnings_severity=4;var oh_mode;var oh_map_value=false;var oh_key,oh_regex_key;if(typeof optional_conf_parm==="number"){oh_mode=optional_conf_parm}else if(typeof optional_conf_parm==="object"){if(checkOptionalConfParm("mode","number")){oh_mode=optional_conf_parm["mode"]}var locale=optional_conf_parm.locale||"en";if(typeof i18n==="object"&&i18n.lng()!==locale){i18n.setLng(locale)}if(checkOptionalConfParm("warnings_severity","number")){warnings_severity=optional_conf_parm["warnings_severity"];if([0,1,2,3,4,5,6,7].indexOf(warnings_severity)===-1){throw t("warnings severity",{severity:warnings_severity,allowed:"[ 0, 1, 2, 3, 4, 5, 6, 7 ]"})}}if(checkOptionalConfParm("tag_key","string")){oh_key=optional_conf_parm["tag_key"]}if(checkOptionalConfParm("map_value","boolean")){oh_map_value=true}}else if(typeof optional_conf_parm!=="undefined"){throw t("optional conf parm type",{given:typeof optional_conf_parm})}if(typeof oh_key==="string"){oh_regex_key=getRegexKeyForKeyFromOsmDefaults(oh_key);if(oh_map_value&&typeof osm_tag_defaults[oh_regex_key]["map"]==="object"&&typeof osm_tag_defaults[oh_regex_key]["map"][value]==="string"){value=osm_tag_defaults[oh_regex_key]["map"][value]}}else if(oh_map_value){throw t("conf param tag key missing")}if(typeof oh_mode==="undefined"){if(typeof oh_key==="string"){if(typeof osm_tag_defaults[oh_regex_key]["mode"]==="number"){oh_mode=osm_tag_defaults[oh_regex_key]["mode"]}else{oh_mode=0}}else{oh_mode=0}}else if(oh_mode!==0&&oh_mode!==1&&oh_mode!==2){throw t("conf param mode invalid",{given:oh_mode,allowed:"[ 0, 1, 2 ]"})}if(typeof value!=="string"){throw t("no string")}if(value.match(/^(?:\s*;?\s*)+$/)){throw t("nothing")}var parsing_warnings=[];var done_with_warnings=false;var done_with_selector_reordering=false;var done_with_selector_reordering_warnings=false;var tokens=tokenize(value);var prettified_value="";var week_stable=true;var rules=[];var new_tokens=[];for(var nrule=0;nrule<tokens.length;nrule++){if(tokens[nrule][0].length===0){parsing_warnings.push([nrule,-1,t("nothing useful")+(nrule===tokens.length-1&&nrule>0&&!tokens[nrule][1]?" "+t("programmers joke"):"")]);continue}var continue_at=0;var next_rule_is_additional=false;do{if(continue_at===tokens[nrule][0].length)break;var selectors={time:[],wraptime:[],weekday:[],holiday:[],week:[],month:[],monthday:[],year:[],date:[],fallback:tokens[nrule][1],additional:continue_at?true:false,meaning:true,unknown:false,comment:undefined,build_from_token_rule:undefined};selectors.build_from_token_rule=[nrule,continue_at,new_tokens.length];continue_at=parseGroup(tokens[nrule][0],continue_at,selectors,nrule);if(typeof continue_at==="object"){continue_at=continue_at[0]}else{continue_at=0}new_tokens.push([tokens[nrule][0].slice(selectors.build_from_token_rule[1],continue_at===0?tokens[nrule][0].length:continue_at),tokens[nrule][1],tokens[nrule][2]]);if(next_rule_is_additional&&new_tokens.length>1){new_tokens[new_tokens.length-1][0].unshift(new_tokens[new_tokens.length-2][0].pop())}next_rule_is_additional=continue_at===0?false:true;if(selectors.year.length>0)selectors.date.push(selectors.year);if(selectors.holiday.length>0)selectors.date.push(selectors.holiday);if(selectors.month.length>0)selectors.date.push(selectors.month);if(selectors.monthday.length>0)selectors.date.push(selectors.monthday);if(selectors.week.length>0)selectors.date.push(selectors.week);if(selectors.weekday.length>0)selectors.date.push(selectors.weekday);rules.push(selectors);if(selectors.wraptime.length>0){var wrapselectors={time:selectors.wraptime,date:[],meaning:selectors.meaning,unknown:selectors.unknown,comment:selectors.comment,wrapped:true,build_from_token_rule:selectors.build_from_token_rule};for(var dselg=0;dselg<selectors.date.length;dselg++){wrapselectors.date.push([]);for(var dsel=0;dsel<selectors.date[dselg].length;dsel++){wrapselectors.date[wrapselectors.date.length-1].push(generateDateShifter(selectors.date[dselg][dsel],-msec_in_day))}}rules.push(wrapselectors)}}while(continue_at)}function getRegexKeyForKeyFromOsmDefaults(key){var regex_key;for(var osm_key in osm_tag_defaults){if(key===osm_key){regex_key=osm_key;break}else if(key.match(osm_key)){regex_key=osm_key}}return regex_key}function checkOptionalConfParm(key,expected_type){if(typeof optional_conf_parm[key]===expected_type){return true}else if(typeof optional_conf_parm[key]!=="undefined"){throw t("conf param unkown type",{key:key,given:typeof optional_conf_parm[key],expected:expected_type})}return false}function formatWarnErrorMessage(nrule,at,message){if(typeof nrule==="number"){var pos=0;if(nrule===-1){pos=value.length-at}else{if(typeof tokens[nrule][0][at]==="undefined"){if(typeof tokens[nrule][0]&&at===-1){pos=value.length;if(typeof tokens[nrule+1]==="object"&&typeof tokens[nrule+1][2]==="number"){pos-=tokens[nrule+1][2]}else if(typeof tokens[nrule][2]==="number"){pos-=tokens[nrule][2]}}else{formatLibraryBugMessage("Bug in warning generation code which could not determine the exact position of the warning or error in value.");pos=value.length;if(typeof tokens[nrule][2]!=="undefined"){pos-=tokens[nrule][2];console.warn("Last token for rule: "+tokens[nrule]);console.log(value.substring(0,pos)+" <--- ("+message+")");console.log("\n")}{console.warn("tokens[nrule][2] is undefined. This is ok if nrule is the last rule.")}}}else{pos=value.length;if(typeof tokens[nrule][0][at+1]!=="undefined"){pos-=tokens[nrule][0][at+1][2]}else if(typeof tokens[nrule][2]!=="undefined"){pos-=tokens[nrule][2]}}}return value.substring(0,pos)+" <--- ("+message+")"}else if(typeof nrule==="string"){return nrule.substring(0,at)+" <--- ("+message+")"}}function formatLibraryBugMessage(message){if(typeof message==="undefined")message="";else message=" "+message;message=t("library bug",{value:value,url:issues_url,message:message});console.log(message);return message}function tokenize(value){var all_tokens=[];var curr_rule_tokens=[];var last_rule_fallback_terminated=false;while(value!==""){var tmp;if(tmp=value.match(/^week\b/i)){curr_rule_tokens.push([tmp[0].toLowerCase(),tmp[0].toLowerCase(),value.length]);value=value.substr(tmp[0].length)}else if(tmp=value.match(/^(?:off\b|closed\b|open\b|unknown\b)/i)){curr_rule_tokens.push([tmp[0].toLowerCase(),"state",value.length]);value=value.substr(tmp[0].length)}else if(tmp=value.match(/^24\/7/i)){curr_rule_tokens.push([tmp[0],tmp[0],value.length]);value=value.substr(tmp[0].length)}else if(tmp=value.match(/^(?:PH|SH)/i)){curr_rule_tokens.push([tmp[0].toUpperCase(),"holiday",value.length]);value=value.substr(2)}else if(tmp=value.match(/^(&|_|→|–|−|—|ー|=|·|öffnungszeit(?:en)?:?|opening_hours\s*=|\?|~|~|:|°°|always (?:open|closed)|24x7|24 hours 7 days a week|24 hours|7 ?days(?:(?: a |\/)week)?|7j?\/7|all days?|every day|(:?bis|till?|-|–)? ?(?:open ?end|late)|(?:(?:one )?day (?:before|after) )?(?:school|public) holidays?|days?\b|до|рм|ам|jours fériés|on work days?|sonntags?|(?:nur |an )?sonn-?(?:(?: und |\/)feiertag(?:s|en?)?)?|(?:an )?feiertag(?:s|en?)?|(?:nach|on|by) (?:appointments?|vereinbarung|absprache)|[_a-zäößàáéøčěíúýřПнВсо]+\b|à|á|mo|tu|we|th|fr|sa|su|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\.?/i)){var correct_val=returnCorrectWordOrToken(tmp[1].toLowerCase(),value.length);if(typeof correct_val==="object"){curr_rule_tokens.push([correct_val[0],correct_val[1],value.length]);value=value.substr(tmp[0].length)}else if(typeof correct_val==="string"){if(tmp[1].toLowerCase()==="pm"){var hours_token_at=curr_rule_tokens.length-1;var hours_token;if(hours_token_at>=0){if(hours_token_at-2>=0&&matchTokens(curr_rule_tokens,hours_token_at-2,"number","timesep","number")){hours_token_at-=2;hours_token=curr_rule_tokens[hours_token_at]}else if(matchTokens(curr_rule_tokens,hours_token_at,"number")){hours_token=curr_rule_tokens[hours_token_at]}if(typeof hours_token==="object"&&hours_token[0]<=12){hours_token[0]+=12;curr_rule_tokens[hours_token_at]=hours_token}}}var correct_tokens=tokenize(correct_val)[0];if(correct_tokens[1]===true){throw formatLibraryBugMessage()}for(var i=0;i<correct_tokens[0].length;i++){curr_rule_tokens.push([correct_tokens[0][i][0],correct_tokens[0][i][1],value.length])}value=value.substr(tmp[0].length)}else{curr_rule_tokens.push([value[0].toLowerCase(),value[0].toLowerCase(),value.length-1]);value=value.substr(1)}}else if(tmp=value.match(/^\d+/)){if(Number(tmp[0])>1900){curr_rule_tokens.push([Number(tmp[0]),"year",value.length]);if(Number(tmp[0])>=2100)parsing_warnings.push([-1,value.length-1,t("interpreted as year",{number:Number(tmp[0])})])}else{curr_rule_tokens.push([Number(tmp[0]),"number",value.length])}value=value.substr(tmp[0].length)}else if(tmp=value.match(/^"([^"]+)"/)){curr_rule_tokens.push([tmp[1],"comment",value.length]);value=value.substr(tmp[0].length)}else if(tmp=value.match(/^(["'„“‚‘’«「『])([^"'“”‘’»」』;|]*)(["'”“‘’»」』])/)){for(var pos=1;pos<=3;pos+=2){var correct_val=returnCorrectWordOrToken(tmp[pos],value.length-(pos===3?tmp[1].length+tmp[2].length:0));if(typeof correct_val!=="string"&&tmp[pos]!=='"'){throw formatLibraryBugMessage("A character for error tolerance was allowed in the regular expression"+" but is not covered by word_error_correction"+" which is needed to format a proper message for the user.")}}curr_rule_tokens.push([tmp[2],"comment",value.length]);value=value.substr(tmp[0].length)}else if(value.match(/^;/)){all_tokens.push([curr_rule_tokens,last_rule_fallback_terminated,value.length]);value=value.substr(1);curr_rule_tokens=[];last_rule_fallback_terminated=false}else if(value.match(/^\|\|/)){if(curr_rule_tokens.length===0)throw formatWarnErrorMessage(-1,value.length-2,t("rule before fallback empty"));all_tokens.push([curr_rule_tokens,last_rule_fallback_terminated,value.length]);curr_rule_tokens=[];value=value.substr(2);last_rule_fallback_terminated=true}else if(value.match(/^(?:␣|\s)/)){value=value.substr(1)}else if(tmp=value.match(/^\s+/)){value=value.substr(tmp[0].length)}else if(value.match(/^[:.]/)){if(value[0]==="."&&!done_with_warnings)parsing_warnings.push([-1,value.length-1,t("hour min seperator")]);curr_rule_tokens.push([":","timesep",value.length]);value=value.substr(1)}else{curr_rule_tokens.push([value[0].toLowerCase(),value[0].toLowerCase(),value.length]);value=value.substr(1)}}all_tokens.push([curr_rule_tokens,last_rule_fallback_terminated]);return all_tokens}function returnCorrectWordOrToken(word,value_length){for(var token_name in word_error_correction){for(var comment in word_error_correction[token_name]){for(var old_val in word_error_correction[token_name][comment]){if(word.match(new RegExp("^"+old_val+"$"))){var val=word_error_correction[token_name][comment][old_val];if(comment==="default"){return[val,token_name]}else if(token_name==="wrong_words"&&!done_with_warnings){parsing_warnings.push([-1,value_length-word.length,comment.replace(/<ko>/,word).replace(/<ok>/,val)]);return val}else{var correct_abbr;for(correct_abbr in word_error_correction[token_name]["default"]){if(word_error_correction[token_name]["default"][correct_abbr]===val)break}if(typeof correct_abbr==="undefined"){throw formatLibraryBugMessage("Including the stacktrace.")}if(token_name!=="timevar"){correct_abbr=correct_abbr.charAt(0).toUpperCase()+correct_abbr.slice(1)}if(!done_with_warnings)parsing_warnings.push([-1,value_length-word.length,comment.replace(/<ko>/,word).replace(/<ok>/,correct_abbr)]);return[val,token_name]}}}}}return undefined}function getWarnings(it){if(warnings_severity<4){return[]}if(!done_with_warnings&&typeof it==="object"){var wide_range_selector_order=["year","month","week","holiday"];var small_range_selector_order=["weekday","time","24/7","state","comment"];var used_selectors=[];var used_selectors_types_array=[];var has_token={};for(var nrule=0;nrule<new_tokens.length;nrule++){if(new_tokens[nrule][0].length===0)continue;var selector_start_end_type=[0,0,undefined],prettified_group_value=[];used_selectors[nrule]={};used_selectors_types_array[nrule]=[];do{selector_start_end_type=getSelectorRange(new_tokens[nrule][0],selector_start_end_type[1]);for(var token_pos=0;token_pos<=selector_start_end_type[1];token_pos++){if(typeof new_tokens[nrule][0][token_pos]==="object"&&new_tokens[nrule][0][token_pos][0]==="PH"){has_token["PH"]=true}}if(selector_start_end_type[0]===selector_start_end_type[1]&&new_tokens[nrule][0][selector_start_end_type[0]][0]==="24/7"){has_token["24/7"]=true}if(typeof used_selectors[nrule][selector_start_end_type[2]]!=="object"){used_selectors[nrule][selector_start_end_type[2]]=[selector_start_end_type[1]]}else{used_selectors[nrule][selector_start_end_type[2]].push(selector_start_end_type[1])}used_selectors_types_array[nrule].push(selector_start_end_type[2]);selector_start_end_type[1]++}while(selector_start_end_type[1]<new_tokens[nrule][0].length)}for(var nrule=0;nrule<used_selectors.length;nrule++){for(var selector_type in used_selectors[nrule]){if(used_selectors[nrule][selector_type].length>1){parsing_warnings.push([nrule,used_selectors[nrule][selector_type][used_selectors[nrule][selector_type].length-1],t("use multi",{count:used_selectors[nrule][selector_type].length,part2:selector_type.match(/^(?:comment|state)/)?t("selector multi 2a",{what:selector_type==="state"?t("selector state"):t("comments")}):t("selector multi 2b",{what:t(selector_type+(selector_type.match(/^(?:month|weekday)$/)?"s":" ranges"))})})]);done_with_selector_reordering=true}}if(typeof used_selectors[nrule].state==="object"&&Object.keys(used_selectors[nrule]).length===1){if(nrule!==0){parsing_warnings.push([nrule,new_tokens[nrule][0].length-1,t("default state")])}}else if(typeof used_selectors[nrule].time==="undefined"){if(typeof used_selectors[nrule].state==="object"&&new_tokens[nrule][0][used_selectors[nrule].state[0]][0]==="open"&&typeof used_selectors[nrule].comment==="undefined"||typeof used_selectors[nrule].comment==="undefined"&&typeof used_selectors[nrule].state==="undefined"&&typeof used_selectors[nrule]["24/7"]==="undefined"){parsing_warnings.push([nrule,new_tokens[nrule][0].length-1,t("vague")])}}if(typeof used_selectors[nrule].comment==="object"&&new_tokens[nrule][0][used_selectors[nrule].comment[0]][0].length===0){parsing_warnings.push([nrule,used_selectors[nrule].comment[0],t("empty comment")])}for(var i=0;i<used_selectors_types_array[nrule].length-1;i++){var selector_type=used_selectors_types_array[nrule][i];var next_selector_type=used_selectors_types_array[nrule][i+1];if(wide_range_selector_order.indexOf(selector_type)!==-1&&wide_range_selector_order.indexOf(next_selector_type)!==-1||small_range_selector_order.indexOf(selector_type)!==-1&&small_range_selector_order.indexOf(next_selector_type)!==-1){if(new_tokens[nrule][0][used_selectors[nrule][selector_type][0]][0]===":"){parsing_warnings.push([nrule,used_selectors[nrule][selector_type][0],t("separator_for_readability")])}}}if(typeof new_tokens[nrule][0][0]==="object"&&new_tokens[nrule][0][0][0]===","&&new_tokens[nrule][0][0][1]==="rule separator"&&typeof used_selectors[nrule].state==="object"&&(new_tokens[nrule][0][used_selectors[nrule].state[0]][0]==="closed"||new_tokens[nrule][0][used_selectors[nrule].state[0]][0]==="off")){}}var has_advanced=it.advance();if(has_advanced===true&&has_token["24/7"]&&!done_with_warnings){parsing_warnings.push([-1,0,t("strange 24/7")])}if(warnings_severity>=5&&!has_token["PH"]&&!has_token["24/7"]&&!done_with_warnings&&(typeof oh_key==="string"&&osm_tag_defaults[oh_regex_key]["warn_for_PH_missing"]||typeof oh_key!=="string")){var keys_with_warn_for_PH_missing=[];for(var key in osm_tag_defaults){if(osm_tag_defaults[key]["warn_for_PH_missing"]){keys_with_warn_for_PH_missing.push(key)}}parsing_warnings.push([-1,0,t("public holiday",{part2:typeof oh_key!=="string"?t("public holiday part2",{keys:keys_with_warn_for_PH_missing.join(", ")}):""})])}prettifyValue()}done_with_warnings=true;var warnings=[];for(var i=0;i<parsing_warnings.length;i++){warnings.push(formatWarnErrorMessage(parsing_warnings[i][0],parsing_warnings[i][1],parsing_warnings[i][2]))}return warnings}function tokenIsTheBeginOfSelector(tokens,at){if(typeof tokens[at][3]==="string"){return 3}else if(tokens[at][1]==="comment"||tokens[at][1]==="state"||tokens[at][1]==="24/7"||tokens[at][1]==="rule separator"){return 1}else{return false}}function getSelectorRange(tokens,at){var selector_start=at,selector_end,pos_in_token_array;for(;selector_start>=0;selector_start--){pos_in_token_array=tokenIsTheBeginOfSelector(tokens,selector_start);if(pos_in_token_array)break}selector_end=selector_start;if(pos_in_token_array===1){if(selector_end+1<tokens.length&&tokens[selector_end+1][0]===":")selector_end++;return[selector_start,selector_end,tokens[selector_start][pos_in_token_array]]}for(selector_end++;selector_end<tokens.length;selector_end++){if(tokenIsTheBeginOfSelector(tokens,selector_end))return[selector_start,selector_end-1,tokens[selector_start][pos_in_token_array]]}return[selector_start,selector_end-1,tokens[selector_start][pos_in_token_array]]}function prettifyValue(argument_hash){var user_conf={};var get_internals=false;var rule_index;prettified_value="";var prettified_value_array=[];if(typeof argument_hash!=="undefined"){if(typeof argument_hash.conf==="object"){user_conf=argument_hash.conf;console.log(user_conf)}if(typeof argument_hash.rule_index==="number"){rule_index=argument_hash.rule_index}if(argument_hash.get_internals===true){get_internals=true}}for(var key in default_prettify_conf){if(typeof user_conf[key]==="undefined")user_conf[key]=default_prettify_conf[key]}if(typeof moment==="object"&&typeof user_conf["locale"]==="string"&&user_conf["locale"]!=="en"){moment.locale("en");var weekdays_en=moment.weekdaysMin();var months_en=moment.months().map(function(month){return month.substr(0,3)});moment.locale(user_conf["locale"]);var weekdays_local=moment.weekdaysMin();var months_local=moment.months().map(function(month){return month.substr(0,3)})}for(var nrule=0;nrule<new_tokens.length;nrule++){if(new_tokens[nrule][0].length===0)continue;if(typeof rule_index==="number"){if(rule_index!==nrule)continue}else{if(nrule!==0)prettified_value+=new_tokens[nrule][1]?user_conf.rule_sep_string+"|| ":(new_tokens[nrule][0][0][1]==="rule separator"?",":user_conf.print_semicolon?";":"")+user_conf.rule_sep_string;
     22}var selector_start_end_type=[0,0,undefined];var prettified_group_value=[];var count=0;do{selector_start_end_type=getSelectorRange(new_tokens[nrule][0],selector_start_end_type[1]);if(count>50){throw formatLibraryBugMessage("infinite loop")}if(selector_start_end_type[2]!=="rule separator"){prettified_group_value.push([selector_start_end_type,prettifySelector(new_tokens[nrule][0],selector_start_end_type[0],selector_start_end_type[1],selector_start_end_type[2],user_conf)])}selector_start_end_type[1]++;count++}while(selector_start_end_type[1]<new_tokens[nrule][0].length);var not_sorted_prettified_group_value=prettified_group_value.slice();if(!done_with_selector_reordering){prettified_group_value.sort(function(a,b){var selector_order=["year","month","week","holiday","weekday","time","24/7","state","comment"];return selector_order.indexOf(a[0][2])-selector_order.indexOf(b[0][2])})}var old_prettified_value_length=prettified_value.length;if(typeof user_conf["locale"]==="string"&&user_conf["locale"]!=="en"){for(var i=0;i<prettified_group_value.length;i++){type=prettified_group_value[i][0][2];if(type==="weekday"){for(var key in weekdays_en){prettified_group_value[i][1]=prettified_group_value[i][1].replace(new RegExp(weekdays_en[key],"g"),weekdays_local[key])}}else if(type==="month"){for(var key in months_en){prettified_group_value[i][1]=prettified_group_value[i][1].replace(new RegExp(months_en[key],"g"),months_local[key])}}else{prettified_group_value[i][1]=i18n.t(["opening_hours:pretty."+prettified_group_value[i][1],prettified_group_value[i][1]])}}}prettified_value+=prettified_group_value.map(function(array){return array[1]}).join(" ");prettified_value_array.push(prettified_group_value);if(!done_with_selector_reordering_warnings){for(var i=0,l=not_sorted_prettified_group_value.length;i<l;i++){if(not_sorted_prettified_group_value[i]!==prettified_group_value[i]){var length=i+old_prettified_value_length;for(var x=0;x<=i;x++){length+=prettified_group_value[x][1].length}parsing_warnings.push([prettified_value,length,t("switched",{first:prettified_group_value[i][0][2],second:not_sorted_prettified_group_value[i][0][2]})])}}}}done_with_selector_reordering_warnings=true;if(get_internals){return[prettified_value_array,new_tokens]}else{return prettified_value}}function matchTokens(tokens,at){if(at+arguments.length-2>tokens.length)return false;for(var i=0;i<arguments.length-2;i++){if(tokens[at+i][1]!==arguments[i+2])return false}return true}function generateDateShifter(func,shift){return function(date){var res=func(new Date(date.getTime()+shift));if(typeof res[1]==="undefined")return res;return[res[0],new Date(res[1].getTime()-shift)]}}function parseGroup(tokens,at,selectors,nrule){var rule_modifier_specified=false;while(at<tokens.length){if(matchTokens(tokens,at,"weekday")){at=parseWeekdayRange(tokens,at,selectors)}else if(matchTokens(tokens,at,"24/7")){selectors.time.push(function(date){return[true]});at++}else if(matchTokens(tokens,at,"holiday")){if(matchTokens(tokens,at+1,","))at=parseHoliday(tokens,at,selectors,true);else at=parseHoliday(tokens,at,selectors,false);week_stable=false}else if(matchTokens(tokens,at,"month","number")||matchTokens(tokens,at,"month","weekday")||matchTokens(tokens,at,"year","month","number")||matchTokens(tokens,at,"year","event")||matchTokens(tokens,at,"event")){at=parseMonthdayRange(tokens,at,nrule);week_stable=false}else if(matchTokens(tokens,at,"year")){at=parseYearRange(tokens,at);week_stable=false}else if(matchTokens(tokens,at,"month")){at=parseMonthRange(tokens,at)}else if(matchTokens(tokens,at,"week")){tokens[at][3]="week";at=parseWeekRange(tokens,at)}else if(at!==0&&at!==tokens.length-1&&tokens[at][0]===":"){if(!done_with_warnings&&matchTokens(tokens,at-1,"holiday"))parsing_warnings.push([nrule,at,t("no colon after",{token:tokens[at-1][1]})]);at++}else if(matchTokens(tokens,at,"number","timesep")||matchTokens(tokens,at,"timevar")||matchTokens(tokens,at,"(","timevar")||matchTokens(tokens,at,"number","-")){at=parseTimeRange(tokens,at,selectors,false)}else if(matchTokens(tokens,at,"state")){if(tokens[at][0]==="open"){selectors.meaning=true}else if(tokens[at][0]==="closed"||tokens[at][0]==="off"){selectors.meaning=false}else{selectors.meaning=false;selectors.unknown=true}rule_modifier_specified=true;at++;if(typeof tokens[at]==="object"&&tokens[at][0]===",")at=[at+1]}else if(matchTokens(tokens,at,"comment")){selectors.comment=tokens[at][0];if(!rule_modifier_specified){selectors.meaning=false;selectors.unknown=true}rule_modifier_specified=true;at++;if(typeof tokens[at]==="object"&&tokens[at][0]===",")at=[at+1]}else if((at===0||at===tokens.length-1)&&matchTokens(tokens,at,"rule separator")){at++;console.log("value: "+nrule)}else{var warnings=getWarnings();throw formatWarnErrorMessage(nrule,at,t("unexpected token",{token:tokens[at][1]}))+(warnings?" "+warnings.join("; "):"")}if(typeof at==="object"){tokens[at[0]-1][1]="rule separator";break}}return at}function get_last_token_pos_in_token_group(tokens,at,last_at){for(at++;at<last_at;at++){if(typeof tokens[at]!=="undefined"){if(typeof tokens[at][3]==="string"||tokens[at][1]==="comment"||tokens[at][1]==="state"){return at-1}}}return last_at}function dateAtDayMinutes(date,minutes){return new Date(date.getFullYear(),date.getMonth(),date.getDate(),0,minutes)}function dateAtNextWeekday(date,weekday){var delta=weekday-date.getDay();return new Date(date.getFullYear(),date.getMonth(),date.getDate()+delta+(delta<0?7:0))}function indexOf(needle){if(typeof Array.prototype.indexOf==="function"){indexOf=Array.prototype.indexOf}else{indexOf=function(needle){var i=-1,index=-1;for(i=0;i<this.length;i++){if(this[i]===needle){index=i;break}}return index}}return indexOf.call(this,needle)}function parseNumRange(tokens,at,func){for(;at<tokens.length;at++){if(matchTokens(tokens,at,"number","-","number")){func(tokens[at][0],tokens[at+2][0],at);at+=3}else if(matchTokens(tokens,at,"-","number")){func(-tokens[at+1][0],-tokens[at+1][0],at);at+=2}else if(matchTokens(tokens,at,"number")){func(tokens[at][0],tokens[at][0],at);at++}else{throw formatWarnErrorMessage(nrule,at+matchTokens(tokens,at,"-"),"Unexpected token in number range: "+tokens[at][1])}if(!matchTokens(tokens,at,","))break}return at}function getConstrainedWeekday(tokens,at){var number=0;var endat=parseNumRange(tokens,at,function(from,to,at){if(from===0||from<-5||from>5)throw formatWarnErrorMessage(nrule,at,t("number -5 to 5"));if(from===to){if(number!==0)throw formatWarnErrorMessage(nrule,at,t("one weekday constraint"));number=from}else{throw formatWarnErrorMessage(nrule,at+2,t("range contrainted weekdays"))}});if(!matchTokens(tokens,endat,"]"))throw formatWarnErrorMessage(nrule,endat,t("expected",{symbol:"]"}));return[number,endat+1]}function checkPeriod(at,period,period_type,parm_string){if(done_with_warnings)return;if(period===0){throw formatWarnErrorMessage(nrule,at,t("range zero",{type:period_type}))}else if(period===1){if(typeof parm_string==="string"&&parm_string==="no_end_year")parsing_warnings.push([nrule,at,t("period one year+",{type:period_type})]);else parsing_warnings.push([nrule,at,t("period one",{type:period_type})])}}function getDateForConstrainedWeekday(year,month,weekday,constrained_weekday,add_days){var tmp_date=dateAtNextWeekday(new Date(year,month+(constrained_weekday[0]>0?0:1),1),weekday);tmp_date.setDate(tmp_date.getDate()+(constrained_weekday[0]+(constrained_weekday[0]>0?-1:0))*7);if(typeof add_days!=="undefined"&&add_days[1])tmp_date.setDate(tmp_date.getDate()+add_days[0]);return tmp_date}function checkIfDateIsValid(month,day,nrule,at){if(day<1||day>31){throw formatWarnErrorMessage(nrule,at,t("month 31",{month:months[month]}))}else if((month===3||month===5||month===8||month===10)&&day===31){throw formatWarnErrorMessage(nrule,at,t("month 30",{month:months[month]}))}else if(month===1&&day===30){throw formatWarnErrorMessage(nrule,at,t("month feb",{month:months[month]}))}}function parseTimeRange(tokens,at,selectors,extended_open_end){if(!extended_open_end)tokens[at][3]="time";for(;at<tokens.length;at++){var has_time_var_calc=[],has_normal_time=[];has_normal_time[0]=matchTokens(tokens,at,"number","timesep","number");has_time_var_calc[0]=matchTokens(tokens,at,"(","timevar");var minutes_from,minutes_to;if(has_normal_time[0]||matchTokens(tokens,at,"timevar")||has_time_var_calc[0]){var is_point_in_time=false;var has_open_end=false;var timevar_add=[0,0];var timevar_string=[];var point_in_time_period;if(has_normal_time[0]){minutes_from=getMinutesByHoursMinutes(tokens,nrule,at+has_time_var_calc[0])}else{timevar_string[0]=tokens[at+has_time_var_calc[0]][0];minutes_from=word_value_replacement[timevar_string[0]];if(has_time_var_calc[0]){timevar_add[0]=parseTimevarCalc(tokens,at);minutes_from+=timevar_add[0]}}var at_end_time=at+(has_normal_time[0]?3:has_time_var_calc[0]?7:1)+1;if(!matchTokens(tokens,at_end_time-1,"-")){if(matchTokens(tokens,at_end_time-1,"+")){has_open_end=true}else{if(oh_mode===0){throw formatWarnErrorMessage(nrule,at+(has_normal_time[0]?typeof tokens[at+3]==="object"?3:2:has_time_var_calc[0]?2:typeof tokens[at+1]!=="undefined"?1:0),t("point in time",{calc:has_time_var_calc[0]?t("calculation")+" ":"",libraryname:library_name}))}else{minutes_to=minutes_from+1;is_point_in_time=true}}}if(has_open_end){if(extended_open_end===1)minutes_from+=minutes_in_day;if(minutes_from>=22*60)minutes_to=minutes_from+8*60;else if(minutes_from>=17*60)minutes_to=minutes_from+10*60;else minutes_to=minutes_in_day}else if(!is_point_in_time){has_normal_time[1]=matchTokens(tokens,at_end_time,"number","timesep","number");has_time_var_calc[1]=matchTokens(tokens,at_end_time,"(","timevar");if(!has_normal_time[1]&&!matchTokens(tokens,at_end_time,"timevar")&&!has_time_var_calc[1]){throw formatWarnErrorMessage(nrule,at_end_time-(typeof tokens[at_end_time]!=="undefined"?0:1),t("time range continue"))}else{if(has_normal_time[1]){minutes_to=getMinutesByHoursMinutes(tokens,nrule,at_end_time)}else{timevar_string[1]=tokens[at_end_time+has_time_var_calc[1]][0];minutes_to=word_value_replacement[timevar_string[1]]}if(has_time_var_calc[1]){timevar_add[1]=parseTimevarCalc(tokens,at_end_time);minutes_to+=timevar_add[1]}}}at=at_end_time+(is_point_in_time?-1:has_normal_time[1]?3:has_time_var_calc[1]?7:!has_open_end);if(matchTokens(tokens,at,"/","number")){if(matchTokens(tokens,at+2,"timesep","number")){point_in_time_period=getMinutesByHoursMinutes(tokens,nrule,at+1);at+=4}else{point_in_time_period=tokens[at+1][0];at+=2;if(matchTokens(tokens,at,"timesep"))throw formatWarnErrorMessage(nrule,at,t("period continue"))}if(oh_mode===0)throw formatWarnErrorMessage(nrule,at-1,t("time range mode",{libraryname:library_name}));is_point_in_time=true}else if(matchTokens(tokens,at,"+")){parseTimeRange(tokens,at_end_time,selectors,minutes_to<minutes_from?1:true);at++}else if(oh_mode===1&&!is_point_in_time){throw formatWarnErrorMessage(nrule,at_end_time,t("point in time mode",{libraryname:library_name}))}if(typeof lat!=="undefined"){if(!has_normal_time[0]||!(has_normal_time[1]||has_open_end||is_point_in_time))week_stable=false}else{timevar_string=[]}if(!extended_open_end&&minutes_from>=minutes_in_day)throw formatWarnErrorMessage(nrule,at_end_time-2,t("outside current day"));if(minutes_to<minutes_from||has_normal_time[0]&&has_normal_time[1]&&minutes_from===minutes_to)minutes_to+=minutes_in_day;if(minutes_to>minutes_in_day*2)throw formatWarnErrorMessage(nrule,at_end_time+(has_normal_time[1]?4:has_time_var_calc[1]?7:1)-2,t("two midnights"));if(minutes_from===0&&minutes_to===minutes_in_day){selectors.time.push(function(date){return[true]})}else{if(minutes_to>minutes_in_day){selectors.time.push(function(minutes_from,minutes_to,timevar_string,timevar_add,has_open_end,is_point_in_time,point_in_time_period,extended_open_end){return function(date){var ourminutes=date.getHours()*60+date.getMinutes();if(timevar_string[0]){var date_from=SunCalc.getTimes(date,lat,lon)[timevar_string[0]];minutes_from=date_from.getHours()*60+date_from.getMinutes()+timevar_add[0]}if(timevar_string[1]){var date_to=SunCalc.getTimes(date,lat,lon)[timevar_string[1]];minutes_to=date_to.getHours()*60+date_to.getMinutes()+timevar_add[1];minutes_to+=minutes_in_day}else if(is_point_in_time&&typeof point_in_time_period!=="number"){minutes_to=minutes_from+1}if(typeof point_in_time_period==="number"){if(ourminutes<minutes_from){return[false,dateAtDayMinutes(date,minutes_from)]}else if(ourminutes<=minutes_to){for(var cur_min=minutes_from;ourminutes+point_in_time_period>=cur_min;cur_min+=point_in_time_period){if(cur_min===ourminutes){return[true,dateAtDayMinutes(date,ourminutes+1)]}else if(ourminutes<cur_min){return[false,dateAtDayMinutes(date,cur_min)]}}}return[false,dateAtDayMinutes(date,minutes_in_day)]}else{if(ourminutes<minutes_from)return[false,dateAtDayMinutes(date,minutes_from)];else return[true,dateAtDayMinutes(date,minutes_to),has_open_end,extended_open_end]}}}(minutes_from,minutes_to,timevar_string,timevar_add,has_open_end,is_point_in_time,point_in_time_period,extended_open_end));selectors.wraptime.push(function(minutes_from,minutes_to,timevar_string,timevar_add,has_open_end,is_point_in_time,point_in_time_period,extended_open_end){return function(date){var ourminutes=date.getHours()*60+date.getMinutes();if(timevar_string[0]){var date_from=SunCalc.getTimes(date,lat,lon)[timevar_string[0]];minutes_from=date_from.getHours()*60+date_from.getMinutes()+timevar_add[0]}if(timevar_string[1]){var date_to=SunCalc.getTimes(date,lat,lon)[timevar_string[1]];minutes_to=date_to.getHours()*60+date_to.getMinutes()+timevar_add[1]}if(typeof point_in_time_period==="number"){if(ourminutes<=minutes_to){for(var cur_min=0;ourminutes+point_in_time_period>=cur_min;cur_min+=point_in_time_period){if(cur_min===ourminutes){return[true,dateAtDayMinutes(date,ourminutes+1)]}else if(ourminutes<cur_min){return[false,dateAtDayMinutes(date,cur_min)]}}}}else{if(ourminutes<minutes_to)return[true,dateAtDayMinutes(date,minutes_to),has_open_end,extended_open_end]}return[false,undefined]}}(minutes_from,minutes_to-minutes_in_day,timevar_string,timevar_add,has_open_end,is_point_in_time,point_in_time_period,extended_open_end))}else{selectors.time.push(function(minutes_from,minutes_to,timevar_string,timevar_add,has_open_end,is_point_in_time,point_in_time_period,extended_open_end){return function(date){var ourminutes=date.getHours()*60+date.getMinutes();if(timevar_string[0]){var date_from=SunCalc.getTimes(date,lat,lon)[timevar_string[0]];minutes_from=date_from.getHours()*60+date_from.getMinutes()+timevar_add[0]}if(timevar_string[1]){var date_to=SunCalc.getTimes(date,lat,lon)[timevar_string[1]];minutes_to=date_to.getHours()*60+date_to.getMinutes()+timevar_add[1]}else if(is_point_in_time&&typeof point_in_time_period!=="number"){minutes_to=minutes_from+1}if(typeof point_in_time_period==="number"){if(ourminutes<minutes_from){return[false,dateAtDayMinutes(date,minutes_from)]}else if(ourminutes<=minutes_to){for(var cur_min=minutes_from;ourminutes+point_in_time_period>=cur_min;cur_min+=point_in_time_period){if(cur_min===ourminutes){return[true,dateAtDayMinutes(date,ourminutes+1)]}else if(ourminutes<cur_min){return[false,dateAtDayMinutes(date,cur_min)]}}}return[false,dateAtDayMinutes(date,minutes_in_day)]}else{if(ourminutes<minutes_from)return[false,dateAtDayMinutes(date,minutes_from)];else if(ourminutes<minutes_to)return[true,dateAtDayMinutes(date,minutes_to),has_open_end];else return[false,dateAtDayMinutes(date,minutes_from+minutes_in_day)]}}}(minutes_from,minutes_to,timevar_string,timevar_add,has_open_end,is_point_in_time,point_in_time_period,extended_open_end))}}}else if(matchTokens(tokens,at,"number","-","number")){minutes_from=tokens[at][0]*60;minutes_to=tokens[at+2][0]*60;if(!done_with_warnings)parsing_warnings.push([nrule,at+2,t("without minutes",{syntax:(tokens[at][0]<10?"0":"")+tokens[at][0]+":00-"+(tokens[at+2][0]<10?"0":"")+tokens[at+2][0]+":00"})]);if(minutes_from>=minutes_in_day)throw formatWarnErrorMessage(nrule,at,t("outside day"));if(minutes_to<minutes_from)minutes_to+=minutes_in_day;if(minutes_to>minutes_in_day*2)throw formatWarnErrorMessage(nrule,at+2,t("two midnights"));if(minutes_to>minutes_in_day){selectors.time.push(function(minutes_from,minutes_to){return function(date){var ourminutes=date.getHours()*60+date.getMinutes();if(ourminutes<minutes_from)return[false,dateAtDayMinutes(date,minutes_from)];else return[true,dateAtDayMinutes(date,minutes_to)]}}(minutes_from,minutes_to));selectors.wraptime.push(function(minutes_from,minutes_to){return function(date){var ourminutes=date.getHours()*60+date.getMinutes();if(ourminutes<minutes_to)return[true,dateAtDayMinutes(date,minutes_to)];else return[false,undefined]}}(minutes_from,minutes_to-minutes_in_day))}else{selectors.time.push(function(minutes_from,minutes_to){return function(date){var ourminutes=date.getHours()*60+date.getMinutes();if(ourminutes<minutes_from)return[false,dateAtDayMinutes(date,minutes_from)];else if(ourminutes<minutes_to)return[true,dateAtDayMinutes(date,minutes_to),has_open_end];else return[false,dateAtDayMinutes(date,minutes_from+minutes_in_day)]}}(minutes_from,minutes_to))}at+=3}else{if(matchTokens(tokens,at,"("))throw formatWarnErrorMessage(nrule,at,'Missing variable time (e.g. sunrise) after: "'+tokens[at][1]+'"');if(matchTokens(tokens,at,"number","timesep"))throw formatWarnErrorMessage(nrule,at+1,'Missing minutes in time range after: "'+tokens[at+1][1]+'"');if(matchTokens(tokens,at,"number"))throw formatWarnErrorMessage(nrule,at+(typeof tokens[at+1]!=="undefined"?1:0),'Missing time separator in time range after: "'+tokens[at][1]+'"');return[at]}if(!matchTokens(tokens,at,","))break}return at}function getMinutesByHoursMinutes(tokens,nrule,at){if(tokens[at+2][0]>59)throw formatWarnErrorMessage(nrule,at+2,"Minutes are greater than 59.");return tokens[at][0]*60+tokens[at+2][0]}function parseTimevarCalc(tokens,at){var error;if(matchTokens(tokens,at+2,"+")||matchTokens(tokens,at+2,"-")){if(matchTokens(tokens,at+3,"number","timesep","number")){if(matchTokens(tokens,at+6,")")){var add_or_subtract=tokens[at+2][0]==="+"?"1":"-1";var minutes=getMinutesByHoursMinutes(tokens,nrule,at+3)*add_or_subtract;if(minutes===0)parsing_warnings.push([nrule,at+5,t("zero calculation")]);return minutes}else{error=[at+6,". "+t("missing",{symbol:")"})+"."]}}else{error=[at+5," "+t("(time)")+"."]}}else{error=[at+2,". "+t("expected",{symbol:'+" or "-'})]}if(error)throw formatWarnErrorMessage(nrule,error[0],t("calculation syntax")+error[1])}function parseWeekdayRange(tokens,at,selectors,in_holiday_selector){if(!in_holiday_selector){in_holiday_selector=true;tokens[at][3]="weekday"}for(;at<tokens.length;at++){if(matchTokens(tokens,at,"weekday","[")){var numbers=[];var endat=parseNumRange(tokens,at+2,function(from,to,at){if(from===0||from<-5||from>5)throw formatWarnErrorMessage(nrule,at,t("number -5 to 5"));if(from===to){numbers.push(from)}else if(from<to){for(var i=from;i<=to;i++){if(i===0||i<-5||i>5)throw formatWarnErrorMessage(nrule,at+2,t("number -5 to 5"));numbers.push(i)}}else{throw formatWarnErrorMessage(nrule,at+2,t("bad range",{from:from,to:to}))}});if(!matchTokens(tokens,endat,"]"))throw formatWarnErrorMessage(nrule,endat,t("] or more numbers"));var add_days=getMoveDays(tokens,endat+1,6,"constrained weekdays");week_stable=false;for(var nnumber=0;nnumber<numbers.length;nnumber++){selectors.weekday.push(function(weekday,number,add_days){return function(date){var date_num=getValueForDate(date,false);var start_of_this_month=new Date(date.getFullYear(),date.getMonth(),1);var start_of_next_month=new Date(date.getFullYear(),date.getMonth()+1,1);var target_day_this_month;target_day_this_month=getDateForConstrainedWeekday(date.getFullYear(),date.getMonth(),weekday,[number]);var target_day_with_added_days_this_month=new Date(target_day_this_month.getFullYear(),target_day_this_month.getMonth(),target_day_this_month.getDate()+add_days);if(target_day_with_added_days_this_month.getTime()<start_of_this_month.getTime()){if(target_day_this_month.getTime()>=start_of_this_month.getTime()){target_day_with_added_days_this_month=dateAtNextWeekday(new Date(date.getFullYear(),date.getMonth()+(number>0?0:1)+1,1),weekday);target_day_this_month.setDate(target_day_with_added_days_this_month.getDate()+(number+(number>0?-1:0))*7+add_days)}else{return[false,start_of_next_month]}}else if(target_day_with_added_days_this_month.getTime()>=start_of_next_month.getTime()){if(target_day_this_month.getTime()>=start_of_next_month.getTime())return[false,start_of_next_month]}var target_day_with_added_moved_days_this_month;if(add_days>0){target_day_with_added_moved_days_this_month=dateAtNextWeekday(new Date(date.getFullYear(),date.getMonth()+(number>0?0:1)-1,1),weekday);target_day_with_added_moved_days_this_month.setDate(target_day_with_added_moved_days_this_month.getDate()+(number+(number>0?-1:0))*7+add_days);if(date_num===getValueForDate(target_day_with_added_moved_days_this_month,false))return[true,dateAtDayMinutes(date,minutes_in_day)]}else if(add_days<0){target_day_with_added_moved_days_this_month=dateAtNextWeekday(new Date(date.getFullYear(),date.getMonth()+(number>0?0:1)+1,1),weekday);target_day_with_added_moved_days_this_month.setDate(target_day_with_added_moved_days_this_month.getDate()+(number+(number>0?-1:0))*7+add_days);if(target_day_with_added_moved_days_this_month.getTime()>=start_of_next_month.getTime()){if(target_day_with_added_days_this_month.getTime()>=start_of_next_month.getTime())return[false,target_day_with_added_moved_days_this_month]}else{if(target_day_with_added_days_this_month.getTime()<start_of_next_month.getTime()&&getValueForDate(target_day_with_added_days_this_month,false)===date_num)return[true,dateAtDayMinutes(date,minutes_in_day)];target_day_with_added_days_this_month=target_day_with_added_moved_days_this_month}}if(date.getDate()===target_day_with_added_days_this_month.getDate()){return[true,dateAtDayMinutes(date,minutes_in_day)]}if(date.getDate()<target_day_with_added_days_this_month.getDate()){return[false,target_day_with_added_days_this_month]}return[false,start_of_next_month]}}(tokens[at][0],numbers[nnumber],add_days[0]))}at=endat+1+add_days[1]}else if(matchTokens(tokens,at,"weekday")){var is_range=matchTokens(tokens,at+1,"-","weekday");var weekday_from=tokens[at][0];var weekday_to=is_range?tokens[at+2][0]:weekday_from;var inside=true;if(weekday_to<weekday_from){var tmp=weekday_to;weekday_to=weekday_from-1;weekday_from=tmp+1;inside=false}if(weekday_to<weekday_from){selectors.weekday.push(function(date){return[true]})}else{selectors.weekday.push(function(weekday_from,weekday_to,inside){return function(date){var ourweekday=date.getDay();if(ourweekday<weekday_from||ourweekday>weekday_to){return[!inside,dateAtNextWeekday(date,weekday_from)]}else{return[inside,dateAtNextWeekday(date,weekday_to+1)]}}}(weekday_from,weekday_to,inside))}at+=is_range?3:1}else if(matchTokens(tokens,at,"holiday")){week_stable=false;return parseHoliday(tokens,at,selectors,true,in_holiday_selector)}else if(matchTokens(tokens,at-1,",")){throw formatWarnErrorMessage(nrule,at-1,t("additional rule no sense"))}else{throw formatWarnErrorMessage(nrule,at,t("unexpected token weekday range",{token:tokens[at][1]}))}if(!matchTokens(tokens,at,","))break}return at}function getMoveDays(tokens,at,max_differ,name){var add_days=[0,0];add_days[0]=matchTokens(tokens,at,"+")||(matchTokens(tokens,at,"-")?-1:0);if(add_days[0]!==0&&matchTokens(tokens,at+1,"number","calcday")){if(tokens[at+1][0]>max_differ)throw formatWarnErrorMessage(nrule,at+2,t("max differ",{maxdiffer:max_differ,name:name}));add_days[0]*=tokens[at+1][0];if(add_days[0]===0&&!done_with_warnings)parsing_warnings.push([nrule,at+2,t("adding 0")]);add_days[1]=3}else{add_days[0]=0}return add_days}function parseHoliday(tokens,at,selectors,push_to_weekday,in_holiday_selector){if(!in_holiday_selector){if(push_to_weekday)tokens[at][3]="weekday";else tokens[at][3]="holiday"}for(;at<tokens.length;at++){if(matchTokens(tokens,at,"holiday")){if(tokens[at][0]==="PH"){var applying_holidays=getMatchingHoliday(tokens[at][0]);var add_days=getMoveDays(tokens,at+1,1,"public holiday");var selector=function(applying_holidays,add_days){return function(date){var holidays=getApplyingHolidaysForYear(applying_holidays,date.getFullYear(),add_days);var date_num=getValueForDate(date,true);for(var i=0;i<holidays.length;i++){var next_holiday_date_num=getValueForDate(holidays[i][0],true);if(date_num<next_holiday_date_num){if(add_days[0]>0){var holidays_last_year=getApplyingHolidaysForYear(applying_holidays,date.getFullYear()-1,add_days);var last_holiday_last_year=holidays_last_year[holidays_last_year.length-1];var last_holiday_last_year_num=getValueForDate(last_holiday_last_year[0],true);if(date_num<last_holiday_last_year_num){return[false,last_holiday_last_year[0]]}else if(date_num===last_holiday_last_year_num){return[true,dateAtDayMinutes(last_holiday_last_year[0],minutes_in_day),"Day after "+last_holiday_last_year[1]]}}return[false,holidays[i][0]]}else if(date_num===next_holiday_date_num){return[true,new Date(date.getFullYear(),date.getMonth(),date.getDate()+1),(add_days[0]>0?"Day after ":add_days[0]<0?"Day before ":"")+holidays[i][1]]}}if(add_days[0]<0){var holidays_next_year=getApplyingHolidaysForYear(applying_holidays,date.getFullYear()+1,add_days);var first_holidays_next_year=holidays_next_year[0];var first_holidays_next_year_num=getValueForDate(first_holidays_next_year[0],true);if(date_num===first_holidays_next_year_num){return[true,dateAtDayMinutes(first_holidays_next_year[0],minutes_in_day),"Day before "+first_holidays_next_year[1]]}}return[false,new Date(holidays[0][0].getFullYear()+1,holidays[0][0].getMonth(),holidays[0][0].getDate())]}}(applying_holidays,add_days);if(push_to_weekday)selectors.weekday.push(selector);else selectors.holiday.push(selector);at+=1+add_days[1]}else if(tokens[at][0]==="SH"){var applying_holidays=getMatchingHoliday(tokens[at][0]);var holidays=[];var selector=function(applying_holidays){return function(date){var date_num=getValueForDate(date);for(var i=0;i<applying_holidays.length;i++){var holiday=getSHForYear(applying_holidays[i],date.getFullYear());for(var h=0;h<holiday.length;h+=4){var holiday_to_plus=new Date(date.getFullYear(),holiday[2+h]-1,holiday[3+h]+1);var holiday_from=(holiday[0+h]-1)*100+holiday[1+h];var holiday_to=(holiday[2+h]-1)*100+holiday[3+h];holiday_to_plus=getValueForDate(holiday_to_plus);var holiday_ends_next_year=holiday_to<holiday_from;if(date_num<holiday_from){var last_year_holiday=getSHForYear(applying_holidays[applying_holidays.length-1],date.getFullYear()-1,false);if(typeof last_year_holiday!=="undefined"){var last_year_holiday_from=(last_year_holiday[last_year_holiday.length-4]-1)*100+last_year_holiday[last_year_holiday.length-3];var last_year_holiday_to=(last_year_holiday[last_year_holiday.length-2]-1)*100+last_year_holiday[last_year_holiday.length-1];if(last_year_holiday_from>last_year_holiday_to&&date_num<=last_year_holiday_to)return[true,new Date(date.getFullYear(),last_year_holiday[last_year_holiday.length-2]-1,last_year_holiday[last_year_holiday.length-1]+1),applying_holidays[applying_holidays.length-1].name];else return[false,new Date(date.getFullYear(),holiday[0+h]-1,holiday[1+h])]}else{return[false,new Date(date.getFullYear(),holiday[0+h]-1,holiday[1+h])]}}else if(holiday_from<=date_num&&(date_num<holiday_to_plus||holiday_ends_next_year)){return[true,new Date(date.getFullYear()+holiday_ends_next_year,holiday[2+h]-1,holiday[3+h]+1),applying_holidays[i].name]}else if(holiday_to_plus===date_num){if(h+4<holiday.length){h+=4;return[false,new Date(date.getFullYear(),holiday[0+h]-1,holiday[1+h])]}else{if(i+1===applying_holidays.length){var holiday=getSHForYear(applying_holidays[0],date.getFullYear()+1);return[false,new Date(date.getFullYear()+!holiday_ends_next_year,holiday[0+h]-1,holiday[1+h])]}else{var holiday=getSHForYear(applying_holidays[i+1],date.getFullYear());return[false,new Date(date.getFullYear(),holiday[0]-1,holiday[1])]}}}}}return[false]}}(applying_holidays);if(push_to_weekday)selectors.weekday.push(selector);else selectors.holiday.push(selector);at+=1}}else if(matchTokens(tokens,at,"weekday")){return parseWeekdayRange(tokens,at,selectors,true)}else if(matchTokens(tokens,at-1,",")){throw formatWarnErrorMessage(nrule,at-1,t("additional rule no sense"))}else{throw formatWarnErrorMessage(nrule,at,t("unexpected token holiday",{token:tokens[at][1]}))}if(!matchTokens(tokens,at,","))break}return at}function getValueForDate(date,include_year){return(include_year?date.getFullYear()*1e4:0)+date.getMonth()*100+date.getDate()}function getSHForYear(SH_hash,year,fatal){if(typeof fatal==="undefined")fatal=true;var holiday=SH_hash[year];if(typeof holiday==="undefined"){holiday=SH_hash["default"];if(typeof holiday==="undefined"){if(fatal){throw formatLibraryBugMessage(t("no SH definition",{name:SH_hash.name,year:year,repository_url:repository_url}))}else{return undefined}}}return holiday}function getMatchingHoliday(type_of_holidays){if(typeof location_cc!=="undefined"){if(holidays.hasOwnProperty(location_cc)){if(typeof location_state!=="undefined"&&holidays[location_cc][location_state]&&holidays[location_cc][location_state][type_of_holidays]){return holidays[location_cc][location_state][type_of_holidays]}else if(holidays[location_cc][type_of_holidays]){var matching_holiday={};for(var holiday_name in holidays[location_cc][type_of_holidays]){if(typeof holidays[location_cc][type_of_holidays][holiday_name][2]==="object"){if(-1!==holidays[location_cc][type_of_holidays][holiday_name][2].indexOf(location_state))matching_holiday[holiday_name]=holidays[location_cc][type_of_holidays][holiday_name]}else{matching_holiday[holiday_name]=holidays[location_cc][type_of_holidays][holiday_name]}}if(Object.keys(matching_holiday).length===0)throw formatLibraryBugMessage(t("no PH definition",{name:type_of_holidays,cc:location_cc,repository_url:repository_url}));return matching_holiday}else{throw formatLibraryBugMessage(t("no PH definition state",{name:type_of_holidays,cc:location_cc,state:location_state,repository_url:repository_url}))}}else{throw formatLibraryBugMessage(t("no PH definition",{name:type_of_holidays,cc:location_cc,repository_url:repository_url}))}}else{throw t("no country code")}}function getMovableEventsForYear(Y){var C=Math.floor(Y/100);var N=Y-19*Math.floor(Y/19);var K=Math.floor((C-17)/25);var I=C-Math.floor(C/4)-Math.floor((C-K)/3)+19*N+15;I=I-30*Math.floor(I/30);I=I-Math.floor(I/28)*(1-Math.floor(I/28)*Math.floor(29/(I+1))*Math.floor((21-N)/11));var J=Y+Math.floor(Y/4)+I+2-C+Math.floor(C/4);J=J-7*Math.floor(J/7);var L=I-J;var M=3+Math.floor((L+40)/44);var D=L+28-31*Math.floor(M/4);var oA=Y%4;var oB=Y%7;var oC=Y%19;var oD=(19*oC+15)%30;var oE=(2*oA+4*oB-oD+34)%7;var oF=oD+oE;var oDate;if(oF<9){oDate=new Date(Y,4-1,oF+4)}else{if(oF+4<31){oDate=new Date(Y,4-1,oF+4)}else{oDate=new Date(Y,5-1,oF-26)}}var lastFebruaryDay=new Date(Y,2,0);var lastFebruarySunday=lastFebruaryDay.getDate()-lastFebruaryDay.getDay();var may_24=new Date(Y,4,24);var victoriaDay=24-(6+may_24.getDay())%7;var july_1=new Date(Y,6,1);var canadaDay=july_1.getDay()===0?2:1;function firstWeekdayOfMonth(month,weekday){var first=new Date(Y,month,1);return 1+(7+weekday-first.getDay())%7}function lastWeekdayOfMonth(month,weekday){var last=new Date(Y,month+1,0);var offset=(7+last.getDay()-weekday)%7;return last.getDate()-offset}return{easter:new Date(Y,M-1,D),"orthodox easter":oDate,victoriaDay:new Date(Y,4,victoriaDay),canadaDay:new Date(Y,6,canadaDay),firstJanuaryMonday:new Date(Y,0,firstWeekdayOfMonth(0,1)),firstFebruaryMonday:new Date(Y,1,firstWeekdayOfMonth(1,1)),lastFebruarySunday:new Date(Y,1,lastFebruarySunday),firstMarchMonday:new Date(Y,2,firstWeekdayOfMonth(2,1)),firstAprilMonday:new Date(Y,3,firstWeekdayOfMonth(3,1)),firstMayMonday:new Date(Y,4,firstWeekdayOfMonth(4,1)),firstJuneMonday:new Date(Y,5,firstWeekdayOfMonth(5,1)),firstJulyMonday:new Date(Y,6,firstWeekdayOfMonth(6,1)),
     23firstAugustMonday:new Date(Y,7,firstWeekdayOfMonth(7,1)),firstSeptemberMonday:new Date(Y,8,firstWeekdayOfMonth(8,1)),firstSeptemberSunday:new Date(Y,8,firstWeekdayOfMonth(8,0)),firstOctoberMonday:new Date(Y,9,firstWeekdayOfMonth(9,1)),firstNovemberMonday:new Date(Y,10,firstWeekdayOfMonth(10,1)),firstMarchTuesday:new Date(Y,2,firstWeekdayOfMonth(2,2)),firstAugustTuesday:new Date(Y,7,firstWeekdayOfMonth(7,2)),firstAugustFriday:new Date(Y,7,firstWeekdayOfMonth(7,5)),firstNovemberThursday:new Date(Y,10,firstWeekdayOfMonth(10,4)),lastMayMonday:new Date(Y,4,lastWeekdayOfMonth(4,1)),lastMarchMonday:new Date(Y,2,lastWeekdayOfMonth(2,1)),lastAprilMonday:new Date(Y,3,lastWeekdayOfMonth(3,1)),lastAprilFriday:new Date(Y,3,lastWeekdayOfMonth(3,5)),lastOctoberFriday:new Date(Y,9,lastWeekdayOfMonth(9,5))}}function getApplyingHolidaysForYear(applying_holidays,year,add_days){var movableDays=getMovableEventsForYear(year);var sorted_holidays=[];var next_holiday;for(var holiday_name in applying_holidays){if(typeof applying_holidays[holiday_name][0]==="string"){var selected_movableDay=movableDays[applying_holidays[holiday_name][0]];if(!selected_movableDay)throw t("movable no formular",{name:applying_holidays[holiday_name][0]});next_holiday=new Date(selected_movableDay.getFullYear(),selected_movableDay.getMonth(),selected_movableDay.getDate()+applying_holidays[holiday_name][1]);if(year!==next_holiday.getFullYear())throw t("movable not in year",{name:applying_holidays[holiday_name][0],days:applying_holidays[holiday_name][1]})}else{next_holiday=new Date(year,applying_holidays[holiday_name][0]-1,applying_holidays[holiday_name][1])}if(add_days[0])next_holiday.setDate(next_holiday.getDate()+add_days[0]);sorted_holidays.push([next_holiday,holiday_name])}sorted_holidays=sorted_holidays.sort(function(a,b){if(a[0].getTime()<b[0].getTime())return-1;if(a[0].getTime()>b[0].getTime())return 1;return 0});return sorted_holidays}function parseYearRange(tokens,at){tokens[at][3]="year";for(;at<tokens.length;at++){if(matchTokens(tokens,at,"year")){var is_range=false,has_period,period;if(matchTokens(tokens,at+1,"-","year","/","number")){is_range=true;has_period=true;period=parseInt(tokens[at+4][0]);checkPeriod(at+4,period,"year")}else{is_range=matchTokens(tokens,at+1,"-","year");has_period=matchTokens(tokens,at+1,"/","number");if(has_period){period=parseInt(tokens[at+2][0]);checkPeriod(at+2,period,"year","no_end_year")}else if(matchTokens(tokens,at+1,"+")){period=1;has_period=2}}var year_from=parseInt(tokens[at][0]);if(is_range&&tokens[at+2][0]<=year_from){if(tokens[at+2][0]===year_from){throw formatWarnErrorMessage(nrule,at,t("year range one year",{year:year_from}))}else{throw formatWarnErrorMessage(nrule,at,t("year range reverse"))}}if(!is_range&&year_from<(new Date).getFullYear()){parsing_warnings.push([nrule,at,t("year past")])}if(is_range&&tokens[at+2][0]<(new Date).getFullYear()){parsing_warnings.push([nrule,at+2,t("year past")])}selectors.year.push(function(tokens,at,year_from,is_range,has_period,period){return function(date){var ouryear=date.getFullYear();var year_to=is_range?parseInt(tokens[at+2][0]):year_from;if(ouryear<year_from){return[false,new Date(year_from,0,1)]}else if(has_period){if(year_from<=ouryear){if(is_range&&ouryear>year_to)return[false];if(period>0){if((ouryear-year_from)%period===0){return[true,new Date(ouryear+1,0,1)]}else{return[false,new Date(ouryear+period-1,0,1)]}}}}else if(is_range){if(ouryear<=year_to)return[true,new Date(year_to+1,0,1)]}else if(ouryear===year_from){return[true]}return[false]}}(tokens,at,year_from,is_range,has_period,period));at+=1+(is_range?2:0)+(has_period?has_period===2?1:2:0)}else if(matchTokens(tokens,at-1,",")){throw formatWarnErrorMessage(nrule,at-1,t("additional rule no sense"))}else{throw formatWarnErrorMessage(nrule,at,t("unexpected token year range",{token:tokens[at][1]}))}if(!matchTokens(tokens,at,","))break}return at}function parseWeekRange(tokens,at){for(;at<tokens.length;at++){if(matchTokens(tokens,at,"week")){at++}if(matchTokens(tokens,at,"number")){var is_range=matchTokens(tokens,at+1,"-","number"),period=0;var week_from=tokens[at][0];var week_to=is_range?tokens[at+2][0]:week_from;if(week_from>week_to){throw formatWarnErrorMessage(nrule,at+2,t("week range reverse"))}if(week_from<1){throw formatWarnErrorMessage(nrule,at,t("week negative"))}if(week_to>53){throw formatWarnErrorMessage(nrule,is_range?at+2:at,t("week exceed"))}if(is_range){period=matchTokens(tokens,at+3,"/","number");if(period){period=tokens[at+4][0];if(period<2){throw formatWarnErrorMessage(nrule,at+4,t("week period less than 2",{weekfrom:week_from,weekto:week_to,period:period}))}else if(period>26){throw formatWarnErrorMessage(nrule,at+4,t("week period greater than 26",{weekfrom:week_from}))}}}if(week_stable&&(!(week_from<=1&&week_to>=53)||period)){week_stable=false}if(!period&&week_from===1&&week_to===53){selectors.week.push(function(date){return[true]})}else{selectors.week.push(function(week_from,week_to,is_range,period){return function(date){var ourweek=getWeekNumber(date);if(ourweek<week_from){return[false,getNextDateOfISOWeek(week_from,date)]}if(ourweek>week_to){return[false,getNextDateOfISOWeek(week_from,date)]}if(period){var in_period=(ourweek-week_from)%period===0;if(in_period){return[true,getNextDateOfISOWeek(ourweek+1,date)]}else{return[false,getNextDateOfISOWeek(ourweek+period-1,date)]}}return[true,getNextDateOfISOWeek(week_to===53?1:week_to+1,date)]}}(week_from,week_to,is_range,period))}at+=1+(is_range?2:0)+(period?2:0)}else if(matchTokens(tokens,at-1,",")){throw formatWarnErrorMessage(nrule,at-1,t("additional rule no sense"))}else{throw formatWarnErrorMessage(nrule,at,t("unexpected token week range",{token:tokens[at][1]}))}if(!matchTokens(tokens,at,","))break}return at}function getWeekNumber(d){d=new Date(+d);d.setHours(0,0,0);d.setDate(d.getDate()+4-(d.getDay()||7));var yearStart=new Date(d.getFullYear(),0,1);return Math.ceil(((d-yearStart)/864e5+1)/7)}function getDateOfISOWeek(w,y){var simple=new Date(y,0,1+(w-1)*7);var dow=simple.getDay();var ISOweekStart=simple;if(dow<=4)ISOweekStart.setDate(simple.getDate()-simple.getDay()+1);else ISOweekStart.setDate(simple.getDate()+8-simple.getDay());return ISOweekStart}function getNextDateOfISOWeek(week,date){var next_date;for(var i=-1;i<=1;i++){next_date=getDateOfISOWeek(week,date.getFullYear()+i);if(next_date.getTime()>date.getTime()){return next_date}}throw formatLibraryBugMessage()}function parseMonthRange(tokens,at,push_to_monthday,in_selector){if(!in_selector)tokens[at][3]="month";for(;at<tokens.length;at++){if(matchTokens(tokens,at,"month","number")&&!matchTokens(tokens,at+2,"timesep","number")){return parseMonthdayRange(tokens,at,nrule,true)}else if(matchTokens(tokens,at,"month")){var is_range=matchTokens(tokens,at+1,"-","month");var month_from=tokens[at][0];var month_to=is_range?tokens[at+2][0]:month_from;if(is_range&&week_stable){if(month_from!==(month_to+1)%12)week_stable=false}else{week_stable=false}var inside=true;if(month_to<month_from){var tmp=month_to;month_to=month_from-1;month_from=tmp+1;inside=false}var selector=function(tokens,at,month_from,month_to,is_range,inside){return function(date){var ourmonth=date.getMonth();if(month_to<month_from)return[!inside];if(ourmonth<month_from||ourmonth>month_to){return[!inside,dateAtNextMonth(date,month_from)]}else{return[inside,dateAtNextMonth(date,month_to+1)]}}}(tokens,at,month_from,month_to,is_range,inside);if(push_to_monthday===true)selectors.monthday.push(selector);else selectors.month.push(selector);at+=is_range?3:1}else{throw formatWarnErrorMessage(nrule,at,t("unexpected token month range",{token:tokens[at][1]}))}if(!matchTokens(tokens,at,","))break}return at}function dateAtNextMonth(date,month){return new Date(date.getFullYear(),month<date.getMonth()?month+12:month)}function parseMonthdayRange(tokens,at,nrule,push_to_month){if(!push_to_month)tokens[at][3]="month";for(;at<tokens.length;at++){var has_year=[],has_month=[],has_event=[],has_calc=[],has_constrained_weekday=[];has_year[0]=matchTokens(tokens,at,"year");has_month[0]=matchTokens(tokens,at+has_year[0],"month","number");has_event[0]=matchTokens(tokens,at+has_year[0],"event");if(has_event[0])has_calc[0]=getMoveDays(tokens,at+has_year[0]+1,200,"event like easter");var at_range_sep;if(matchTokens(tokens,at+has_year[0],"month","weekday","[")){has_constrained_weekday[0]=getConstrainedWeekday(tokens,at+has_year[0]+3);has_calc[0]=getMoveDays(tokens,has_constrained_weekday[0][1],6,"constrained weekdays");at_range_sep=has_constrained_weekday[0][1]+(typeof has_calc[0]!=="undefined"&&has_calc[0][1]?3:0)}else{at_range_sep=at+has_year[0]+(has_event[0]?typeof has_calc[0]!=="undefined"&&has_calc[0][1]?4:1:2)}var at_sec_event_or_month;if((has_month[0]||has_event[0]||has_constrained_weekday[0])&&matchTokens(tokens,at_range_sep,"-")){has_year[1]=matchTokens(tokens,at_range_sep+1,"year");at_sec_event_or_month=at_range_sep+1+has_year[1];has_month[1]=matchTokens(tokens,at_sec_event_or_month,"month","number");if(!has_month[1]){has_event[1]=matchTokens(tokens,at_sec_event_or_month,"event");if(has_event[1]){has_calc[1]=getMoveDays(tokens,at_sec_event_or_month+1,366,"event like easter")}else if(matchTokens(tokens,at_sec_event_or_month,"month","weekday","[")){has_constrained_weekday[1]=getConstrainedWeekday(tokens,at_sec_event_or_month+3);has_calc[1]=getMoveDays(tokens,has_constrained_weekday[1][1],6,"constrained weekdays")}}}if(has_year[0]===has_year[1]&&(has_month[1]||has_event[1]||has_constrained_weekday[1])){if(has_month[0])checkIfDateIsValid(tokens[at+has_year[0]][0],tokens[at+has_year[0]+1][0],nrule,at+has_year[0]+1);if(has_month[1])checkIfDateIsValid(tokens[at_sec_event_or_month][0],tokens[at_sec_event_or_month+1][0],nrule,at_sec_event_or_month+1);var selector=function(tokens,at,nrule,has_year,has_event,has_calc,at_sec_event_or_month,has_constrained_weekday){return function(date){var start_of_next_year=new Date(date.getFullYear()+1,0,1);var movableDays,from_date;if(has_event[0]){movableDays=getMovableEventsForYear(has_year[0]?parseInt(tokens[at][0]):date.getFullYear());from_date=movableDays[tokens[at+has_year[0]][0]];if(typeof has_calc[0]!=="undefined"&&has_calc[0][1]){var from_year_before_calc=from_date.getFullYear();from_date.setDate(from_date.getDate()+has_calc[0][0]);if(from_year_before_calc!==from_date.getFullYear())throw formatWarnErrorMessage(nrule,at+has_year[0]+has_calc[0][1]*3,t("movable not in year",{name:tokens[at+has_year[0]][0],days:has_calc[0][0]}))}}else if(has_constrained_weekday[0]){from_date=getDateForConstrainedWeekday(has_year[0]?tokens[at][0]:date.getFullYear(),tokens[at+has_year[0]][0],tokens[at+has_year[0]+1][0],has_constrained_weekday[0],has_calc[0])}else{from_date=new Date(has_year[0]?tokens[at][0]:date.getFullYear(),tokens[at+has_year[0]][0],tokens[at+has_year[0]+1][0])}var to_date;if(has_event[1]){movableDays=getMovableEventsForYear(has_year[1]?parseInt(tokens[at_sec_event_or_month-1][0]):date.getFullYear());to_date=movableDays[tokens[at_sec_event_or_month][0]];if(typeof has_calc[1]!=="undefined"&&has_calc[1][1]){var to_year_before_calc=to_date.getFullYear();to_date.setDate(to_date.getDate()+has_calc[1][0]);if(to_year_before_calc!==to_date.getFullYear())throw formatWarnErrorMessage(nrule,at_sec_event_or_month+has_calc[1][1],t("movable not in year",{name:tokens[at_sec_event_or_month][0],days:has_calc[1][0]}))}}else if(has_constrained_weekday[1]){to_date=getDateForConstrainedWeekday(has_year[1]?tokens[at_sec_event_or_month-1][0]:date.getFullYear(),tokens[at_sec_event_or_month][0],tokens[at_sec_event_or_month+1][0],has_constrained_weekday[1],has_calc[1])}else{to_date=new Date(has_year[1]?tokens[at_sec_event_or_month-1][0]:date.getFullYear(),tokens[at_sec_event_or_month][0],tokens[at_sec_event_or_month+1][0]+1)}var inside=true;if(to_date<from_date){var tmp=to_date;to_date=from_date;from_date=tmp;inside=false}if(date.getTime()<from_date.getTime()){return[!inside,from_date]}else if(date.getTime()<to_date.getTime()){return[inside,to_date]}else{if(has_year[0]){return[!inside]}else{return[!inside,start_of_next_year]}}}}(tokens,at,nrule,has_year,has_event,has_calc,at_sec_event_or_month,has_constrained_weekday);if(push_to_month===true)selectors.month.push(selector);else selectors.monthday.push(selector);at=(has_constrained_weekday[1]?has_constrained_weekday[1][1]:at_sec_event_or_month+(has_event[1]?1:2))+(typeof has_calc[1]!=="undefined"?has_calc[1][1]:0)}else if(has_month[0]){has_year=has_year[0];var year=tokens[at][0];var month=tokens[at+has_year][0];var first_round=true;do{var range_from=tokens[at+1+has_year][0];var is_range=matchTokens(tokens,at+2+has_year,"-","number");var period=undefined;var range_to=tokens[at+has_year+(is_range?3:1)][0]+1;if(is_range&&matchTokens(tokens,at+has_year+4,"/","number")){period=tokens[at+has_year+5][0];checkPeriod(at+has_year+5,period,"day")}if(first_round){var at_timesep_if_monthRange=at+has_year+1+(is_range?2:0)+(period?2:0)+!(is_range||period);if(matchTokens(tokens,at_timesep_if_monthRange,"timesep","number")&&(matchTokens(tokens,at_timesep_if_monthRange+2,"+")||matchTokens(tokens,at_timesep_if_monthRange+2,"-")||oh_mode!==0)){return parseMonthRange(tokens,at,true,true)}}if(range_to<range_from)throw formatWarnErrorMessage(nrule,at+has_year+3,t("day range reverse"));checkIfDateIsValid(month,range_from,nrule,at+1+has_year);checkIfDateIsValid(month,range_to-1,nrule,at+has_year+(is_range?3:1));var selector=function(year,has_year,month,range_from,range_to,period){return function(date){var start_of_next_year=new Date(date.getFullYear()+1,0,1);var from_date=new Date(has_year?year:date.getFullYear(),month,range_from);if(month===1&&range_from!==from_date.getDate())return[false];var to_date=new Date(from_date.getFullYear(),month,range_to);if(month===1&&is_range&&range_to!==to_date.getDate())return[false];if(date.getTime()<from_date.getTime())return[false,from_date];else if(date.getTime()>=to_date.getTime())return[false,start_of_next_year];else if(!period)return[true,to_date];var nday=Math.floor((date.getTime()-from_date.getTime())/msec_in_day);var in_period=nday%period;if(in_period===0)return[true,new Date(date.getFullYear(),date.getMonth(),date.getDate()+1)];else return[false,new Date(date.getFullYear(),date.getMonth(),date.getDate()+period-in_period)]}}(year,has_year,month,range_from,range_to,period);if(push_to_month===true)selectors.month.push(selector);else selectors.monthday.push(selector);at+=2+has_year+(is_range?2:0)+(period?2:0);first_round=false}while(matchTokens(tokens,at,",","number"))}else if(has_event[0]){var selector=function(tokens,at,nrule,has_year,add_days){return function(date){var movableDays=getMovableEventsForYear(has_year?tokens[at][0]:date.getFullYear());var event_date=movableDays[tokens[at+has_year][0]];if(!event_date)throw t("movable no formular",{name:tokens[at+has_year][0]});if(add_days[0]){event_date.setDate(event_date.getDate()+add_days[0]);if(date.getFullYear()!==event_date.getFullYear())throw formatWarnErrorMessage(nrule,at+has_year+add_days[1],t("movable not in year",{name:tokens[at+has_year][0],days:add_days[0]}))}if(date.getTime()<event_date.getTime())return[false,event_date];else if(event_date.getMonth()*100+event_date.getDate()===date.getMonth()*100+date.getDate())return[true,new Date(date.getFullYear(),date.getMonth(),date.getDate()+1)];else return[false,new Date(date.getFullYear()+1,0,1)]}}(tokens,at,nrule,has_year[0],has_calc[0]);if(push_to_month===true)selectors.month.push(selector);else selectors.monthday.push(selector);at+=has_year[0]+has_event[0]+(typeof has_calc[0][1]!=="undefined"&&has_calc[0][1]?3:0)}else if(has_constrained_weekday[0]){at=parseMonthRange(tokens,at)}else if(matchTokens(tokens,at,"month")){return parseMonthRange(tokens,at,true,true)}else{return at}if(!matchTokens(tokens,at,","))break}return at}this.getStatePair=function(date){var resultstate=false;var changedate;var unknown=false;var comment;var match_rule;var date_matching_rules=[];for(var nrule=0;nrule<rules.length;nrule++){var matching_date_rule=true;for(var ndateselector=0;ndateselector<rules[nrule].date.length;ndateselector++){var dateselectors=rules[nrule].date[ndateselector];var has_matching_selector=false;for(var datesel=0;datesel<dateselectors.length;datesel++){var res=dateselectors[datesel](date);if(res[0]){has_matching_selector=true;if(typeof res[2]==="string"){comment=[res[2],nrule]}}if(typeof changedate==="undefined"||typeof res[1]!=="undefined"&&res[1].getTime()<changedate.getTime())changedate=res[1]}if(!has_matching_selector){matching_date_rule=false;break}}if(matching_date_rule){if((rules[nrule].date.length>0||nrule>0&&rules[nrule].meaning&&rules[nrule-1].date.length===0)&&(rules[nrule].meaning||rules[nrule].unknown)&&!rules[nrule].wrapped&&!rules[nrule].additional&&!rules[nrule].fallback){date_matching_rules=[]}date_matching_rules.push(nrule)}}rule:for(var nrule=0;nrule<date_matching_rules.length;nrule++){var rule=date_matching_rules[nrule];if(rules[rule].time.length===0){if(!rules[rule].fallback||rules[rule].fallback&&!(resultstate||unknown)){resultstate=rules[rule].meaning;unknown=rules[rule].unknown;match_rule=rule}}for(var timesel=0;timesel<rules[rule].time.length;timesel++){var res=rules[rule].time[timesel](date);if(res[0]){if(!rules[rule].fallback||rules[rule].fallback&&!(resultstate||unknown)){resultstate=rules[rule].meaning;unknown=rules[rule].unknown;match_rule=rule;if(typeof comment==="object"&&comment[0]===t("open end"))comment=undefined;if(res[2]===true&&(resultstate||unknown)){comment=[t("open end"),match_rule];resultstate=false;unknown=true;if(typeof rules[rule].time[timesel+1]==="function"){var next_res=rules[rule].time[timesel+1](date);if(!next_res[0]&&typeof next_res[1]==="object"&&rules[rule].time[timesel](new Date(date.getTime()-1))[0]){resultstate=false;unknown=false}}if(false&&typeof rules[rule-1]==="object"&&rules[rule].build_from_token_rule.toString()===rules[rule-1].build_from_token_rule.toString()&&typeof rules[rule]==="object"&&rules[rule].build_from_token_rule.toString()===rules[rule].build_from_token_rule.toString()){var last_wrapping_time_selector=rules[rule].time[rules[rule].time.length-1];var last_w_res=last_wrapping_time_selector(new Date(date.getTime()-1));if(last_w_res[0]&&typeof last_w_res[2]==="undefined"&&(typeof last_w_res[2]==="undefined"||last_w_res[2]===false)&&typeof last_w_res[1]==="object"&&date.getTime()===last_w_res[1].getTime()){resultstate=false;unknown=false}}}if(rules[rule].fallback){if(typeof changedate==="undefined"||typeof res[1]!=="undefined"&&res[1]<changedate)changedate=res[1]}}}if(typeof changedate==="undefined"||typeof res[1]!=="undefined"&&res[1]<changedate)changedate=res[1]}}if(typeof rules[match_rule]==="object"&&typeof rules[match_rule].comment==="string"){comment=rules[match_rule].comment}else if(typeof comment==="object"){if(comment[1]===match_rule){comment=comment[0]}else{comment=undefined}}return[resultstate,changedate,unknown,comment,match_rule]};function prettifySelector(tokens,selector_start,selector_end,selector_type,conf){var prettified_value="";var at=selector_start;while(at<=selector_end){if(matchTokens(tokens,at,"weekday")){if(!conf.leave_weekday_sep_one_day_betw&&at-selector_start>1&&(matchTokens(tokens,at-1,",")||matchTokens(tokens,at-1,"-"))&&matchTokens(tokens,at-2,"weekday")&&tokens[at][0]===(tokens[at-2][0]+1)%7){prettified_value=prettified_value.substring(0,prettified_value.length-1)+conf.sep_one_day_between}prettified_value+=weekdays[tokens[at][0]]}else if(at-selector_start>0&&selector_type==="time"&&matchTokens(tokens,at-1,"timesep")&&matchTokens(tokens,at,"number")){prettified_value+=(tokens[at][0]<10?"0":"")+tokens[at][0].toString()}else if(selector_type==="time"&&conf.zero_pad_hour&&at!==tokens.length&&matchTokens(tokens,at,"number")&&matchTokens(tokens,at+1,"timesep")){prettified_value+=(tokens[at][0]<10?tokens[at][0]===0&&conf.one_zero_if_hour_zero?"":"0":"")+tokens[at][0].toString()}else if(selector_type==="time"&&at+2<=selector_end&&matchTokens(tokens,at,"number")&&matchTokens(tokens,at+1,"-")&&matchTokens(tokens,at+2,"number")){prettified_value+=(tokens[at][0]<10?tokens[at][0]===0&&conf.one_zero_if_hour_zero?"":"0":"")+tokens[at][0].toString();prettified_value+=":00-"+(tokens[at+2][0]<10?"0":"")+tokens[at+2][0].toString()+":00";at+=2}else if(matchTokens(tokens,at,"comment")){prettified_value+='"'+tokens[at][0].toString()+'"'}else if(matchTokens(tokens,at,"closed")){prettified_value+=conf.leave_off_closed?tokens[at][0]:conf.keyword_for_off_closed}else if(at-selector_start>0&&matchTokens(tokens,at,"number")&&(matchTokens(tokens,at-1,"month")&&selector_type==="month"||matchTokens(tokens,at-1,"week")&&selector_type==="week")){prettified_value+=" "+(conf.zero_pad_month_and_week_numbers&&tokens[at][0]<10?"0":"")+tokens[at][0]}else if(at-selector_start>0&&matchTokens(tokens,at,"month")&&matchTokens(tokens,at-1,"year")){prettified_value+=" "+months[[tokens[at][0]]]}else if(at-selector_start>0&&matchTokens(tokens,at,"event")&&matchTokens(tokens,at-1,"year")){prettified_value+=" "+tokens[at][0]}else if(matchTokens(tokens,at,"month")){prettified_value+=months[[tokens[at][0]]];if(at+1<=selector_end&&matchTokens(tokens,at+1,"weekday"))prettified_value+=" "}else if(at+2<=selector_end&&(matchTokens(tokens,at,"-")||matchTokens(tokens,at,"+"))&&matchTokens(tokens,at+1,"number","calcday")){prettified_value+=" "+tokens[at][0]+tokens[at+1][0]+" day"+(Math.abs(tokens[at+1][0])===1?"":"s");at+=2}else if(at===selector_end&&selector_type==="weekday"&&tokens[at][0]===":"){}else{prettified_value+=tokens[at][0].toString()}at++}return prettified_value}this.getState=function(date){var it=this.getIterator(date);return it.getState()};this.getUnknown=function(date){var it=this.getIterator(date);return it.getUnknown()};this.getStateString=function(date,past){var it=this.getIterator(date);return it.getStateString(past)};this.getComment=function(date){var it=this.getIterator(date);return it.getComment()};this.getMatchingRule=function(date){var it=this.getIterator(date);return it.getMatchingRule()};this.getWarnings=function(){var it=this.getIterator();return getWarnings(it)};this.prettifyValue=function(argument_hash){this.getWarnings();return prettifyValue(argument_hash)};this.getNextChange=function(date,maxdate){var it=this.getIterator(date);if(!it.advance(maxdate))return undefined;return it.getDate()};this.isWeekStable=function(){return week_stable};this.getOpenIntervals=function(from,to){var res=[];var it=this.getIterator(from);if(it.getState()||it.getUnknown())res.push([from,undefined,it.getUnknown(),it.getComment()]);while(it.advance(to)){if(it.getState()||it.getUnknown()){if(res.length!==0&&typeof res[res.length-1][1]==="undefined"){res[res.length-1][1]=it.getDate()}res.push([it.getDate(),undefined,it.getUnknown(),it.getComment()])}else{if(res.length!==0&&typeof res[res.length-1][1]==="undefined"){res[res.length-1][1]=it.getDate()}}}if(res.length>0&&typeof res[res.length-1][1]==="undefined")res[res.length-1][1]=to;return res};this.getOpenDuration=function(from,to){var open=0;var unknown=0;var it=this.getIterator(from);var prevdate=it.getState()||it.getUnknown()?from:undefined;var prevstate=it.getState();var prevunknown=it.getUnknown();while(it.advance(to)){if(it.getState()||it.getUnknown()){if(typeof prevdate!=="undefined"){if(prevunknown)unknown+=it.getDate().getTime()-prevdate.getTime();else if(prevstate)open+=it.getDate().getTime()-prevdate.getTime()}prevdate=it.getDate();prevstate=it.getState();prevunknown=it.getUnknown()}else{if(typeof prevdate!=="undefined"){if(prevunknown)unknown+=it.getDate().getTime()-prevdate.getTime();else open+=it.getDate().getTime()-prevdate.getTime();prevdate=undefined}}}if(typeof prevdate!=="undefined"){if(prevunknown)unknown+=to.getTime()-prevdate.getTime();else open+=to.getTime()-prevdate.getTime()}return[open,unknown]};this.getIterator=function(date){return new function(oh){if(typeof date==="undefined")date=new Date;var prevstate=[undefined,date,undefined,undefined,undefined];var state=oh.getStatePair(date);this.getDate=function(){return prevstate[1]};this.setDate=function(date){if(typeof date!=="object")throw t("date parameter needed");prevstate=[undefined,date,undefined,undefined,undefined];state=oh.getStatePair(date)};this.getState=function(){return state[0]};this.getUnknown=function(){return state[2]};this.getStateString=function(past){return state[0]?"open":state[2]?"unknown":past?"closed":"close"};this.getComment=function(){return state[3]};this.getMatchingRule=function(){if(typeof state[4]==="undefined")return undefined;return rules[state[4]].build_from_token_rule[2]};this.advance=function(datelimit){if(typeof datelimit==="undefined")datelimit=new Date(prevstate[1].getTime()+msec_in_day*366*5);else if(datelimit.getTime()<=prevstate[1].getTime())return false;do{if(typeof state[1]==="undefined")return false;if(state[1].getTime()<=prevstate[1].getTime())throw"Fatal: infinite loop in nextChange";if(state[1].getTime()>=datelimit.getTime())return false;prevstate=state;state=oh.getStatePair(prevstate[1])}while(state[0]===prevstate[0]&&state[2]===prevstate[2]&&state[3]===prevstate[3]);return true}}(this)}}})},{"./locales/core":1,moment:"moment",suncalc:2}]},{},[]);
  • trunk/src/org/openstreetmap/josm/data/validation/tests/ConditionalKeys.java

    r8540 r8680  
    1717import org.openstreetmap.josm.data.validation.Test;
    1818import org.openstreetmap.josm.data.validation.TestError;
     19import org.openstreetmap.josm.tools.LanguageInfo;
    1920import org.openstreetmap.josm.tools.Predicates;
    2021import org.openstreetmap.josm.tools.Utils;
     
    132133                    if (condition.matches(".*[0-9]:[0-9]{2}.*")) {
    133134                        final List<OpeningHourTest.OpeningHoursTestError> errors = openingHourTest.checkOpeningHourSyntax(
    134                                 "", condition, OpeningHourTest.CheckMode.TIME_RANGE, true);
     135                                "", condition, OpeningHourTest.CheckMode.TIME_RANGE, true, LanguageInfo.getJOSMLocaleCode());
    135136                        if (!errors.isEmpty()) {
    136137                            return errors.get(0).getMessage();
  • trunk/src/org/openstreetmap/josm/data/validation/tests/OpeningHourTest.java

    r8540 r8680  
    2525import org.openstreetmap.josm.data.validation.TestError;
    2626import org.openstreetmap.josm.io.CachedFile;
     27import org.openstreetmap.josm.tools.LanguageInfo;
    2728
    2829/**
     
    5556                    new CachedFile("resource://data/validator/opening_hours.js").getInputStream(), StandardCharsets.UTF_8)) {
    5657                ENGINE.eval(reader);
     58                ENGINE.eval("var opening_hours = require('opening_hours');");
    5759                // fake country/state to not get errors on holidays
    5860                ENGINE.eval("var nominatimJSON = {address: {state: 'Bayern', country_code: 'de'}};");
    5961                ENGINE.eval(
    60                         "var oh = function (value, mode) {" +
     62                        "var oh = function (value, mode, locale) {" +
    6163                        " try {" +
    62                         "    var r= new opening_hours(value, nominatimJSON, mode);" +
     64                        "    var r = new opening_hours(value, nominatimJSON, {mode: mode, locale: locale});" +
    6365                        "    r.getErrors = function() {return [];};" +
    6466                        "    return r;" +
     
    8587    }
    8688
    87     protected Object parse(String value, CheckMode mode) throws ScriptException, NoSuchMethodException {
    88         return ((Invocable) ENGINE).invokeFunction("oh", value, mode.code);
     89    protected Object parse(String value, CheckMode mode, String locale) throws ScriptException, NoSuchMethodException {
     90        return ((Invocable) ENGINE).invokeFunction("oh", value, mode.code, locale);
    8991    }
    9092
     
    179181     */
    180182    public List<OpeningHoursTestError> checkOpeningHourSyntax(final String key, final String value, CheckMode mode) {
    181         return checkOpeningHourSyntax(key, value, mode, false);
     183        return checkOpeningHourSyntax(key, value, mode, false, LanguageInfo.getJOSMLocaleCode());
    182184    }
    183185
     
    190192     * @param mode whether to validate {@code value} as a time range, or points in time, or both.
    191193     * @param ignoreOtherSeverity whether to ignore errors with {@link Severity#OTHER}.
     194     * @param locale the locale code used for localizing messages
    192195     * @return a list of {@link TestError} or an empty list
    193196     */
    194197    public List<OpeningHoursTestError> checkOpeningHourSyntax(final String key, final String value, CheckMode mode,
    195             boolean ignoreOtherSeverity) {
     198            boolean ignoreOtherSeverity, String locale) {
    196199        if (ENGINE == null || value == null || value.trim().isEmpty()) {
    197200            return Collections.emptyList();
     
    199202        final List<OpeningHoursTestError> errors = new ArrayList<>();
    200203        try {
    201             final Object r = parse(value, mode);
     204            final Object r = parse(value, mode, locale);
    202205            String prettifiedValue = null;
    203206            try {
  • trunk/test/unit/org/openstreetmap/josm/data/validation/tests/OpeningHourTestTest.java

    r8509 r8680  
    66import static org.hamcrest.CoreMatchers.is;
    77import static org.hamcrest.CoreMatchers.not;
     8import static org.junit.Assert.assertFalse;
    89import static org.junit.Assert.assertThat;
     10import static org.junit.Assert.assertTrue;
    911
    1012import java.util.Arrays;
     
    5052        assertThat(OPENING_HOUR_TEST.checkOpeningHourSyntax(key, "24/7"), isEmpty());
    5153        assertThat(OPENING_HOUR_TEST.checkOpeningHourSyntax(key, "Mo-Fr 08:30-20:00"), isEmpty());
     54        assertThat(OPENING_HOUR_TEST.checkOpeningHourSyntax(key, "Mo-Fr sunrise-sunset"), isEmpty());
    5255        assertThat(OPENING_HOUR_TEST.checkOpeningHourSyntax(key, "09:00-21:00"), isEmpty());
    5356        assertThat(OPENING_HOUR_TEST.checkOpeningHourSyntax(key, "Su-Th sunset-24:00,04:00-sunrise; Fr-Sa sunset-sunrise"), isEmpty());
     
    5760        assertThat(OPENING_HOUR_TEST.checkOpeningHourSyntax(key, "Su-Th sunset-24:00, 04:00-sunrise; Fr-Sa sunset-sunrise")
    5861                .get(0).getPrettifiedValue(), is("Su-Th sunset-24:00,04:00-sunrise; Fr-Sa sunset-sunrise"));
     62    }
     63
     64    @Test
     65    public void testI18n() throws Exception {
     66        assertTrue(OPENING_HOUR_TEST.checkOpeningHourSyntax("opening_hours", ".", OpeningHourTest.CheckMode.POINTS_IN_TIME, false, "de")
     67                .get(0).toString().contains("Unerwartetes Zeichen"));
     68        assertFalse(OPENING_HOUR_TEST.checkOpeningHourSyntax("opening_hours", ".", OpeningHourTest.CheckMode.POINTS_IN_TIME, false, "en")
     69                .get(0).toString().contains("Unerwartetes Zeichen"));
    5970    }
    6071
Note: See TracChangeset for help on using the changeset viewer.