diff --git a/Dockerfile b/Dockerfile index ee766ef..4ba5c95 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,10 +10,17 @@ RUN apt-get update && apt-get install -y \ apache2 \ iptables \ nodejs \ + python-virtualenv \ python-imaging \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* +# Install pip +# RUN easy_install pip + +# Install Flask +RUN pip install Flask + # Apache site configuration ADD chute/000-default.conf /etc/apache2/sites-available/ @@ -30,6 +37,6 @@ ADD chute/run.sh /usr/local/bin/run.sh # Set the work dir for nodejs photo server WORKDIR "/var/www/html" -EXPOSE 80 81 8010 +EXPOSE 80 81 8010 8011 CMD ["/bin/bash", "/usr/local/bin/run.sh"] diff --git a/chute/hello.py b/chute/hello.py new file mode 100644 index 0000000..5240d45 --- /dev/null +++ b/chute/hello.py @@ -0,0 +1,19 @@ +from flask import Flask +from flask import request +app = Flask(__name__) + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'GET': + return ('get message') + else: + return ("error") + +@app.route('/') +def hello_world(): + return 'Hello, World!' + +app.run(host = '0.0.0.0', port = 5001) + +#if(__name__ == "__main__"): +# print("In Main") diff --git a/chute/run.sh b/chute/run.sh index 43b1a43..1f2b7db 100644 --- a/chute/run.sh +++ b/chute/run.sh @@ -5,7 +5,15 @@ mkdir -p /var/www/html/motionLog chmod a+rw /var/www/html/motionLog # Execute the file, one pic every 2 seconds -python /usr/local/bin/seccam.py -m_sec 2.0 > seccam.log 2> seccam.err & +python /usr/local/bin/seccam.py -m_sec 5.0 > seccam.log 2> seccam.err & +#python /usr/local/bin/seccam.py -m_sec 2.0 > seccam.log & + + +#export FLASK_APP = seccam.py +#flask run > flask.log & + +# Execute the file, one pic every 2 seconds +# python /usr/local/bin/snapshot.py -m_sec 2.0 > snapshot.log 2> snapshot.err & # Add the symlink ln -s --relative /var/www/html/motionLog /var/www/html/app-dist/ diff --git a/chute/seccam.py b/chute/seccam.py index b986109..28771b4 100644 --- a/chute/seccam.py +++ b/chute/seccam.py @@ -4,6 +4,9 @@ import httplib import base64 import StringIO +import thread +from flask import Flask +from flask import request try: import PIL @@ -18,6 +21,63 @@ THRESH_1 = 40.0 THRESH_2 = 60.0 +#''' + +def create_app(ip, m_save): + app = Flask(__name__) + + @app.route('/login', methods=['GET', 'POST']) + def login(): + if request.method == 'GET': + return ('get message') + else: + return ("error") + + @app.route('/') + def hello_world(): + return 'Hello, World!' + + @app.route('/snap') + def takeSnapShot(): + print("In snap shot") + jpg = None + fileName = "" + print(ip, m_save) + while(jpg is None): + try: + print("try to get image") + img = getImage(ip) + # Did we get an image? + if(img is None): + print("** SnapShot Failed, retrying") + time.sleep(2.0) + continue + else: + try: + jpg = PIL.Image.open(img) + fileName = "%s%d.jpg" % (m_save, time.time()) + print('jpg: %s' % str(fileName)) + jpg.save(fileName) + except Exception as e: + time.sleep(2.0) + jpg = None + except KeyboardInterrupt: + break + except Exception as e: + print('!! error: %s' % str(e)) + jpg = None + time.sleep(2.0) + return fileName + + return app + +#''' +def run_app(ip, m_save): + print("\nListen!!!\n") + app = create_app(ip, m_save) + app.run(host = '0.0.0.0', port = 8011) +#''' + def setupArgParse(): p = argparse.ArgumentParser(description='SecCam security suite') p.add_argument('-calibrate', help='Temporary mode to help calibrate the thresholds', action='store_true') @@ -31,9 +91,9 @@ def getImage(ip): # Here is a portion of the URL ####################################################################### # TODO1 : Send a HTTP GET Request to the WebCam - # (with Username:'admin' and Password:''). - # We recommend using the httplib package - h = httplib.HTTP(ip, 80) + # (with Username:'admin' and Password:''). + # We recommend using the httplib package + h = httplib.HTTP(ip, 80) h.putrequest('GET', '/image.jpg') h.putheader('Host', ip) h.putheader('User-agent', 'python-httplib') @@ -91,6 +151,8 @@ def detectMotion(img1, jpg2): if(__name__ == "__main__"): + print("In main\n") + p = setupArgParse() args = p.parse_args() @@ -99,6 +161,8 @@ def detectMotion(img1, jpg2): sens = args.m_sensitivity m_save = '/var/www/html/motionLog/motion-' + print("After global vars\n") + if(m_sec < 1.0): print('** For the workshop, please do not use lower than 1.0 for m_sec') exit() @@ -126,6 +190,7 @@ def detectMotion(img1, jpg2): subnet = "" ip = "" while(ip == ""): + print("Try to connect from router to WebCam") try: # Get the subnet if haven't yet @@ -172,6 +237,15 @@ def detectMotion(img1, jpg2): print("Found IP %s" % ip) + + try: + thread.start_new_thread( run_app, (ip, m_save,) ) + except: + print "Error: unable to start thread" + + #while(True): + # pass + # Setup while loop requesting images from webcam while(True): try: @@ -193,7 +267,7 @@ def detectMotion(img1, jpg2): ####################################################################### # TODO2 : Check the RMS difference and store the image to the proper # location, for our webserver to read these files they should go - # under the location /srv/www/motionlog/* + # under the location /srv/www/motionlog/* if(diff > thresh): print("** Motion! %.3f" % diff) fileName = "%s%d.jpg" % (m_save, time.time()) diff --git a/chute/snapshot.py b/chute/snapshot.py new file mode 100644 index 0000000..0ffb325 --- /dev/null +++ b/chute/snapshot.py @@ -0,0 +1,203 @@ +#!/usr/bin/python + +import sys, math, os, string, time, argparse, json, subprocess +import httplib +import base64 +import StringIO + +try: + import PIL + from PIL import Image, ImageChops +except Exception as e: + print('No PIL, please install "python-imaging-library" if on OpenWrt') + sys.exit(1) + +timeflt = lambda: time.time() + +THRESH_0 = 20.0 +THRESH_1 = 40.0 +THRESH_2 = 60.0 + +def setupArgParse(): + p = argparse.ArgumentParser(description='SecCam security suite') + p.add_argument('-calibrate', help='Temporary mode to help calibrate the thresholds', action='store_true') + p.add_argument('-m_sec', help='How much time to wait between motion images', type=float, default=2.0) + p.add_argument('-m_sensitivity', help='How sensitive the motion capture should be, 0=very, 1=somewhat, 2=not very', type=int, default=0) + return p + +def getImage(ip): + """Gets the file from the specified host, port and location/query""" + try: + # Here is a portion of the URL + ####################################################################### + # TODO1 : Send a HTTP GET Request to the WebCam + # (with Username:'admin' and Password:''). + # We recommend using the httplib package + h = httplib.HTTP(ip, 80) + h.putrequest('GET', '/image.jpg') + h.putheader('Host', ip) + h.putheader('User-agent', 'python-httplib') + h.putheader('Content-type', 'image/jpeg') + h.putheader('Authorization', 'Basic {0}'.format(base64.b64encode("{0}:".format('admin')))) + h.endheaders() + + (returncode, returnmsg, headers) = h.getreply() + print "return code:",returncode + print "return message:",returnmsg + print "headers:",headers + if returncode != 200: + print returncode, returnmsg + sys.exit() + + f = h.getfile() + return StringIO.StringIO(f.read()) + + except Exception as e: + print('!! Failed to connect to webcam: %s' % str(e)) + return None + +def detectMotion(img1, jpg2): + """ + Detects motion using a simple difference algorithm. + Arguments: + img1 : the image data from the getImage() function + jpg2 : the last jpg object (you save outside of this function) + Returns: + None if no img data provided + (None, JPG) if jpg2 is None, we convert img1 into a JPG object and return that + (RMS, JPG) if img difference successful + """ + if(not img1): + return None + + #Convert to Image so we can compare them using PIL + try: + jpg1 = PIL.Image.open(img1) + except Exception as e: + print('jpg1: %s' % str(e)) + return None + + if(not jpg2): + return (None, jpg1) + + # Now compute the difference + diff = PIL.ImageChops.difference(jpg1, jpg2) + h = diff.histogram() + sq = (value*((idx%256)**2) for idx, value in enumerate(h)) + sum_sqs = sum(sq) + rms = math.sqrt(sum_sqs / float(jpg1.size[0] * jpg1.size[1])) + return (rms,jpg1) + +def takeSnapShot(ip, m_save): + jpg = None + while(jpg is None): + try: + img = getImage(ip) + # Did we get an image? + if(img is None): + print("** SnapShot Failed, retrying") + time.sleep(1.0) + continue + else: + try: + jpg = PIL.Image.open(img) + fileName = "%s%d.jpg" % (m_save, time.time()) + print('jpg: %s' % str(fileName)) + jpg.save(fileName) + return jpg; + except Exception as e: + time.sleep(1.0) + jpg = None + except KeyboardInterrupt: + break + except Exception as e: + print('!! error: %s' % str(e)) + jpg = None + time.sleep(1.0) + +if(__name__ == "__main__"): + p = setupArgParse() + args = p.parse_args() + + calib = args.calibrate + m_sec = args.m_sec + sens = args.m_sensitivity + m_save = '/var/www/html/motionLog/motion-' + + if(m_sec < 1.0): + print('** For the workshop, please do not use lower than 1.0 for m_sec') + exit() + + #Setup threshold for motion + #very sensitive + if(sens == 0): + thresh = THRESH_0 + #kind of sensitive + elif(sens == 1): + thresh = THRESH_1 + #not very sensitive + elif(sens == 2): + thresh = THRESH_2 + else: + raise Exception('InvalidParam', 'm_sensitivity') + + # Need to store the old image + oldjpg = None + + ## Determine IP address + ####################################################################### + # make sure apr table contains all devices + # Get the subnet of paradrop + subnet = "" + ip = "" + while(ip == ""): + try: + + # Get the subnet if haven't yet + if (subnet == ""): + cmd = "ifconfig -a | grep 'inet addr:192.168' | awk '{print $2}' | egrep -o '([0-9]+\.){2}[0-9]+'" + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output, errors = p.communicate() + if (output != ""): + subnet = output.rstrip() + + # Add a . after 192.168.xxx + subnet = subnet + '.' + print "subnet: " + subnet + + # Prevent race condition by running this in the loop to put the device on the arp table + cmd = "echo $(seq 100 200) | xargs -P255 -I% -d' ' ping -W 1 -c 1 " + subnet + "% | grep -E '[0-1].*?:'" + p2 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output2, errors2 = p2.communicate() + + # Search arp for leading mac address bits + cmd="arp -a | grep -e '28:10:7b' -e 'b0:c5:54' -e '01:b0:c5' | awk '{print $2}' | egrep -o '([0-9]+\.){3}[0-9]+'" + p3 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output3, errors3 = p3.communicate() + + if (output3 != ""): + print "output3: '" + output3 + "'" + ip = output3.rstrip() + + # Set iptables for wan port access + cmd="iptables -t nat -A PREROUTING -p tcp --dport 81 -j DNAT --to-destination " + ip + ":80" + print "cmd: " + cmd + p4 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output4, errors4 = p4.communicate() + cmd="iptables -t nat -A POSTROUTING -p tcp -d " + ip + " --dport 81 -j MASQUERADE" + print "cmd: " + cmd + p5 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) + output5, errors5 = p5.communicate() + + except KeyboardInterrupt: + break + except Exception as e: + print('!! error: %s' % str(e)) + time.sleep(m_sec) + + print("Found IP %s" % ip) + + # Setup while loop requesting images from webcam + while(True): + jpg = takeSnapShot(ip, m_save) + time.sleep(5.0) diff --git a/chute/web/app-dist/index.html b/chute/web/app-dist/index.html index 563c393..f3bde9d 100644 --- a/chute/web/app-dist/index.html +++ b/chute/web/app-dist/index.html @@ -1,9 +1,53 @@ - SecCam
+ ga('create', 'UA-XXXXX-X'); + ga('send', 'pageview'); + + + diff --git a/chute/web/app-dist/scripts/scripts.27ca6ab5.js b/chute/web/app-dist/scripts/scripts.27ca6ab5.js index 6a390cb..31b0a58 100644 --- a/chute/web/app-dist/scripts/scripts.27ca6ab5.js +++ b/chute/web/app-dist/scripts/scripts.27ca6ab5.js @@ -1 +1,100 @@ -"use strict";angular.module("seccamApp",["ngAnimate","ngAria","ngCookies","ngMessages","ngResource","ngRoute","ngSanitize","ngTouch"]).config(["$routeProvider",function(a){a.when("/",{templateUrl:"views/main.html",controller:"MainCtrl",controllerAs:"main"}).when("/live-stream",{templateUrl:"views/live-stream.html",controller:"LiveStreamCtrl"}).when("/photos",{templateUrl:"views/photos.html",controller:"PhotosCtrl"}).otherwise({redirectTo:"/"})}]).controller("BaseController",["$scope","$location",function(a,b){a.isActive=function(a){return a===b.url()}}]),angular.module("seccamApp").controller("MainCtrl",function(){this.awesomeThings=["HTML5 Boilerplate","AngularJS","Karma"]}),angular.module("seccamApp").controller("LiveStreamCtrl",["$scope",function(a){a.streamStarted=!1;var b="http://admin@" + window.location.hostname + ":81/video.cgi";a.startStream=function(){a.streamStarted||(a.streamStarted=!0,$("#video-stream").attr("src",b))}}]),angular.module("seccamApp").controller("PhotosCtrl",["$scope","$http","$interval",function(a,b,c){a.photos=[];var d="http://" + window.location.hostname + ":8010",e=6e4,f=null,g=function(){b.get(d).then(function(b){a.photos=b.data})};g(),f=c(g,e)}]),angular.module("seccamApp").run(["$templateCache",function(a){a.put("views/live-stream.html",'

Live Stream

Stream is live!

Stream has not started.

Click to start stream
'),a.put("views/main.html",'

SecCam


Security brought to you by
Paradrop


Live Stream

Photos

'),a.put("views/photos.html",'

Photos

Taken at {{ photos[$index + 0].ts | date:\'mediumTime\':\'CST\' }}
A SecCam photo
Taken at {{ photos[$index + 1].ts | date:\'mediumTime\':\'CST\' }}
A SecCam photo
Taken at {{ photos[$index + 2].ts | date:\'mediumTime\':\'CST\' }}
A SecCam photo
Taken at {{ photos[$index + 3].ts | date:\'mediumTime\':\'CST\' }}
A SecCam photo
')}]); +"use strict"; +angular.module("seccamApp", ["ngAnimate", "ngAria", "ngCookies", "ngMessages", "ngResource", "ngRoute", "ngSanitize", "ngTouch"]) + .config(["$routeProvider", function(a) { + a.when("/", { + templateUrl: "views/main.html", + controller: "MainCtrl", + controllerAs: "main" + }) + .when("/live-stream", { + templateUrl: "views/live-stream.html", + controller: "LiveStreamCtrl" + }) + .when("/photos", { + templateUrl: "views/photos.html", + controller: "PhotosCtrl" + }) + .otherwise({ + redirectTo: "/" + }) +}]) + .controller("BaseController", ["$scope", "$location", function(a, b) { + a.isActive = function(a) { + return a === b.url() + } +}]), angular.module("seccamApp") + .controller("MainCtrl", function() { + this.awesomeThings = ["HTML5 Boilerplate", "AngularJS", "Karma"] + }), angular.module("seccamApp") + .controller("LiveStreamCtrl", ["$scope", function(a) { + a.streamStarted = !1; + var b = "http://admin@" + window.location.hostname + ":81/video.cgi"; + a.startStream = function() { + a.streamStarted || (a.streamStarted = !0, $("#video-stream") + .attr("src", b)) + } +}]), angular.module("seccamApp") + .controller("PhotosCtrl", ["$scope", "$http", "$interval", function(a, b, c) { + a.photos = []; + var d = "http://" + window.location.hostname + ":8010", + e = 6e4, + f = null, + g = function() { + b.get(d) + .then(function(b) { + a.photos = b.data + }) + }; + g(), f = c(g, e) +}]), angular.module("seccamApp") + .run(["$templateCache", function(a) { + var live_stream_html = ` +
+

Live Stream

+

Stream is live!

+

Stream has not started.

+ Click to start stream +
+ ` + var main_html = ` +
+

SecCam

+
+

+ Security brought to you by
Paradrop +

+
+

Live Stream

+

Photos

+
+
+ +
+ ` + + var photo_html = ` +
+

Photos

+
+
+
Taken at {{ photos[$index + 0].ts | date:\'mediumTime\':\'CST\' }}
+ A SecCam photo +
+
+
Taken at {{ photos[$index + 1].ts | date:\'mediumTime\':\'CST\' }}
+ A SecCam photo +
+
+
Taken at {{ photos[$index + 2].ts | date:\'mediumTime\':\'CST\' }}
+ A SecCam photo +
+
+
Taken at {{ photos[$index + 3].ts | date:\'mediumTime\':\'CST\' }}
+ A SecCam photo +
+
+
+ ` + a.put("views/live-stream.html", live_stream_html), + a.put("views/main.html", main_html), + a.put("views/photos.html", photo_html)}]); diff --git a/chute/web/app-dist/scripts/vendor.01519822.js b/chute/web/app-dist/scripts/vendor.01519822.js index 94b5219..f0e3d3d 100644 --- a/chute/web/app-dist/scripts/vendor.01519822.js +++ b/chute/web/app-dist/scripts/vendor.01519822.js @@ -1,11 +1,14631 @@ -if(function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){function c(a){var b=!!a&&"length"in a&&a.length,c=fa.type(a);return"function"===c||fa.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}function d(a,b,c){if(fa.isFunction(b))return fa.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return fa.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(pa.test(b))return fa.filter(b,a,c);b=fa.filter(b,a)}return fa.grep(a,function(a){return _.call(b,a)>-1!==c})}function e(a,b){for(;(a=a[b])&&1!==a.nodeType;);return a}function f(a){var b={};return fa.each(a.match(va)||[],function(a,c){b[c]=!0}),b}function g(){X.removeEventListener("DOMContentLoaded",g),a.removeEventListener("load",g),fa.ready()}function h(){this.expando=fa.expando+h.uid++}function i(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Ca,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:Ba.test(c)?fa.parseJSON(c):c}catch(e){}Aa.set(a,b,c)}else c=void 0;return c}function j(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return fa.css(a,b,"")},i=h(),j=c&&c[3]||(fa.cssNumber[b]?"":"px"),k=(fa.cssNumber[b]||"px"!==j&&+i)&&Ea.exec(fa.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,fa.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}function k(a,b){var c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&fa.nodeName(a,b)?fa.merge([a],c):c}function l(a,b){for(var c=0,d=a.length;d>c;c++)za.set(a[c],"globalEval",!b||za.get(b[c],"globalEval"))}function m(a,b,c,d,e){for(var f,g,h,i,j,m,n=b.createDocumentFragment(),o=[],p=0,q=a.length;q>p;p++)if(f=a[p],f||0===f)if("object"===fa.type(f))fa.merge(o,f.nodeType?[f]:f);else if(La.test(f)){for(g=g||n.appendChild(b.createElement("div")),h=(Ia.exec(f)||["",""])[1].toLowerCase(),i=Ka[h]||Ka._default,g.innerHTML=i[1]+fa.htmlPrefilter(f)+i[2],m=i[0];m--;)g=g.lastChild;fa.merge(o,g.childNodes),g=n.firstChild,g.textContent=""}else o.push(b.createTextNode(f));for(n.textContent="",p=0;f=o[p++];)if(d&&fa.inArray(f,d)>-1)e&&e.push(f);else if(j=fa.contains(f.ownerDocument,f),g=k(n.appendChild(f),"script"),j&&l(g),c)for(m=0;f=g[m++];)Ja.test(f.type||"")&&c.push(f);return n}function n(){return!0}function o(){return!1}function p(){try{return X.activeElement}catch(a){}}function q(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)q(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=o;else if(!e)return a;return 1===f&&(g=e,e=function(a){return fa().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=fa.guid++)),a.each(function(){fa.event.add(this,b,e,d,c)})}function r(a,b){return fa.nodeName(a,"table")&&fa.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function s(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function t(a){var b=Sa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function u(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(za.hasData(a)&&(f=za.access(a),g=za.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)fa.event.add(b,e,j[e][c])}Aa.hasData(a)&&(h=Aa.access(a),i=fa.extend({},h),Aa.set(b,i))}}function v(a,b){var c=b.nodeName.toLowerCase();"input"===c&&Ha.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}function w(a,b,c,d){b=Z.apply([],b);var e,f,g,h,i,j,l=0,n=a.length,o=n-1,p=b[0],q=fa.isFunction(p);if(q||n>1&&"string"==typeof p&&!da.checkClone&&Ra.test(p))return a.each(function(e){var f=a.eq(e);q&&(b[0]=p.call(this,e,f.html())),w(f,b,c,d)});if(n&&(e=m(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(g=fa.map(k(e,"script"),s),h=g.length;n>l;l++)i=e,l!==o&&(i=fa.clone(i,!0,!0),h&&fa.merge(g,k(i,"script"))),c.call(a[l],i,l);if(h)for(j=g[g.length-1].ownerDocument,fa.map(g,t),l=0;h>l;l++)i=g[l],Ja.test(i.type||"")&&!za.access(i,"globalEval")&&fa.contains(j,i)&&(i.src?fa._evalUrl&&fa._evalUrl(i.src):fa.globalEval(i.textContent.replace(Ta,"")))}return a}function x(a,b,c){for(var d,e=b?fa.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||fa.cleanData(k(d)),d.parentNode&&(c&&fa.contains(d.ownerDocument,d)&&l(k(d,"script")),d.parentNode.removeChild(d));return a}function y(a,b){var c=fa(b.createElement(a)).appendTo(b.body),d=fa.css(c[0],"display");return c.detach(),d}function z(a){var b=X,c=Va[a];return c||(c=y(a,b),"none"!==c&&c||(Ua=(Ua||fa("