<\/h3>
<\/div><\/div>'});t.prototype=n.extend({},n.fn.tooltip.Constructor.prototype);t.prototype.constructor=t;t.prototype.getDefaults=function(){return t.DEFAULTS};t.prototype.setContent=function(){var n=this.tip(),i=this.getTitle(),t=this.getContent();n.find(".popover-title")[this.options.html?"html":"text"](i);n.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof t?"html":"append":"text"](t);n.removeClass("fade top bottom left right in");n.find(".popover-title").html()||n.find(".popover-title").hide()};t.prototype.hasContent=function(){return this.getTitle()||this.getContent()};t.prototype.getContent=function(){var t=this.$element,n=this.options;return t.attr("data-content")||("function"==typeof n.content?n.content.call(t[0]):n.content)};t.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};i=n.fn.popover;n.fn.popover=r;n.fn.popover.Constructor=t;n.fn.popover.noConflict=function(){return n.fn.popover=i,this}}(jQuery);+function(n){"use strict";function t(i,r){this.$body=n(document.body);this.$scrollElement=n(n(i).is(document.body)?window:i);this.options=n.extend({},t.DEFAULTS,r);this.selector=(this.options.target||"")+" .nav li > a";this.offsets=[];this.targets=[];this.activeTarget=null;this.scrollHeight=0;this.$scrollElement.on("scroll.bs.scrollspy",n.proxy(this.process,this));this.refresh();this.process()}function i(i){return this.each(function(){var u=n(this),r=u.data("bs.scrollspy"),f="object"==typeof i&&i;r||u.data("bs.scrollspy",r=new t(this,f));"string"==typeof i&&r[i]()})}t.VERSION="3.3.7";t.DEFAULTS={offset:10};t.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)};t.prototype.refresh=function(){var t=this,i="offset",r=0;this.offsets=[];this.targets=[];this.scrollHeight=this.getScrollHeight();n.isWindow(this.$scrollElement[0])||(i="position",r=this.$scrollElement.scrollTop());this.$body.find(this.selector).map(function(){var f=n(this),u=f.data("target")||f.attr("href"),t=/^#./.test(u)&&n(u);return t&&t.length&&t.is(":visible")&&[[t[i]().top+r,u]]||null}).sort(function(n,t){return n[0]-t[0]}).each(function(){t.offsets.push(this[0]);t.targets.push(this[1])})};t.prototype.process=function(){var n,i=this.$scrollElement.scrollTop()+this.options.offset,f=this.getScrollHeight(),e=this.options.offset+f-this.$scrollElement.height(),t=this.offsets,r=this.targets,u=this.activeTarget;if(this.scrollHeight!=f&&this.refresh(),i>=e)return u!=(n=r[r.length-1])&&this.activate(n);if(u&&i=t[n]&&(void 0===t[n+1]||i .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1);i.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0);o?(i[0].offsetWidth,i.addClass("in")):i.removeClass("fade");i.parent(".dropdown-menu").length&&i.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0);u&&u()}var f=r.find("> .active"),o=u&&n.support.transition&&(f.length&&f.hasClass("fade")||!!r.find("> .fade").length);f.length&&o?f.one("bsTransitionEnd",e).emulateTransitionEnd(t.TRANSITION_DURATION):e();f.removeClass("in")};u=n.fn.tab;n.fn.tab=r;n.fn.tab.Constructor=t;n.fn.tab.noConflict=function(){return n.fn.tab=u,this};i=function(t){t.preventDefault();r.call(n(this),"show")};n(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',i).on("click.bs.tab.data-api",'[data-toggle="pill"]',i)}(jQuery);+function(n){"use strict";function i(i){return this.each(function(){var u=n(this),r=u.data("bs.affix"),f="object"==typeof i&&i;r||u.data("bs.affix",r=new t(this,f));"string"==typeof i&&r[i]()})}var t=function(i,r){this.options=n.extend({},t.DEFAULTS,r);this.$target=n(this.options.target).on("scroll.bs.affix.data-api",n.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",n.proxy(this.checkPositionWithEventLoop,this));this.$element=n(i);this.affixed=null;this.unpin=null;this.pinnedOffset=null;this.checkPosition()},r;t.VERSION="3.3.7";t.RESET="affix affix-top affix-bottom";t.DEFAULTS={offset:0,target:window};t.prototype.getState=function(n,t,i,r){var u=this.$target.scrollTop(),f=this.$element.offset(),e=this.$target.height();if(null!=i&&"top"==this.affixed)return u=n-r&&"bottom"};t.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(t.RESET).addClass("affix");var n=this.$target.scrollTop(),i=this.$element.offset();return this.pinnedOffset=i.top-n};t.prototype.checkPositionWithEventLoop=function(){setTimeout(n.proxy(this.checkPosition,this),1)};t.prototype.checkPosition=function(){var i,e,o;if(this.$element.is(":visible")){var s=this.$element.height(),r=this.options.offset,f=r.top,u=r.bottom,h=Math.max(n(document).height(),n(document.body).height());if("object"!=typeof r&&(u=f=r),"function"==typeof f&&(f=r.top(this.$element)),"function"==typeof u&&(u=r.bottom(this.$element)),i=this.getState(h,s,f,u),this.affixed!=i){if(null!=this.unpin&&this.$element.css("top",""),e="affix"+(i?"-"+i:""),o=n.Event(e+".bs.affix"),this.$element.trigger(o),o.isDefaultPrevented())return;this.affixed=i;this.unpin="bottom"==i?this.getPinnedOffset():null;this.$element.removeClass(t.RESET).addClass(e).trigger(e.replace("affix","affixed")+".bs.affix")}"bottom"==i&&this.$element.offset({top:h-s-u})}};r=n.fn.affix;n.fn.affix=i;n.fn.affix.Constructor=t;n.fn.affix.noConflict=function(){return n.fn.affix=r,this};n(window).on("load",function(){n('[data-spy="affix"]').each(function(){var r=n(this),t=r.data();t.offset=t.offset||{};null!=t.offsetBottom&&(t.offset.bottom=t.offsetBottom);null!=t.offsetTop&&(t.offset.top=t.offsetTop);i.call(r,t)})})}(jQuery);!function(n){"use strict";n.matchMedia=n.matchMedia||function(n){var u,i=n.documentElement,f=i.firstElementChild||i.firstChild,r=n.createElement("body"),t=n.createElement("div");return t.id="mq-test-1",t.style.cssText="position:absolute;top:-100em",r.style.background="none",r.appendChild(t),function(n){return t.innerHTML=''].join('');
+ div.id = mod;
+ // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
+ // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
+ (body ? div : fakeBody).innerHTML += style;
+ fakeBody.appendChild(div);
+ if ( !body ) {
+ //avoid crashing IE8, if background image is used
+ fakeBody.style.background = '';
+ //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
+ fakeBody.style.overflow = 'hidden';
+ docOverflow = docElement.style.overflow;
+ docElement.style.overflow = 'hidden';
+ docElement.appendChild(fakeBody);
+ }
+
+ ret = callback(div, rule);
+ // If this is done after page load we don't want to remove the body so check if body exists
+ if ( !body ) {
+ fakeBody.parentNode.removeChild(fakeBody);
+ docElement.style.overflow = docOverflow;
+ } else {
+ div.parentNode.removeChild(div);
+ }
+
+ return !!ret;
+
+ },
+ /*>>teststyles*/
+
+ /*>>mq*/
+ // adapted from matchMedia polyfill
+ // by Scott Jehl and Paul Irish
+ // gist.github.com/786768
+ testMediaQuery = function( mq ) {
+
+ var matchMedia = window.matchMedia || window.msMatchMedia;
+ if ( matchMedia ) {
+ return matchMedia(mq) && matchMedia(mq).matches || false;
+ }
+
+ var bool;
+
+ injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) {
+ bool = (window.getComputedStyle ?
+ getComputedStyle(node, null) :
+ node.currentStyle)['position'] == 'absolute';
+ });
+
+ return bool;
+
+ },
+ /*>>mq*/
+
+
+ /*>>hasevent*/
+ //
+ // isEventSupported determines if a given element supports the given event
+ // kangax.github.com/iseventsupported/
+ //
+ // The following results are known incorrects:
+ // Modernizr.hasEvent("webkitTransitionEnd", elem) // false negative
+ // Modernizr.hasEvent("textInput") // in Webkit. github.com/Modernizr/Modernizr/issues/333
+ // ...
+ isEventSupported = (function() {
+
+ var TAGNAMES = {
+ 'select': 'input', 'change': 'input',
+ 'submit': 'form', 'reset': 'form',
+ 'error': 'img', 'load': 'img', 'abort': 'img'
+ };
+
+ function isEventSupported( eventName, element ) {
+
+ element = element || document.createElement(TAGNAMES[eventName] || 'div');
+ eventName = 'on' + eventName;
+
+ // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
+ var isSupported = eventName in element;
+
+ if ( !isSupported ) {
+ // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
+ if ( !element.setAttribute ) {
+ element = document.createElement('div');
+ }
+ if ( element.setAttribute && element.removeAttribute ) {
+ element.setAttribute(eventName, '');
+ isSupported = is(element[eventName], 'function');
+
+ // If property was created, "remove it" (by setting value to `undefined`)
+ if ( !is(element[eventName], 'undefined') ) {
+ element[eventName] = undefined;
+ }
+ element.removeAttribute(eventName);
+ }
+ }
+
+ element = null;
+ return isSupported;
+ }
+ return isEventSupported;
+ })(),
+ /*>>hasevent*/
+
+ // TODO :: Add flag for hasownprop ? didn't last time
+
+ // hasOwnProperty shim by kangax needed for Safari 2.0 support
+ _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
+
+ if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
+ hasOwnProp = function (object, property) {
+ return _hasOwnProperty.call(object, property);
+ };
+ }
+ else {
+ hasOwnProp = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
+ return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
+ };
+ }
+
+ // Adapted from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js
+ // es5.github.com/#x15.3.4.5
+
+ if (!Function.prototype.bind) {
+ Function.prototype.bind = function bind(that) {
+
+ var target = this;
+
+ if (typeof target != "function") {
+ throw new TypeError();
+ }
+
+ var args = slice.call(arguments, 1),
+ bound = function () {
+
+ if (this instanceof bound) {
+
+ var F = function(){};
+ F.prototype = target.prototype;
+ var self = new F();
+
+ var result = target.apply(
+ self,
+ args.concat(slice.call(arguments))
+ );
+ if (Object(result) === result) {
+ return result;
+ }
+ return self;
+
+ } else {
+
+ return target.apply(
+ that,
+ args.concat(slice.call(arguments))
+ );
+
+ }
+
+ };
+
+ return bound;
+ };
+ }
+
+ /**
+ * setCss applies given styles to the Modernizr DOM node.
+ */
+ function setCss( str ) {
+ mStyle.cssText = str;
+ }
+
+ /**
+ * setCssAll extrapolates all vendor-specific css strings.
+ */
+ function setCssAll( str1, str2 ) {
+ return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
+ }
+
+ /**
+ * is returns a boolean for if typeof obj is exactly type.
+ */
+ function is( obj, type ) {
+ return typeof obj === type;
+ }
+
+ /**
+ * contains returns a boolean for if substr is found within str.
+ */
+ function contains( str, substr ) {
+ return !!~('' + str).indexOf(substr);
+ }
+
+ /*>>testprop*/
+
+ // testProps is a generic CSS / DOM property test.
+
+ // In testing support for a given CSS property, it's legit to test:
+ // `elem.style[styleName] !== undefined`
+ // If the property is supported it will return an empty string,
+ // if unsupported it will return undefined.
+
+ // We'll take advantage of this quick test and skip setting a style
+ // on our modernizr element, but instead just testing undefined vs
+ // empty string.
+
+ // Because the testing of the CSS property names (with "-", as
+ // opposed to the camelCase DOM properties) is non-portable and
+ // non-standard but works in WebKit and IE (but not Gecko or Opera),
+ // we explicitly reject properties with dashes so that authors
+ // developing in WebKit or IE first don't end up with
+ // browser-specific content by accident.
+
+ function testProps( props, prefixed ) {
+ for ( var i in props ) {
+ var prop = props[i];
+ if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
+ return prefixed == 'pfx' ? prop : true;
+ }
+ }
+ return false;
+ }
+ /*>>testprop*/
+
+ // TODO :: add testDOMProps
+ /**
+ * testDOMProps is a generic DOM property test; if a browser supports
+ * a certain property, it won't return undefined for it.
+ */
+ function testDOMProps( props, obj, elem ) {
+ for ( var i in props ) {
+ var item = obj[props[i]];
+ if ( item !== undefined) {
+
+ // return the property name as a string
+ if (elem === false) return props[i];
+
+ // let's bind a function
+ if (is(item, 'function')){
+ // default to autobind unless override
+ return item.bind(elem || obj);
+ }
+
+ // return the unbound function or obj or value
+ return item;
+ }
+ }
+ return false;
+ }
+
+ /*>>testallprops*/
+ /**
+ * testPropsAll tests a list of DOM properties we want to check against.
+ * We specify literally ALL possible (known and/or likely) properties on
+ * the element including the non-vendor prefixed one, for forward-
+ * compatibility.
+ */
+ function testPropsAll( prop, prefixed, elem ) {
+
+ var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
+ props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
+
+ // did they call .prefixed('boxSizing') or are we just testing a prop?
+ if(is(prefixed, "string") || is(prefixed, "undefined")) {
+ return testProps(props, prefixed);
+
+ // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
+ } else {
+ props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
+ return testDOMProps(props, prefixed, elem);
+ }
+ }
+ /*>>testallprops*/
+
+
+ /**
+ * Tests
+ * -----
+ */
+
+ // The *new* flexbox
+ // dev.w3.org/csswg/css3-flexbox
+
+ tests['flexbox'] = function() {
+ return testPropsAll('flexWrap');
+ };
+
+ // The *old* flexbox
+ // www.w3.org/TR/2009/WD-css3-flexbox-20090723/
+
+ tests['flexboxlegacy'] = function() {
+ return testPropsAll('boxDirection');
+ };
+
+ // On the S60 and BB Storm, getContext exists, but always returns undefined
+ // so we actually have to call getContext() to verify
+ // github.com/Modernizr/Modernizr/issues/issue/97/
+
+ tests['canvas'] = function() {
+ var elem = document.createElement('canvas');
+ return !!(elem.getContext && elem.getContext('2d'));
+ };
+
+ tests['canvastext'] = function() {
+ return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
+ };
+
+ // webk.it/70117 is tracking a legit WebGL feature detect proposal
+
+ // We do a soft detect which may false positive in order to avoid
+ // an expensive context creation: bugzil.la/732441
+
+ tests['webgl'] = function() {
+ return !!window.WebGLRenderingContext;
+ };
+
+ /*
+ * The Modernizr.touch test only indicates if the browser supports
+ * touch events, which does not necessarily reflect a touchscreen
+ * device, as evidenced by tablets running Windows 7 or, alas,
+ * the Palm Pre / WebOS (touch) phones.
+ *
+ * Additionally, Chrome (desktop) used to lie about its support on this,
+ * but that has since been rectified: crbug.com/36415
+ *
+ * We also test for Firefox 4 Multitouch Support.
+ *
+ * For more info, see: modernizr.github.com/Modernizr/touch.html
+ */
+
+ tests['touch'] = function() {
+ var bool;
+
+ if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
+ bool = true;
+ } else {
+ injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
+ bool = node.offsetTop === 9;
+ });
+ }
+
+ return bool;
+ };
+
+
+ // geolocation is often considered a trivial feature detect...
+ // Turns out, it's quite tricky to get right:
+ //
+ // Using !!navigator.geolocation does two things we don't want. It:
+ // 1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
+ // 2. Disables page caching in WebKit: webk.it/43956
+ //
+ // Meanwhile, in Firefox < 8, an about:config setting could expose
+ // a false positive that would throw an exception: bugzil.la/688158
+
+ tests['geolocation'] = function() {
+ return 'geolocation' in navigator;
+ };
+
+
+ tests['postmessage'] = function() {
+ return !!window.postMessage;
+ };
+
+
+ // Chrome incognito mode used to throw an exception when using openDatabase
+ // It doesn't anymore.
+ tests['websqldatabase'] = function() {
+ return !!window.openDatabase;
+ };
+
+ // Vendors had inconsistent prefixing with the experimental Indexed DB:
+ // - Webkit's implementation is accessible through webkitIndexedDB
+ // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
+ // For speed, we don't test the legacy (and beta-only) indexedDB
+ tests['indexedDB'] = function() {
+ return !!testPropsAll("indexedDB", window);
+ };
+
+ // documentMode logic from YUI to filter out IE8 Compat Mode
+ // which false positives.
+ tests['hashchange'] = function() {
+ return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
+ };
+
+ // Per 1.6:
+ // This used to be Modernizr.historymanagement but the longer
+ // name has been deprecated in favor of a shorter and property-matching one.
+ // The old API is still available in 1.6, but as of 2.0 will throw a warning,
+ // and in the first release thereafter disappear entirely.
+ tests['history'] = function() {
+ return !!(window.history && history.pushState);
+ };
+
+ tests['draganddrop'] = function() {
+ var div = document.createElement('div');
+ return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
+ };
+
+ // FF3.6 was EOL'ed on 4/24/12, but the ESR version of FF10
+ // will be supported until FF19 (2/12/13), at which time, ESR becomes FF17.
+ // FF10 still uses prefixes, so check for it until then.
+ // for more ESR info, see: mozilla.org/en-US/firefox/organizations/faq/
+ tests['websockets'] = function() {
+ return 'WebSocket' in window || 'MozWebSocket' in window;
+ };
+
+
+ // css-tricks.com/rgba-browser-support/
+ tests['rgba'] = function() {
+ // Set an rgba() color and check the returned value
+
+ setCss('background-color:rgba(150,255,150,.5)');
+
+ return contains(mStyle.backgroundColor, 'rgba');
+ };
+
+ tests['hsla'] = function() {
+ // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
+ // except IE9 who retains it as hsla
+
+ setCss('background-color:hsla(120,40%,100%,.5)');
+
+ return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
+ };
+
+ tests['multiplebgs'] = function() {
+ // Setting multiple images AND a color on the background shorthand property
+ // and then querying the style.background property value for the number of
+ // occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
+
+ setCss('background:url(https://),url(https://),red url(https://)');
+
+ // If the UA supports multiple backgrounds, there should be three occurrences
+ // of the string "url(" in the return value for elemStyle.background
+
+ return (/(url\s*\(.*?){3}/).test(mStyle.background);
+ };
+
+
+
+ // this will false positive in Opera Mini
+ // github.com/Modernizr/Modernizr/issues/396
+
+ tests['backgroundsize'] = function() {
+ return testPropsAll('backgroundSize');
+ };
+
+ tests['borderimage'] = function() {
+ return testPropsAll('borderImage');
+ };
+
+
+ // Super comprehensive table about all the unique implementations of
+ // border-radius: muddledramblings.com/table-of-css3-border-radius-compliance
+
+ tests['borderradius'] = function() {
+ return testPropsAll('borderRadius');
+ };
+
+ // WebOS unfortunately false positives on this test.
+ tests['boxshadow'] = function() {
+ return testPropsAll('boxShadow');
+ };
+
+ // FF3.0 will false positive on this test
+ tests['textshadow'] = function() {
+ return document.createElement('div').style.textShadow === '';
+ };
+
+
+ tests['opacity'] = function() {
+ // Browsers that actually have CSS Opacity implemented have done so
+ // according to spec, which means their return values are within the
+ // range of [0.0,1.0] - including the leading zero.
+
+ setCssAll('opacity:.55');
+
+ // The non-literal . in this regex is intentional:
+ // German Chrome returns this value as 0,55
+ // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
+ return (/^0.55$/).test(mStyle.opacity);
+ };
+
+
+ // Note, Android < 4 will pass this test, but can only animate
+ // a single property at a time
+ // goo.gl/v3V4Gp
+ tests['cssanimations'] = function() {
+ return testPropsAll('animationName');
+ };
+
+
+ tests['csscolumns'] = function() {
+ return testPropsAll('columnCount');
+ };
+
+
+ tests['cssgradients'] = function() {
+ /**
+ * For CSS Gradients syntax, please see:
+ * webkit.org/blog/175/introducing-css-gradients/
+ * developer.mozilla.org/en/CSS/-moz-linear-gradient
+ * developer.mozilla.org/en/CSS/-moz-radial-gradient
+ * dev.w3.org/csswg/css3-images/#gradients-
+ */
+
+ var str1 = 'background-image:',
+ str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
+ str3 = 'linear-gradient(left top,#9f9, white);';
+
+ setCss(
+ // legacy webkit syntax (FIXME: remove when syntax not in use anymore)
+ (str1 + '-webkit- '.split(' ').join(str2 + str1) +
+ // standard syntax // trailing 'background-image:'
+ prefixes.join(str3 + str1)).slice(0, -str1.length)
+ );
+
+ return contains(mStyle.backgroundImage, 'gradient');
+ };
+
+
+ tests['cssreflections'] = function() {
+ return testPropsAll('boxReflect');
+ };
+
+
+ tests['csstransforms'] = function() {
+ return !!testPropsAll('transform');
+ };
+
+
+ tests['csstransforms3d'] = function() {
+
+ var ret = !!testPropsAll('perspective');
+
+ // Webkit's 3D transforms are passed off to the browser's own graphics renderer.
+ // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
+ // some conditions. As a result, Webkit typically recognizes the syntax but
+ // will sometimes throw a false positive, thus we must do a more thorough check:
+ if ( ret && 'webkitPerspective' in docElement.style ) {
+
+ // Webkit allows this media query to succeed only if the feature is enabled.
+ // `@media (transform-3d),(-webkit-transform-3d){ ... }`
+ injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
+ ret = node.offsetLeft === 9 && node.offsetHeight === 3;
+ });
+ }
+ return ret;
+ };
+
+
+ tests['csstransitions'] = function() {
+ return testPropsAll('transition');
+ };
+
+
+ /*>>fontface*/
+ // @font-face detection routine by Diego Perini
+ // javascript.nwbox.com/CSSSupport/
+
+ // false positives:
+ // WebOS github.com/Modernizr/Modernizr/issues/342
+ // WP7 github.com/Modernizr/Modernizr/issues/538
+ tests['fontface'] = function() {
+ var bool;
+
+ injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
+ var style = document.getElementById('smodernizr'),
+ sheet = style.sheet || style.styleSheet,
+ cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
+
+ bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
+ });
+
+ return bool;
+ };
+ /*>>fontface*/
+
+ // CSS generated content detection
+ tests['generatedcontent'] = function() {
+ var bool;
+
+ injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) {
+ bool = node.offsetHeight >= 3;
+ });
+
+ return bool;
+ };
+
+
+
+ // These tests evaluate support of the video/audio elements, as well as
+ // testing what types of content they support.
+ //
+ // We're using the Boolean constructor here, so that we can extend the value
+ // e.g. Modernizr.video // true
+ // Modernizr.video.ogg // 'probably'
+ //
+ // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
+ // thx to NielsLeenheer and zcorpan
+
+ // Note: in some older browsers, "no" was a return value instead of empty string.
+ // It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
+ // It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
+
+ tests['video'] = function() {
+ var elem = document.createElement('video'),
+ bool = false;
+
+ // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
+ try {
+ if ( bool = !!elem.canPlayType ) {
+ bool = new Boolean(bool);
+ bool.ogg = elem.canPlayType('video/ogg; codecs="theora"') .replace(/^no$/,'');
+
+ // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
+ bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
+
+ bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
+ }
+
+ } catch(e) { }
+
+ return bool;
+ };
+
+ tests['audio'] = function() {
+ var elem = document.createElement('audio'),
+ bool = false;
+
+ try {
+ if ( bool = !!elem.canPlayType ) {
+ bool = new Boolean(bool);
+ bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
+ bool.mp3 = elem.canPlayType('audio/mpeg;') .replace(/^no$/,'');
+
+ // Mimetypes accepted:
+ // developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
+ // bit.ly/iphoneoscodecs
+ bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/,'');
+ bool.m4a = ( elem.canPlayType('audio/x-m4a;') ||
+ elem.canPlayType('audio/aac;')) .replace(/^no$/,'');
+ }
+ } catch(e) { }
+
+ return bool;
+ };
+
+
+ // In FF4, if disabled, window.localStorage should === null.
+
+ // Normally, we could not test that directly and need to do a
+ // `('localStorage' in window) && ` test first because otherwise Firefox will
+ // throw bugzil.la/365772 if cookies are disabled
+
+ // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
+ // will throw the exception:
+ // QUOTA_EXCEEDED_ERRROR DOM Exception 22.
+ // Peculiarly, getItem and removeItem calls do not throw.
+
+ // Because we are forced to try/catch this, we'll go aggressive.
+
+ // Just FWIW: IE8 Compat mode supports these features completely:
+ // www.quirksmode.org/dom/html5.html
+ // But IE8 doesn't support either with local files
+
+ tests['localstorage'] = function() {
+ try {
+ localStorage.setItem(mod, mod);
+ localStorage.removeItem(mod);
+ return true;
+ } catch(e) {
+ return false;
+ }
+ };
+
+ tests['sessionstorage'] = function() {
+ try {
+ sessionStorage.setItem(mod, mod);
+ sessionStorage.removeItem(mod);
+ return true;
+ } catch(e) {
+ return false;
+ }
+ };
+
+
+ tests['webworkers'] = function() {
+ return !!window.Worker;
+ };
+
+
+ tests['applicationcache'] = function() {
+ return !!window.applicationCache;
+ };
+
+
+ // Thanks to Erik Dahlstrom
+ tests['svg'] = function() {
+ return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
+ };
+
+ // specifically for SVG inline in HTML, not within XHTML
+ // test page: paulirish.com/demo/inline-svg
+ tests['inlinesvg'] = function() {
+ var div = document.createElement('div');
+ div.innerHTML = '';
+ return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
+ };
+
+ // SVG SMIL animation
+ tests['smil'] = function() {
+ return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
+ };
+
+ // This test is only for clip paths in SVG proper, not clip paths on HTML content
+ // demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg
+
+ // However read the comments to dig into applying SVG clippaths to HTML content here:
+ // github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491
+ tests['svgclippaths'] = function() {
+ return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
+ };
+
+ /*>>webforms*/
+ // input features and input types go directly onto the ret object, bypassing the tests loop.
+ // Hold this guy to execute in a moment.
+ function webforms() {
+ /*>>input*/
+ // Run through HTML5's new input attributes to see if the UA understands any.
+ // We're using f which is the element created early on
+ // Mike Taylr has created a comprehensive resource for testing these attributes
+ // when applied to all input types:
+ // miketaylr.com/code/input-type-attr.html
+ // spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
+
+ // Only input placeholder is tested while textarea's placeholder is not.
+ // Currently Safari 4 and Opera 11 have support only for the input placeholder
+ // Both tests are available in feature-detects/forms-placeholder.js
+ Modernizr['input'] = (function( props ) {
+ for ( var i = 0, len = props.length; i < len; i++ ) {
+ attrs[ props[i] ] = !!(props[i] in inputElem);
+ }
+ if (attrs.list){
+ // safari false positive's on datalist: webk.it/74252
+ // see also github.com/Modernizr/Modernizr/issues/146
+ attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
+ }
+ return attrs;
+ })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
+ /*>>input*/
+
+ /*>>inputtypes*/
+ // Run through HTML5's new input types to see if the UA understands any.
+ // This is put behind the tests runloop because it doesn't return a
+ // true/false like all the other tests; instead, it returns an object
+ // containing each input type with its corresponding true/false value
+
+ // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
+ Modernizr['inputtypes'] = (function(props) {
+
+ for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
+
+ inputElem.setAttribute('type', inputElemType = props[i]);
+ bool = inputElem.type !== 'text';
+
+ // We first check to see if the type we give it sticks..
+ // If the type does, we feed it a textual value, which shouldn't be valid.
+ // If the value doesn't stick, we know there's input sanitization which infers a custom UI
+ if ( bool ) {
+
+ inputElem.value = smile;
+ inputElem.style.cssText = 'position:absolute;visibility:hidden;';
+
+ if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
+
+ docElement.appendChild(inputElem);
+ defaultView = document.defaultView;
+
+ // Safari 2-4 allows the smiley as a value, despite making a slider
+ bool = defaultView.getComputedStyle &&
+ defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
+ // Mobile android web browser has false positive, so must
+ // check the height to see if the widget is actually there.
+ (inputElem.offsetHeight !== 0);
+
+ docElement.removeChild(inputElem);
+
+ } else if ( /^(search|tel)$/.test(inputElemType) ){
+ // Spec doesn't define any special parsing or detectable UI
+ // behaviors so we pass these through as true
+
+ // Interestingly, opera fails the earlier test, so it doesn't
+ // even make it here.
+
+ } else if ( /^(url|email)$/.test(inputElemType) ) {
+ // Real url and email support comes with prebaked validation.
+ bool = inputElem.checkValidity && inputElem.checkValidity() === false;
+
+ } else {
+ // If the upgraded input compontent rejects the :) text, we got a winner
+ bool = inputElem.value != smile;
+ }
+ }
+
+ inputs[ props[i] ] = !!bool;
+ }
+ return inputs;
+ })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
+ /*>>inputtypes*/
+ }
+ /*>>webforms*/
+
+
+ // End of test definitions
+ // -----------------------
+
+
+
+ // Run through all tests and detect their support in the current UA.
+ // todo: hypothetically we could be doing an array of tests and use a basic loop here.
+ for ( var feature in tests ) {
+ if ( hasOwnProp(tests, feature) ) {
+ // run the test, throw the return value into the Modernizr,
+ // then based on that boolean, define an appropriate className
+ // and push it into an array of classes we'll join later.
+ featureName = feature.toLowerCase();
+ Modernizr[featureName] = tests[feature]();
+
+ classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
+ }
+ }
+
+ /*>>webforms*/
+ // input tests need to run.
+ Modernizr.input || webforms();
+ /*>>webforms*/
+
+
+ /**
+ * addTest allows the user to define their own feature tests
+ * the result will be added onto the Modernizr object,
+ * as well as an appropriate className set on the html element
+ *
+ * @param feature - String naming the feature
+ * @param test - Function returning true if feature is supported, false if not
+ */
+ Modernizr.addTest = function ( feature, test ) {
+ if ( typeof feature == 'object' ) {
+ for ( var key in feature ) {
+ if ( hasOwnProp( feature, key ) ) {
+ Modernizr.addTest( key, feature[ key ] );
+ }
+ }
+ } else {
+
+ feature = feature.toLowerCase();
+
+ if ( Modernizr[feature] !== undefined ) {
+ // we're going to quit if you're trying to overwrite an existing test
+ // if we were to allow it, we'd do this:
+ // var re = new RegExp("\\b(no-)?" + feature + "\\b");
+ // docElement.className = docElement.className.replace( re, '' );
+ // but, no rly, stuff 'em.
+ return Modernizr;
+ }
+
+ test = typeof test == 'function' ? test() : test;
+
+ if (typeof enableClasses !== "undefined" && enableClasses) {
+ docElement.className += ' ' + (test ? '' : 'no-') + feature;
+ }
+ Modernizr[feature] = test;
+
+ }
+
+ return Modernizr; // allow chaining.
+ };
+
+
+ // Reset modElem.cssText to nothing to reduce memory footprint.
+ setCss('');
+ modElem = inputElem = null;
+
+ /*>>shiv*/
+ /**
+ * @preserve HTML5 Shiv prev3.7.1 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
+ */
+ ;(function(window, document) {
+ /*jshint evil:true */
+ /** version */
+ var version = '3.7.0';
+
+ /** Preset options */
+ var options = window.html5 || {};
+
+ /** Used to skip problem elements */
+ var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
+
+ /** Not all elements can be cloned in IE **/
+ var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
+
+ /** Detect whether the browser supports default html5 styles */
+ var supportsHtml5Styles;
+
+ /** Name of the expando, to work with multiple documents or to re-shiv one document */
+ var expando = '_html5shiv';
+
+ /** The id for the the documents expando */
+ var expanID = 0;
+
+ /** Cached data for each document */
+ var expandoData = {};
+
+ /** Detect whether the browser supports unknown elements */
+ var supportsUnknownElements;
+
+ (function() {
+ try {
+ var a = document.createElement('a');
+ a.innerHTML = '';
+ //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
+ supportsHtml5Styles = ('hidden' in a);
+
+ supportsUnknownElements = a.childNodes.length == 1 || (function() {
+ // assign a false positive if unable to shiv
+ (document.createElement)('a');
+ var frag = document.createDocumentFragment();
+ return (
+ typeof frag.cloneNode == 'undefined' ||
+ typeof frag.createDocumentFragment == 'undefined' ||
+ typeof frag.createElement == 'undefined'
+ );
+ }());
+ } catch(e) {
+ // assign a false positive if detection fails => unable to shiv
+ supportsHtml5Styles = true;
+ supportsUnknownElements = true;
+ }
+
+ }());
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * Creates a style sheet with the given CSS text and adds it to the document.
+ * @private
+ * @param {Document} ownerDocument The document.
+ * @param {String} cssText The CSS text.
+ * @returns {StyleSheet} The style element.
+ */
+ function addStyleSheet(ownerDocument, cssText) {
+ var p = ownerDocument.createElement('p'),
+ parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
+
+ p.innerHTML = 'x';
+ return parent.insertBefore(p.lastChild, parent.firstChild);
+ }
+
+ /**
+ * Returns the value of `html5.elements` as an array.
+ * @private
+ * @returns {Array} An array of shived element node names.
+ */
+ function getElements() {
+ var elements = html5.elements;
+ return typeof elements == 'string' ? elements.split(' ') : elements;
+ }
+
+ /**
+ * Returns the data associated to the given document
+ * @private
+ * @param {Document} ownerDocument The document.
+ * @returns {Object} An object of data.
+ */
+ function getExpandoData(ownerDocument) {
+ var data = expandoData[ownerDocument[expando]];
+ if (!data) {
+ data = {};
+ expanID++;
+ ownerDocument[expando] = expanID;
+ expandoData[expanID] = data;
+ }
+ return data;
+ }
+
+ /**
+ * returns a shived element for the given nodeName and document
+ * @memberOf html5
+ * @param {String} nodeName name of the element
+ * @param {Document} ownerDocument The context document.
+ * @returns {Object} The shived element.
+ */
+ function createElement(nodeName, ownerDocument, data){
+ if (!ownerDocument) {
+ ownerDocument = document;
+ }
+ if(supportsUnknownElements){
+ return ownerDocument.createElement(nodeName);
+ }
+ if (!data) {
+ data = getExpandoData(ownerDocument);
+ }
+ var node;
+
+ if (data.cache[nodeName]) {
+ node = data.cache[nodeName].cloneNode();
+ } else if (saveClones.test(nodeName)) {
+ node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
+ } else {
+ node = data.createElem(nodeName);
+ }
+
+ // Avoid adding some elements to fragments in IE < 9 because
+ // * Attributes like `name` or `type` cannot be set/changed once an element
+ // is inserted into a document/fragment
+ // * Link elements with `src` attributes that are inaccessible, as with
+ // a 403 response, will cause the tab/window to crash
+ // * Script elements appended to fragments will execute when their `src`
+ // or `text` property is set
+ return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
+ }
+
+ /**
+ * returns a shived DocumentFragment for the given document
+ * @memberOf html5
+ * @param {Document} ownerDocument The context document.
+ * @returns {Object} The shived DocumentFragment.
+ */
+ function createDocumentFragment(ownerDocument, data){
+ if (!ownerDocument) {
+ ownerDocument = document;
+ }
+ if(supportsUnknownElements){
+ return ownerDocument.createDocumentFragment();
+ }
+ data = data || getExpandoData(ownerDocument);
+ var clone = data.frag.cloneNode(),
+ i = 0,
+ elems = getElements(),
+ l = elems.length;
+ for(;i>shiv*/
+
+ // Assign private properties to the return object with prefix
+ Modernizr._version = version;
+
+ // expose these for the plugin API. Look in the source for how to join() them against your input
+ /*>>prefixes*/
+ Modernizr._prefixes = prefixes;
+ /*>>prefixes*/
+ /*>>domprefixes*/
+ Modernizr._domPrefixes = domPrefixes;
+ Modernizr._cssomPrefixes = cssomPrefixes;
+ /*>>domprefixes*/
+
+ /*>>mq*/
+ // Modernizr.mq tests a given media query, live against the current state of the window
+ // A few important notes:
+ // * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
+ // * A max-width or orientation query will be evaluated against the current state, which may change later.
+ // * You must specify values. Eg. If you are testing support for the min-width media query use:
+ // Modernizr.mq('(min-width:0)')
+ // usage:
+ // Modernizr.mq('only screen and (max-width:768)')
+ Modernizr.mq = testMediaQuery;
+ /*>>mq*/
+
+ /*>>hasevent*/
+ // Modernizr.hasEvent() detects support for a given event, with an optional element to test on
+ // Modernizr.hasEvent('gesturestart', elem)
+ Modernizr.hasEvent = isEventSupported;
+ /*>>hasevent*/
+
+ /*>>testprop*/
+ // Modernizr.testProp() investigates whether a given style property is recognized
+ // Note that the property names must be provided in the camelCase variant.
+ // Modernizr.testProp('pointerEvents')
+ Modernizr.testProp = function(prop){
+ return testProps([prop]);
+ };
+ /*>>testprop*/
+
+ /*>>testallprops*/
+ // Modernizr.testAllProps() investigates whether a given style property,
+ // or any of its vendor-prefixed variants, is recognized
+ // Note that the property names must be provided in the camelCase variant.
+ // Modernizr.testAllProps('boxSizing')
+ Modernizr.testAllProps = testPropsAll;
+ /*>>testallprops*/
+
+
+ /*>>teststyles*/
+ // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
+ // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
+ Modernizr.testStyles = injectElementWithStyles;
+ /*>>teststyles*/
+
+
+ /*>>prefixed*/
+ // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
+ // Modernizr.prefixed('boxSizing') // 'MozBoxSizing'
+
+ // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
+ // Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
+ //
+ // str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
+
+ // If you're trying to ascertain which transition end event to bind to, you might do something like...
+ //
+ // var transEndEventNames = {
+ // 'WebkitTransition' : 'webkitTransitionEnd',
+ // 'MozTransition' : 'transitionend',
+ // 'OTransition' : 'oTransitionEnd',
+ // 'msTransition' : 'MSTransitionEnd',
+ // 'transition' : 'transitionend'
+ // },
+ // transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
+
+ Modernizr.prefixed = function(prop, obj, elem){
+ if(!obj) {
+ return testPropsAll(prop, 'pfx');
+ } else {
+ // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
+ return testPropsAll(prop, obj, elem);
+ }
+ };
+ /*>>prefixed*/
+
+
+ /*>>cssclasses*/
+ // Remove "no-js" class from element, if it exists:
+ docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +
+
+ // Add the new classes to the element.
+ (enableClasses ? ' js ' + classes.join(' ') : '');
+ /*>>cssclasses*/
+
+ return Modernizr;
+
+})(this, this.document);
diff --git a/MP-MON-PI/IOB-MON-2021.12/MP-MON-DEMO_files/respond.js b/MP-MON-PI/IOB-MON-2021.12/MP-MON-DEMO_files/respond.js
new file mode 100644
index 0000000..b1298d0
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/MP-MON-DEMO_files/respond.js
@@ -0,0 +1,224 @@
+/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
+/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
+(function(w) {
+ "use strict";
+ w.matchMedia = w.matchMedia || function(doc, undefined) {
+ var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div");
+ div.id = "mq-test-1";
+ div.style.cssText = "position:absolute;top:-100em";
+ fakeBody.style.background = "none";
+ fakeBody.appendChild(div);
+ return function(q) {
+ div.innerHTML = '';
+ docElem.insertBefore(fakeBody, refNode);
+ bool = div.offsetWidth === 42;
+ docElem.removeChild(fakeBody);
+ return {
+ matches: bool,
+ media: q
+ };
+ };
+ }(w.document);
+})(this);
+
+/*! Respond.js v1.4.0: min/max-width media query polyfill. (c) Scott Jehl. MIT Lic. j.mp/respondjs */
+(function(w) {
+ "use strict";
+ var respond = {};
+ w.respond = respond;
+ respond.update = function() {};
+ var requestQueue = [], xmlHttp = function() {
+ var xmlhttpmethod = false;
+ try {
+ xmlhttpmethod = new w.XMLHttpRequest();
+ } catch (e) {
+ xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP");
+ }
+ return function() {
+ return xmlhttpmethod;
+ };
+ }(), ajax = function(url, callback) {
+ var req = xmlHttp();
+ if (!req) {
+ return;
+ }
+ req.open("GET", url, true);
+ req.onreadystatechange = function() {
+ if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) {
+ return;
+ }
+ callback(req.responseText);
+ };
+ if (req.readyState === 4) {
+ return;
+ }
+ req.send(null);
+ };
+ respond.ajax = ajax;
+ respond.queue = requestQueue;
+ respond.regex = {
+ media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,
+ keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,
+ urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,
+ findStyles: /@media *([^\{]+)\{([\S\s]+?)$/,
+ only: /(only\s+)?([a-zA-Z]+)\s?/,
+ minw: /\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,
+ maxw: /\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/
+ };
+ respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches;
+ if (respond.mediaQueriesSupported) {
+ return;
+ }
+ var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() {
+ var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false;
+ div.style.cssText = "position:absolute;font-size:1em;width:1em";
+ if (!body) {
+ body = fakeUsed = doc.createElement("body");
+ body.style.background = "none";
+ }
+ docElem.style.fontSize = "100%";
+ body.style.fontSize = "100%";
+ body.appendChild(div);
+ if (fakeUsed) {
+ docElem.insertBefore(body, docElem.firstChild);
+ }
+ ret = div.offsetWidth;
+ if (fakeUsed) {
+ docElem.removeChild(body);
+ } else {
+ body.removeChild(div);
+ }
+ docElem.style.fontSize = originalHTMLFontSize;
+ if (originalBodyFontSize) {
+ body.style.fontSize = originalBodyFontSize;
+ }
+ ret = eminpx = parseFloat(ret);
+ return ret;
+ }, applyMedia = function(fromResize) {
+ var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime();
+ if (fromResize && lastCall && now - lastCall < resizeThrottle) {
+ w.clearTimeout(resizeDefer);
+ resizeDefer = w.setTimeout(applyMedia, resizeThrottle);
+ return;
+ } else {
+ lastCall = now;
+ }
+ for (var i in mediastyles) {
+ if (mediastyles.hasOwnProperty(i)) {
+ var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em";
+ if (!!min) {
+ min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
+ }
+ if (!!max) {
+ max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1);
+ }
+ if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) {
+ if (!styleBlocks[thisstyle.media]) {
+ styleBlocks[thisstyle.media] = [];
+ }
+ styleBlocks[thisstyle.media].push(rules[thisstyle.rules]);
+ }
+ }
+ }
+ for (var j in appendedEls) {
+ if (appendedEls.hasOwnProperty(j)) {
+ if (appendedEls[j] && appendedEls[j].parentNode === head) {
+ head.removeChild(appendedEls[j]);
+ }
+ }
+ }
+ appendedEls.length = 0;
+ for (var k in styleBlocks) {
+ if (styleBlocks.hasOwnProperty(k)) {
+ var ss = doc.createElement("style"), css = styleBlocks[k].join("\n");
+ ss.type = "text/css";
+ ss.media = k;
+ head.insertBefore(ss, lastLink.nextSibling);
+ if (ss.styleSheet) {
+ ss.styleSheet.cssText = css;
+ } else {
+ ss.appendChild(doc.createTextNode(css));
+ }
+ appendedEls.push(ss);
+ }
+ }
+ }, translate = function(styles, href, media) {
+ var qs = styles.replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0;
+ href = href.substring(0, href.lastIndexOf("/"));
+ var repUrls = function(css) {
+ return css.replace(respond.regex.urls, "$1" + href + "$2$3");
+ }, useMedia = !ql && media;
+ if (href.length) {
+ href += "/";
+ }
+ if (useMedia) {
+ ql = 1;
+ }
+ for (var i = 0; i < ql; i++) {
+ var fullq, thisq, eachq, eql;
+ if (useMedia) {
+ fullq = media;
+ rules.push(repUrls(styles));
+ } else {
+ fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1;
+ rules.push(RegExp.$2 && repUrls(RegExp.$2));
+ }
+ eachq = fullq.split(",");
+ eql = eachq.length;
+ for (var j = 0; j < eql; j++) {
+ thisq = eachq[j];
+ mediastyles.push({
+ media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all",
+ rules: rules.length - 1,
+ hasquery: thisq.indexOf("(") > -1,
+ minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""),
+ maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "")
+ });
+ }
+ }
+ applyMedia();
+ }, makeRequests = function() {
+ if (requestQueue.length) {
+ var thisRequest = requestQueue.shift();
+ ajax(thisRequest.href, function(styles) {
+ translate(styles, thisRequest.href, thisRequest.media);
+ parsedSheets[thisRequest.href] = true;
+ w.setTimeout(function() {
+ makeRequests();
+ }, 0);
+ });
+ }
+ }, ripCSS = function() {
+ for (var i = 0; i < links.length; i++) {
+ var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
+ if (!!href && isCSS && !parsedSheets[href]) {
+ if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
+ translate(sheet.styleSheet.rawCssText, href, media);
+ parsedSheets[href] = true;
+ } else {
+ if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) {
+ if (href.substring(0, 2) === "//") {
+ href = w.location.protocol + href;
+ }
+ requestQueue.push({
+ href: href,
+ media: media
+ });
+ }
+ }
+ }
+ }
+ makeRequests();
+ };
+ ripCSS();
+ respond.update = ripCSS;
+ respond.getEmValue = getEmValue;
+ function callMedia() {
+ applyMedia(true);
+ }
+ if (w.addEventListener) {
+ w.addEventListener("resize", callMedia, false);
+ } else if (w.attachEvent) {
+ w.attachEvent("onresize", callMedia);
+ }
+})(this);
\ No newline at end of file
diff --git a/MP-MON-PI/IOB-MON-2021.12/READ.me b/MP-MON-PI/IOB-MON-2021.12/READ.me
new file mode 100644
index 0000000..b4b4cc4
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/READ.me
@@ -0,0 +1,10 @@
+Per sistemare log e script vari eseguire file install (come sudo)
+
+POI va sistemata chiamata x target sysctl:
+
+systemctl enable sendRebootIOB
+systemctl daemon-reload
+systemctl status sendRebootIOB
+
+RICORDARSI di creare crontab x root x registrazione temperature!!!
+*/20 * * * * /usr/local/bin/saveTemp.sh
diff --git a/MP-MON-PI/IOB-MON-2021.12/checkOffline.sh b/MP-MON-PI/IOB-MON-2021.12/checkOffline.sh
new file mode 100644
index 0000000..f75b5e2
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/checkOffline.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# gestione check x riavvio se offline
+FILE=/home/pi/steamware/ImOffline.sta
+
+# in aggiunta verifico di essere ancora online...
+netStatus=`cat /sys/class/net/eth0/operstate`
+
+if [[ $netStatus != "up" ]] ;
+then
+ echo "Creating offline file $FILE"
+ touch "$FILE"
+fi
+
+# Verifica: se fosse offline esegue startBrowser...
+if test -f "$FILE" ;
+then
+ echo "$FILE exists, MON offline, try restart"
+ systemctl restart startBrowser
+ rm $FILE
+fi
diff --git a/MP-MON-PI/IOB-MON-2021.12/install-RPI-MON.sh b/MP-MON-PI/IOB-MON-2021.12/install-RPI-MON.sh
new file mode 100644
index 0000000..ff38dec
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/install-RPI-MON.sh
@@ -0,0 +1,60 @@
+#|/bin/bash
+
+#installa il necessario per RPI-MON partendo dal contenuto della folder /home/pi/steamware
+
+#step 1: creo file di log nuovi
+rm /var/log/log*.txt
+rm /var/log/log*.log
+rm /home/pi/steamware/log*.txt
+rm /home/pi/steamware/log*.log
+
+touch /var/log/logReboot.log
+touch /var/log/logBrowser.log
+touch /var/log/logTemp.log
+touch /var/log/logMonitor.log
+
+ln -sf /var/log/logReboot.log /home/pi/steamware/logReboot.log
+ln -sf /var/log/logBrowser.log /home/pi/steamware/logBrowser.log
+ln -sf /var/log/logTemp.log /home/pi/steamware/logTemp.log
+ln -sf /var/log/logMonitor.log /home/pi/steamware/logMonitor.log
+
+chown pi:pi /home/pi -R
+chmod 777 /var/log/log*.log
+
+#step 2: copio files in /usr/local/bin
+chmod +x *.sh
+cp *.sh /usr/local/bin/
+cp *.ini /usr/local/bin/
+
+# step 3: copio target systemd in avvio...
+cp -f sendRebootIOB /etc/init.d/sendRebootIOB
+chmod +x /etc/init.d/sendRebootIOB
+cp -f sendRebootIOB.service /etc/systemd/system/sendRebootIOB.service
+echo ""
+echo "-----------------------------------------------"
+echo "Completare registrazione servizio avvio: digitare i seguenti comandi"
+echo "systemctl enable sendRebootIOB"
+echo "systemctl daemon-reload"
+echo "systemctl status sendRebootIOB"
+echo "-----------------------------------------------"
+echo ""
+echo ""
+echo ""
+echo "-----------------------------------------------"
+echo "Infine creare voce crontab che salvi temperatura CPU/GPU ogni 20 minuti..."
+echo "crontab -e"
+echo "*/20 * * * * /usr/local/bin/saveTemp.sh"
+echo "-----------------------------------------------"
+
+
+# step 4: copio target systemd in avvio x start browser...
+cp -f startBrowser.service /etc/systemd/system/startBrowser.service
+echo ""
+echo "-----------------------------------------------"
+echo "Completare registrazione servizio avvio: digitare i seguenti comandi"
+echo "systemctl enable startBrowser"
+echo "systemctl daemon-reload"
+echo "systemctl status startBrowser"
+echo "-----------------------------------------------"
+
+
diff --git a/MP-MON-PI/IOB-MON-2021.12/kiosk.sh b/MP-MON-PI/IOB-MON-2021.12/kiosk.sh
new file mode 100644
index 0000000..6fd3cf6
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/kiosk.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+xset s noblank
+xset s off
+xset -dpms
+unclutter -idle 0.5 -root &
+sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' /home/pi/.config/chromium/Default/Preferences
+sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' /home/pi/.config/chromium/Default/Preferences
+/usr/bin/chromium-browser --noerrdialogs --disable-infobars --kiosk
diff --git a/MP-MON-PI/IOB-MON-2021.12/monitorOff.sh b/MP-MON-PI/IOB-MON-2021.12/monitorOff.sh
new file mode 100644
index 0000000..7a93545
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/monitorOff.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+export DISPLAY=:0.0
+
+xset dpms force standby
+
+#imposto logFile
+logFile="/var/log/logMonitor.log"
+
+echo "$(date) | Monitor OFF " >> $logFile
diff --git a/MP-MON-PI/IOB-MON-2021.12/monitorOn.sh b/MP-MON-PI/IOB-MON-2021.12/monitorOn.sh
new file mode 100644
index 0000000..c2a6586
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/monitorOn.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+export DISPLAY=:0.0
+
+xset dpms force on
+
+#imposto logFile
+logFile="/var/log/logMonitor.log"
+
+echo "$(date) | Monitor ON " >> $logFile
diff --git a/MP-MON-PI/IOB-MON-2021.12/saveTemp.sh b/MP-MON-PI/IOB-MON-2021.12/saveTemp.sh
new file mode 100644
index 0000000..a2cd2be
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/saveTemp.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+#salva la temperatura CPU e GPU su chiamata...
+
+# imposto logfile...
+logFile="/var/log/logTemp.txt"
+
+cpuTemp0=$(cat /sys/class/thermal/thermal_zone0/temp)
+cpuTemp1=$(($cpuTemp0/1000))
+cpuTemp2=$(($cpuTemp0/100))
+cpuTempM=$(($cpuTemp2 % $cpuTemp1))
+
+gpuTemp=`vcgencmd measure_temp`
+
+loadAvg=`cat /proc/loadavg`
+
+echo "$(date) | CPU: temp=$cpuTemp1.$cpuTempM ºC | GPU: $gpuTemp | LoadAvg: $loadAvg" >> $logFile
diff --git a/MP-MON-PI/IOB-MON-2021.12/sendReboot.py b/MP-MON-PI/IOB-MON-2021.12/sendReboot.py
new file mode 100644
index 0000000..d83f6c0
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/sendReboot.py
@@ -0,0 +1,131 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# sendReboot v. 1.8
+
+#---------------------------------------------------------------
+
+
+import time
+import sys
+
+
+from datetime import datetime
+
+import urllib.request
+import configparser
+import os, sys
+
+import logging
+
+import time
+
+#---------------------------------------------------------------
+
+# COSTANTI
+PROGRAM_NAME = "SendReboot IOB-pi v.1.8"
+
+# DA FILE CONF
+idxMacchina = "99"
+
+# registro se ho fatto chiamata
+global numTry
+numTry = 1
+
+
+#---------------------------------------------------------------
+#Funzione di scrittura su url con try-except
+#---------------------------------------------------------------
+
+def chiamaUrl(numTry):
+ try:
+ with urllib.request.urlopen( url ) as urlCli:
+ s = urlCli.read()
+ print(s)
+ numTry = numTry + 10
+ except Exception as e:
+ print (e)
+ logging.info ( e )
+ print("Url aforte" , url)
+ return numTry
+
+
+#---------------------------------------------------------------
+# Funzione di recupero mac address per poterlo inviare a MPIO
+#---------------------------------------------------------------
+def getMAC(interface):
+ # Return the MAC address of interface
+ try:
+ str = open('/sys/class/net/' + interface + '/address').read()
+ except:
+ str = "00:00:00:00:00:00"
+ return str[0:17]
+
+#---------------------------------------------------------------
+# MAIN
+#---------------------------------------------------------------
+
+try:
+ config = configparser.RawConfigParser()
+ config.read ( 'IOB.cfg' )
+
+ idxMacchina = config.get ( 'id' , 'idxMacchina' )
+
+
+ URLREBO = config.get ( 'web' , 'URLREBO' )
+
+ LOGFILE = config.get ( 'log' , 'LOGREBO' )
+except:
+ print("\n\n" + PROGRAM_NAME + ' - Error 4 - in config file ' 'IOB.cfg')
+ sys.exit(1)
+
+
+#--------------------------------------------
+# oggetto Logger
+#--------------------------------------------
+try:
+# log = Logger(LOGFILE)
+ logging.basicConfig(level=logging.DEBUG,
+ format='%(asctime)s %(name)-8s %(levelname)-8s %(message)s',
+ datefmt='%Y-%m-%d %H:%M:%S',
+ filename=LOGFILE,
+ filemode='a')
+
+except:
+ # manda mail o simili - FARE!!!
+ print ("LOG: Impossibile creare file log con nome ")
+ print (LOGFILE)
+#--------------------------------------------
+
+
+print ("\n\n" + PROGRAM_NAME + "\n\n")
+
+global startstatus
+startstatus = 1
+
+if startstatus == 1:
+ logging.info("Avvio Programma " + PROGRAM_NAME)
+
+
+# lettura file configurazione
+print ( ' idxMacchina = %s' % ( idxMacchina ) )
+print ( ' URLREBO = %s' % ( URLREBO ) )
+print ( ' LOGFILE = %s' % ( LOGFILE ) )
+
+# lettura mac address
+myMac = getMAC('eth0')
+print ( ' MAC Address = %s' % ( myMac ) )
+
+# configuro URL da inviare
+url = URLREBO + idxMacchina + "&mac=" + myMac
+
+# modifica: cerco se ho inviato segnale altrimenti ritento invio...
+while (numTry < 11):
+ logging.info("Tentativo invio URL: " + str(numTry) )
+ numTry = chiamaUrl(numTry)
+ time.sleep(3)
+ numTry = numTry + 1
+
+
+# registro che ho inviato!
+logging.info("Inviato segnale di reboot!: " + url )
diff --git a/MP-MON-PI/IOB-MON-2021.12/sendRebootIOB b/MP-MON-PI/IOB-MON-2021.12/sendRebootIOB
new file mode 100644
index 0000000..2d57e87
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/sendRebootIOB
@@ -0,0 +1,31 @@
+#!/bin/sh -
+#
+### BEGIN INIT INFO
+# Provides: sendReboot
+# Required-Start: $network $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Steamware's IOB reboot signal
+# Description: Steamware's sendReboot segnalazione reboot dispositivo
+### END INIT INFO
+
+#! /bin/sh
+# /etc/init.d/sendReboot
+
+
+
+export HOME
+case "$1" in
+ start)
+ echo "Starting sendReboot"
+ cd /home/pi/steamware
+ /usr/bin/python ./sendReboot.py 2>&1 &
+ ;;
+ *)
+ echo "Usage: /etc/init.d/sendReboot {start}"
+ exit 1
+ ;;
+esac
+exit 0
+
diff --git a/MP-MON-PI/IOB-MON-2021.12/sendRebootIOB.service b/MP-MON-PI/IOB-MON-2021.12/sendRebootIOB.service
new file mode 100644
index 0000000..d0204de
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/sendRebootIOB.service
@@ -0,0 +1,21 @@
+[Unit]
+SourcePath=/etc/init.d/sendRebootIOB
+Description=LSB: Steamware's IOB reboot signal
+Before=runlevel2.target runlevel3.target runlevel4.target runlevel5.target shutdown.target
+Wants=network-online.target
+After=network.target network-online.target auditd.service
+Conflicts=shutdown.target
+
+[Service]
+Type=forking
+Restart=no
+TimeoutSec=5min
+IgnoreSIGPIPE=no
+KillMode=process
+GuessMainPID=no
+RemainAfterExit=yes
+ExecStart=/etc/init.d/sendRebootIOB start
+ExecStop=/etc/init.d/sendRebootIOB stop
+
+[Install]
+WantedBy=multi-user.target
diff --git a/MP-MON-PI/IOB-MON-2021.12/splash.png b/MP-MON-PI/IOB-MON-2021.12/splash.png
new file mode 100644
index 0000000..361a978
Binary files /dev/null and b/MP-MON-PI/IOB-MON-2021.12/splash.png differ
diff --git a/MP-MON-PI/IOB-MON-2021.12/startBrowser.service b/MP-MON-PI/IOB-MON-2021.12/startBrowser.service
new file mode 100644
index 0000000..47d0554
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/startBrowser.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=LSB: Steamware's IOB MON Chromium startup
+After=graphical.target
+
+[Service]
+Environment=DISPLAY=:0.0
+Environment=XAUTHORITY=/home/pi/.Xauthority
+Type=simple
+ExecStart=/bin/bash /home/pi/steamware/startBrowser.sh
+Restart=on-abort
+User=pi
+Group=pi
+
+[Install]
+WantedBy=graphical.target
diff --git a/MP-MON-PI/IOB-MON-2021.12/startBrowser.sh b/MP-MON-PI/IOB-MON-2021.12/startBrowser.sh
new file mode 100644
index 0000000..c142076
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/startBrowser.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+# imposto logfile...
+logFile="/var/log/logBrowser.txt"
+
+#imposto rete e server: leggo conf file (non funziona all'avvio)
+. MON.ini
+
+#setup rete steamware
+#localNet="10.74.82"
+#srvAddr="10.74.82.219"
+
+#setup rete cliente
+#localNet="??.??.??"
+#srvAddr="??.??.??.??"
+
+# chiudo se fosse aperto un chrome precedente...
+killall -9 chromium-browser
+
+# primo test: rete online...
+numTry=0
+netStatus=`cat /sys/class/net/eth0/operstate`
+iaddr=`ifconfig eth0 | grep "inet " | cut -d 'n' -f 2 | cut -d ' ' -f 2`
+#echo "Netstatus: $netstatus" >> $logFile
+
+while [ $netStatus != "up" ] ;
+do
+ numTry=$(( $numTry + 1 ))
+ echo "$(date) | Siamo Offline, tentativo num $numTry" >> $logFile
+ if [ $numTry -gt 15 ]
+ then
+ netStatus=`cat /sys/class/net/eth0/operstate`
+ break
+ fi
+ sleep 1s
+ netStatus=`cat /sys/class/net/eth0/operstate`
+ #echo "Netstatus: $netstatus"
+done
+
+echo "$(date) | Cavo connesso, eth: $netStatus" >> $logFile
+
+#ora aspetto prenda IP...
+iaddr=`/sbin/ifconfig eth0 | grep "inet " | cut -d 'n' -f 2 | cut -d ' ' -f 2`
+numTry=0
+while [[ $iaddr == "" ]] ;
+do
+ numTry=$(( $numTry + 1 ))
+ echo "$(date) | Attesa IP, tentativo num $numTry" >> $logFile
+ if [ $numTry -gt 60 ]
+ then
+ iaddr=`/sbin/ifconfig eth0 | grep "inet " | cut -d 'n' -f 2 | cut -d ' ' -f 2`
+ break
+ fi
+ sleep 1s
+ iaddr=`/sbin/ifconfig eth0 | grep "inet " | cut -d 'n' -f 2 | cut -d ' ' -f 2`
+ #echo "IP: $iaddr"
+done
+
+echo "$(date) | IP: $iaddr" >> $logFile
+
+# default imposto su pagina demo!!
+url='/home/pi/steamware/MP-MON-DEMO.html'
+#url='http://10.74.82.218/MP/MON'
+
+if [[ $iaddr == "$localNet"* ]]
+then
+ url="http://$srvAddr/MP/MON"
+ echo "$(date) | Siamo in target URL, imposto pagina a $url!" >> $logFile
+ rm /home/pi/steamware/ImOffline.sta >> /dev/null 2>&1
+else
+ # salvo che sono offline
+ touch /home/pi/steamware/ImOffline.sta
+fi
+
+# chiudo se fosse aperto un chrome precedente...
+killall -9 chromium-browser
+
+# fix salvaschermo
+xset s noblank
+xset s off
+xset -dpms
+unclutter -idle 1.5 -root &
+
+# pulizia eventuale di errori su ultima chiusura chromium
+sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' /home/pi/.config/chromium/Default/Preferences
+sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' /home/pi/.config/chromium/Default/Preferences
+
+# avvio chromium in KIOSK senza segnalazione errori...
+#chromium-browser --noerrdialogs --kiosk http://10.74.82.219/MP-MON --incognito --disable-translate
+chromium-browser --noerrdialogs --kiosk $url --incognito --disable-translate --disable-infobars --disable-component-update
+
diff --git a/MP-MON-PI/IOB-MON-2021.12/testNet.sh b/MP-MON-PI/IOB-MON-2021.12/testNet.sh
new file mode 100644
index 0000000..468b0f0
--- /dev/null
+++ b/MP-MON-PI/IOB-MON-2021.12/testNet.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# verifico se sia rete donati o rete steamware o offline...
+netStatus=`cat /sys/class/net/eth0/operstate`
+iaddr=`ifconfig eth0 | grep "inet " | cut -d 'n' -f 2 | cut -d ' ' -f 2`
+
+if [[ $netStatus != "up" ]]
+then
+ echo "Siamo Offline, pagina demo!"
+elif [[ $iaddr == "10.74.82"* ]]
+then
+ echo "Siamo in Steamware!"
+elif [[ $iaddr == "192.168.51"* ]]
+then
+ echo "Siamo a Passirano!"
+else
+ echo "Siamo altrove, pagina demo!"
+fi
+
+echo "$iaddr"