From 244ef243d75145a01d9029589de65be51299b3f3 Mon Sep 17 00:00:00 2001 From: Krzysztof Bielicki Date: Tue, 10 Mar 2015 10:44:06 +0100 Subject: [PATCH 001/170] [#514] Add support for ignoring payload params in multipart/form-data --- libmproxy/console/contentview.py | 24 ++---------------------- libmproxy/flow.py | 2 +- libmproxy/protocol/http.py | 21 ++++++++++++++++++++- libmproxy/utils.py | 27 +++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 24 deletions(-) diff --git a/libmproxy/console/contentview.py b/libmproxy/console/contentview.py index 582723bb1..84e9946d9 100644 --- a/libmproxy/console/contentview.py +++ b/libmproxy/console/contentview.py @@ -210,33 +210,13 @@ class ViewMultipart: prompt = ("multipart", "m") content_types = ["multipart/form-data"] def __call__(self, hdrs, content, limit): - v = hdrs.get_first("content-type") + v = utils.multipartdecode(hdrs, content) if v: - v = utils.parse_content_type(v) - if not v: - return - boundary = v[2].get("boundary") - if not boundary: - return - - rx = re.compile(r'\bname="([^"]+)"') - keys = [] - vals = [] - - for i in content.split("--" + boundary): - parts = i.splitlines() - if len(parts) > 1 and parts[0][0:2] != "--": - match = rx.search(parts[1]) - if match: - keys.append(match.group(1) + ":") - vals.append(netlib.utils.cleanBin( - "\n".join(parts[3+parts[2:].index(""):]) - )) r = [ urwid.Text(("highlight", "Form data:\n")), ] r.extend(common.format_keyvals( - zip(keys, vals), + v, key = "header", val = "text" )) diff --git a/libmproxy/flow.py b/libmproxy/flow.py index 43580109c..0e9e481c8 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -236,7 +236,7 @@ class ServerPlaybackState: ] if not self.ignore_content: - form_contents = r.get_form_urlencoded() + form_contents = r.get_form() if self.ignore_payload_params and form_contents: key.extend( p for p in form_contents diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 49310ec3f..512cf75b1 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -15,6 +15,7 @@ from ..proxy.connection import ServerConnection from .. import encoding, utils, controller, stateobject, proxy HDR_FORM_URLENCODED = "application/x-www-form-urlencoded" +HDR_FORM_MULTIPART = "multipart/form-data" CONTENT_MISSING = 0 @@ -507,6 +508,19 @@ class HTTPRequest(HTTPMessage): """ self.headers["Host"] = [self.host] + def get_form(self): + """ + Retrieves the URL-encoded or multipart form data, returning an ODict object. + Returns an empty ODict if there is no data or the content-type + indicates non-form data. + """ + if self.content: + if self.headers.in_any("content-type", HDR_FORM_URLENCODED, True): + return self.get_form_urlencoded() + elif self.headers.in_any("content-type", HDR_FORM_MULTIPART, True): + return self.get_form_multipart() + return ODict([]) + def get_form_urlencoded(self): """ Retrieves the URL-encoded form data, returning an ODict object. @@ -514,7 +528,12 @@ class HTTPRequest(HTTPMessage): indicates non-form data. """ if self.content and self.headers.in_any("content-type", HDR_FORM_URLENCODED, True): - return ODict(utils.urldecode(self.content)) + return ODict(utils.urldecode(self.content)) + return ODict([]) + + def get_form_multipart(self): + if self.content and self.headers.in_any("content-type", HDR_FORM_MULTIPART, True): + return ODict(utils.multipartdecode(self.headers, self.content)) return ODict([]) def set_form_urlencoded(self, odict): diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 51f2dc26a..b84c589a4 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -69,6 +69,33 @@ def urlencode(s): return urllib.urlencode(s, False) +def multipartdecode(hdrs, content): + """ + Takes a multipart boundary encoded string and returns list of (key, value) tuples. + """ + v = hdrs.get_first("content-type") + if v: + v = parse_content_type(v) + if not v: + return [] + boundary = v[2].get("boundary") + if not boundary: + return [] + + rx = re.compile(r'\bname="([^"]+)"') + r = [] + + for i in content.split("--" + boundary): + parts = i.splitlines() + if len(parts) > 1 and parts[0][0:2] != "--": + match = rx.search(parts[1]) + if match: + key = match.group(1) + value = "".join(parts[3+parts[2:].index(""):]) + r.append((key, value)) + return r + return [] + def pretty_size(size): suffixes = [ ("B", 2**10), From 953f9aa64166451a07502f05c15db47c053e6081 Mon Sep 17 00:00:00 2001 From: Krzysztof Bielicki Date: Mon, 16 Mar 2015 10:23:50 +0100 Subject: [PATCH 002/170] Added tests --- test/test_protocol_http.py | 21 +++++++++++++++++++++ test/test_utils.py | 19 ++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/test/test_protocol_http.py b/test/test_protocol_http.py index 16870777d..23c3f469b 100644 --- a/test/test_protocol_http.py +++ b/test/test_protocol_http.py @@ -1,3 +1,4 @@ +from mock import MagicMock from libmproxy.protocol.http import * from cStringIO import StringIO import tutils, tservers @@ -112,6 +113,26 @@ class TestHTTPRequest: r = tutils.treq() assert repr(r) + def test_get_form_for_urlencoded(self): + r = tutils.treq() + r.headers.add("content-type", "application/x-www-form-urlencoded") + r.get_form_urlencoded = MagicMock() + + r.get_form() + + assert r.get_form_urlencoded.called + + def test_get_form_for_multipart(self): + r = tutils.treq() + r.headers.add("content-type", "multipart/form-data") + r.get_form_multipart = MagicMock() + + r.get_form() + + assert r.get_form_multipart.called + + + class TestHTTPResponse: def test_read_from_stringio(self): diff --git a/test/test_utils.py b/test/test_utils.py index 78d1c0725..a79029108 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1,5 +1,5 @@ import json -from libmproxy import utils +from libmproxy import utils, flow import tutils utils.CERT_SLEEP_TIME = 0 @@ -52,6 +52,23 @@ def test_urldecode(): s = "one=two&three=four" assert len(utils.urldecode(s)) == 2 +def test_multipartdecode(): + boundary = 'somefancyboundary' + headers = flow.ODict([('content-type', ('multipart/form-data; boundary=%s' % boundary))]) + content = "--{0}\n" \ + "Content-Disposition: form-data; name=\"field1\"\n\n" \ + "value1\n" \ + "--{0}\n" \ + "Content-Disposition: form-data; name=\"field2\"\n\n" \ + "value2\n" \ + "--{0}--".format(boundary) + + form = utils.multipartdecode(headers, content) + + assert len(form) == 2 + assert form[0] == ('field1', 'value1') + assert form[1] == ('field2', 'value2') + def test_pretty_duration(): assert utils.pretty_duration(0.00001) == "0ms" assert utils.pretty_duration(0.0001) == "0ms" From 968d94d4710616ebf94cde4f3c35d469e227e910 Mon Sep 17 00:00:00 2001 From: Jim Shaver Date: Tue, 17 Mar 2015 00:26:42 -0400 Subject: [PATCH 003/170] Removes all of the platform specific certificate installation instructions. --- doc-src/_nav.html | 7 --- .../android-settingssecurityinstallca.png | Bin 57723 -> 0 bytes .../android-settingssecuritymenu.png | Bin 75679 -> 0 bytes ...ndroid-settingssecurityuserinstalledca.png | Bin 47263 -> 0 bytes .../android-shellwgetmitmproxyca.png | Bin 22198 -> 0 bytes doc-src/certinstall/android.html | 53 ------------------ doc-src/certinstall/firefox.html | 31 ---------- doc-src/certinstall/index.py | 7 --- doc-src/certinstall/ios-simulator.html | 23 -------- doc-src/certinstall/ios.html | 27 --------- doc-src/certinstall/java.html | 13 ----- doc-src/certinstall/osx.html | 16 ------ doc-src/certinstall/windows7.html | 35 ------------ doc-src/ssl.html | 8 --- doc-src/tutorials/gamecenter.html | 5 +- 15 files changed, 2 insertions(+), 223 deletions(-) delete mode 100644 doc-src/certinstall/android-settingssecurityinstallca.png delete mode 100644 doc-src/certinstall/android-settingssecuritymenu.png delete mode 100644 doc-src/certinstall/android-settingssecurityuserinstalledca.png delete mode 100644 doc-src/certinstall/android-shellwgetmitmproxyca.png delete mode 100644 doc-src/certinstall/android.html delete mode 100644 doc-src/certinstall/firefox.html delete mode 100644 doc-src/certinstall/ios-simulator.html delete mode 100644 doc-src/certinstall/ios.html delete mode 100644 doc-src/certinstall/java.html delete mode 100644 doc-src/certinstall/osx.html delete mode 100644 doc-src/certinstall/windows7.html diff --git a/doc-src/_nav.html b/doc-src/_nav.html index 69175c0ce..91d2118fe 100644 --- a/doc-src/_nav.html +++ b/doc-src/_nav.html @@ -31,13 +31,6 @@ $!nav("ssl.html", this, state)!$ $!nav("certinstall/webapp.html", this, state)!$ - $!nav("certinstall/android.html", this, state)!$ - $!nav("certinstall/firefox.html", this, state)!$ - $!nav("certinstall/ios.html", this, state)!$ - $!nav("certinstall/ios-simulator.html", this, state)!$ - $!nav("certinstall/java.html", this, state)!$ - $!nav("certinstall/osx.html", this, state)!$ - $!nav("certinstall/windows7.html", this, state)!$ $!nav("transparent.html", this, state)!$ diff --git a/doc-src/certinstall/android-settingssecurityinstallca.png b/doc-src/certinstall/android-settingssecurityinstallca.png deleted file mode 100644 index f0f97273ead447d2d480a9754ba0dc878f35a333..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57723 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%0Ahew9hNy&_|qcj@F%yL{tZ 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 diff --git a/doc-src/certinstall/android-settingssecuritymenu.png b/doc-src/certinstall/android-settingssecuritymenu.png deleted file mode 100644 index fea412fecf71df20e0240a89bcd78741200a28bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75679 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 diff --git a/doc-src/certinstall/android-settingssecurityuserinstalledca.png b/doc-src/certinstall/android-settingssecurityuserinstalledca.png deleted file mode 100644 index 1f7717ad45a9a0b06ba186a202cbd60eac41186d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47263 zcmZ_#1yq&Y_XUj7-CY9G5~7C|q`Q%pZV;rqyQRCkK^p0hJamePbV`Sm2zTTA`+wgZ zcZ~atVI2?WdCuN@tu^Odb44gCN@1drp~1kwV9H2~zk`8+JBERQokxKKuRLeow*`No z+DmIY!N8#7KmCG*$;cvsf%&2$BQB!mzI2$4tfl(BtyT=3F8^8?@53J3b68Q7&g&I^ zCT27m4V+|ik^WF>2?UW^W7775KtlAz(MFDmtn}9F^F;3K7Re$|%Un$;nJg(@HDI zDJaOnCa5NIKxP~2IXF0GXJ=JaRTJ~=9UVoDZA@)?oxf>U>esPh{C7ng5Pw!nAG>WO z{2dIXqZ?#oU}T_YgdJI9TYI%{WktIG!m514*!l%4)A0BRTtt9;-FN>XItGRT#(r_} zU8UVI-2mpGfPdGSr1~I(i{e#5TiKNV;+MUfo3!9B;o^Ze!&||7NkwUmTQ_q>U;4k4 zozt`IoKUdY@@HtOWu>GfrQ{?eWF#dKU^f{TiWWLXEzW*0Q#Si=3tz1iLA8pXvp zS!Ac2W}xLPuWRG%uI#=*kXq2TS_2XCdWQl3-=%II2&GFcX0Jj=zx))9@d?Trt=G!q zJ8yUo6>|HX;}qOXjEih~1g{)5qX)$FKW zj1?G0bf%DW>F%ZXbf|B#DT#b`}>Gx3sLav)>^Y z3j7cO6&|I)D(&umJYE0lb#-`leVtpzDxM*lZ{MnGW@e_v$-&W3UmqCU(BK4izoOz7 z`e$8V2`t~S|IYYHAvA4>sC29v^^!0+BrI4eSVCMvTvAF>QX*6$I7}iqBp4wiBxoa8 ztfXgl_B+qa($Ce2m0osgYC29jPF7BW$Y3PoKj`qYXonXmvfhXY+jHfr)(cfeby~Bf zN>t?Jg|qu{?Ck7zhK9m>=&?iOR8-f$e_K4?Sh*(!lgiw6(w`D3%z2(KvPMtM ziHn<$8*gN^#?%`SQXI8g{UcjbgPf9ZpL}g{y={sAO~lF0PTjIEUwpXcS?!{0xxy82ERC670;kBfCC zQVtGhi;Fi>R6a?$xs#i%zb`MDn3+Y|eSCiC=;*K;bS+O!!PFO2R5Uwm4$hWNI=i?W z{cP9N)SO&d@m=lmDOJj)q@bW0!nDRYKlWoPYRU z&v05^8Si6wT3KV?mcp+0f?ni%KS4`7vj&fpdOHBMhxUtdw| z?j*SOtY4^*=ZTq_Jlx#PW}_)nQ?G_Y)tj1{s9%ziW&Hj<+Vb(h#mNai=IQZa#k{nrs9jNNai5$6{r){%uLM;P@?}b;7T|&SbKLa!{2xQ#do^@6??~y9D`WJ zOS$Ym*tz4b<=(ivp%=JcsaIH1Us&=+O3@*5*bQyc32W2=ZNyxP@D2gV%j?`b;rt_{ zvPX-KO-!p^3!RAdi}U_Wi9%+NW(?(9w2T?BlsCii_>78eU%u#edM1yr3y<90-7Sn~ zK3_lB<$*v%^WUkyd*^zxg2`83@3=de>*naH-)$r|yVMj{m|yO4v7^uyAmZ(PKQ)D8 z3J!XCd1aJ&o__uR*Oo|X8Oe`8p64DMoZ#aSkPxQgWXBO?r%_}k;U#d*R@*XpFQCOP zZRXT@^cJ9IYIWCIo~)td=Gm{t*>_K&JWko$QRSzGRceanxZD|wnn^<-Z`#@hI4qzM z>=s6^(y=K8YU`T?o%g0PxU84K^>$fXL&Me8_1k9yWT^lMi$;~D)khymv#aBu=zM6V zkTMK+B_}5*F|i;mGfumoZ3Bi7H8u64!y^s|Bs45cPEJmu0dnI(3$|l;OO^C{YVa_J zC|aR8+i%C+n;Q@KF5ea32f+u}t_RqM6;UNy?|3Ke79VHawBVl6(NQTT95jI&Z+l$I z$@%f0pH6!5-90?p90WEUt5sRdOr^yeJUu=0UL+?c+i>%9a5#B;Q#cZ_y?0*gfqg}y zq@?sR)!NwD@%s2@RTZm;hX<3#{fz_2dpJ1ux94We$r(905534#I4w>Ft&Rip^G&t2 z_Rh{ple@cHTiy@1yHkeN)-1enpFWL)7~dJs97u%xuL38s=@&yJdqZ$JD&PKG6s2MZ z%Q|d+@8kW~=P%rSNY{#hCNZNIIlm5hGs`!zwHG*OZ$m`g1al8|ad8r;<>6;L59FyrBAiHX6oPtE3cla!DUDT$1PCeX_vAtV3!^JjB&b9-xRXEL|j zWC%-4OiWI0^k=&pF#!QDA78b0gQSei$j}fnT2M9<6B8#FSHNds1{I&Lp_o)Ym+_$T zRabx1)FdWR^77)38oZMy`2z0?IxIW3^ywFy z=BS{=MEJ1Hu}z2NpRJSyw%=Y!j0T6`CCB@Cwqop| z$H#3cm#fhzEH^9UD~C(GB8Q~k%dbZ$^u9kO#K%u8Dk{q4vHP{RhjW_{Hnqn1>A$+X zQXbu9px86V%o78@8gzi0(Zh1$midFxoWJ87>cv<5^KgbT2F1bH72C`8bL}sGxp|ow zw=|0pbJv}B#Qf;`&N14Dy4s{O7n$xm9g`e<37ig_H=}K6l}X9T?QLzLp`jC5e2H;! z!UQQEcT7h2Y5&2m6}jZIku&zHt+vIsR;OD*-`;(R{QX%`j*<{FMeOk`qAZQA%(#g7$Kxti&#JZfrcd(PmN zNE5yP!NfdhxSHfQ{vR#&s6!(uyMx193p_!qA_>dn|Dar*nEMXe0pFtbeY$;8_rb;)xM#G8EMe;?bS$xM4K+JowhK-$+K zON`8dmAZ*`s@rO->%Tj(*?L9|%U2tT`NdHjRa28Y^R%rM(O6TME7 zFcO_bD>zLX_LM47&iT)olc$MHJUJH9;*guJP_IzRh|vmCXP;=k85Ln>)O@qPML^h|wI4wi+pd2o8dXuU~R}qStE( zB+}Ws^2<9tk**YrE^Zi9SUR*u1e!)fB|P>)IfSI?E9S;e?CP&~M~0yt&N}~YPTh?* zQ>hWZEv2#f>_=QM4faJI%izl72y#`V$)$ z!Gj(fylF+KXopFGrt$*~$~hW=8t0ZeC&AOp*jvf->*|p)GjttM=py<77&4OaRb|!1 z#pU_s#Szpfko|zo?3AkLy$LESKIO!%tu640q!38`hY!E*?wrv=n6b#7QsCh7GF*&r zflhq!mhdM~ri4C2a3UiK*x25(vFRa*#K~ZgU@1j@Yk)^iBve&R=@8IHQyk97Inv}wJO&tO*$Jh?pgrUj016Zq7XD3`f_wGq!CzTjy_lTD((*$A6dZ+| zvgp@A0n8Ut-=p_DKOlHC#F?6^&Cl6uAc^3prMta1+uA0Cp%K~YVtrk=b&}(Lp>xlc z>HC}fH#z?2_WhRgP^ApFlX=uy(rJnAr(@AU#ax&tZ2pSmd_#_(PU?>vMM9%9fyfG4 zy>aria5C5%btH8p5oI&5(8>T;KmGgv=f#y5;@Be|co1F~+J6VF3^IctBY7#Ukw3-% z>ecY~0SRZ~^ePIhuP7B5V41!0AZTbaF$D<;`T0h^BE6r;dG7xFVb^Qhf^PoW`}JTW z5q~x;)N1F8*MU7u)f>xP7z*}c_)igJh65to2^}7WW@MyeibY3{W$~#-h<@+#`LjKm znwgpD*IZK{85vr_AY42RiYNR1B6Y4f4eko<8#j8Es6zgy+k(bn1hc)34|j72HnxFs$7p<=79Z{y&jDP7Li3moA< zd4@kXH?Pv7;(keA`Wo)%HaO@{rwuDam8e$+I+}TrGNimGpUp*vHzj> zK<)f<*UZAKqOT#Rfu$ySbeYZ}FrPx;1kEP&qJl~Sx4#OuS!cxCFSzVp} z?s2*%!Z3@lbn@#L941Y?=`@nESgb1oikzaNzPkERe+0h8MArVnLA&2$mnD&uiVV}GesdMsVDdw7(6 zbeOeHSlig>@$)U@^=&%j_&A4~8>`z>DW4|nt4Tv^cM)QN(CM#@4d|vvM=e_F!SUX( zq@CDPw6APcMQ`us`aMKLFMt2;d~epnp_nW9?AbE~rr`pKC=j=)FZEo(9upJ0Dk@?P zqm{`Uttb8cb1mk<#`aM;x3Q6v$$O(eqOHx72p#K^8z63NZEa*M3hJfxv*jMUm}mTg zb}Qam;)KG<9@Rl8HU+J%F3y)93=D*Zoz1rKjD-==^JhsVC6#o8dtZe~h>78Aq3^(= z(olJa^w#=QNaGwQ#KmoFZ(AE0zSH1#ySq#mXDh=BiHJ;q{S(3rzxg(o9S6-PFi7mi zn_W7{2`7-=0Z!((#g1b?Dv@-kxN7+MWa{PhwVS=YuMs-FMQDzJ1Z&^1@X(F7;Pk~V z+GCMWO^tw#j+C)Qz6twsu<{=IPv7^5rG+?Zq-yCr1&~rIcN{#t{Nm!=v^3A- zWe;RzZfO~B@0kSp`8E1iHeU;r_cYa;2fqqxV-wzbpRBE&UhJ}G3HmU+eECAiFH(37KIQBB7ec~u|0{ZvEA-FF0p6z=U?)b7 zgV3~e#AKS2le0TJ6M1K6CMMzs>gj8qnK!gzVZ9U|>FE(Z#gH4N(!^EoVP<9fD4c9K zJvnJt0PP8-c=o*(?Sl;W?%`NKV@L?s*4L7Vi5`}s{2Jl4?cYwW}b4c*z0s+?mKH7)uy|%okXd80oC@!_ZE5 zjS>Ur?X3hTn`<-}NDLJ`a z|6bj0Ums^@PR3Hh-HD&%JhtyNzoiTLP4Ddy#vzTE4zjC|YF(b6UtL^WpPnLoI=#mB z_Z|i*4ep;5eu|V96YuE>6$Rf)c2Wlm|xThIhR}LPM8+ zJeEQF1>%IMgA-U&Fgx%FMSKiry}L@kqzLQcac?1KqGMqNz)it5B9*`i%eX7$c}-yv zprD{2d+6)I5Xk#;F9(OHf zHXMn;koaXp`#siNqKMfT8>`^M&E`qhpW_qp`y)G{`_r!}Y&yQayMAOFVZFl;}gAzlOISVRXGm!O#MKllS^kf7Gda=Frbah3Z zg^ya&F{Xv1;?-i}JR3$%tZj0E`52h8o*kg6jCQuoKT%5<_lgM>Gm`uoF1fDB1+EnQ zMljihz{mRq0Rh3kTv#*zD>YB8b*+^pa>c1TWgcXsl}2Z=%-uH%x&78zL(+L0(;edy z)^%!Pg470Mhz~)1CtICVqFhoxpsJvP;S}%g7P;rSQnZ1vVO~(->}Ok?8>^TCI*W}8 zi^!3Y#Q8Zcz-BWu76AUp(TH#GlUf(Wy zxCgOlXgG&;9O}nF4shB9vy*W}k@LLz2i{Kc;1JYh3+xMk!wMZ7R1x^TNl)OZq)a+} ziQ$fSNfeAk#(0P(vO=ExTyC04G6Nw9^URqvp(<-kwV#9K+^&n!RD%AL*7hT z8x-XJL5erdi%Ux)a&oJyLR$@!f=(_j-QFGq&izwU{e68%V}+faPLnwz&z`}%xqY^p zHD{nN{uI0FZ}ek$_;4(}AsFi4i}MXmPR;yB^HCn;?ha#7R&Lb%G>uj&25;%IQa$v` zWw0`-fq~y}V?EwmQ*0tVJ&!fgDI-xcVe$Sp>bR^ixE6muf$(ZE86fRu_VyNNlS<>K zZuUGf1Vg`kvH$z`Z?1l@HR{PbdwY~&swy})*dH)WXlQ5*cktt)v{RiHYJ=adwUcp` zI^A*f0z2c%FzE7jYtd^_7i+eD0qU15lAOLJ{cR|=LzNl+Yegdd?piN)k5ERYj-=#- zi_7nx_~I&?3i$;;rIBXAAj_8-IX7Lu(8}+UH{%r z`sKVXEUK;DTW-Awh6)?6_sPC}TbPm2=5>8+VY)>^k|r)S^f>u=?*gJRk5}kVxWKTR zvoq2Wc(UlfuYN^+uJdv1jB4i>qNAJp{ymwu0p6UNz!M!olnFZlmaO0S`_j^zfcjJS zV@k>#<%BO4p_A8v60h(^%(`m{m6V=4C}7wSL?R*}1VVdu`i-~HZ>LaRD*zk;zXWT= z1n)y#vl+nV*lG))k}?kyQ@AoI4sIDbYJt$2y{)bH9^IC^J4%jz|K`C76^ai|t_Xev z`XOAAksBNw9E1M&6Nr6c0?ZfnEPiYh6pM(6s;MulN5;onnq8@Fvtm9eRF#!6Gcj%0 zF9ZF`+Xr4m84bNOg3&}C5iU0bodv?-)T81qpromZEsY}yhbm}*@@er$`&gDX8F6Y+ zsRacNj^pN_0#&Ymgi?mbz^rfY^L~pctpxtGejb*H3V;0Y6H!Mb6Y68b`sQZjX$MDR z9WAXW^u_Rjff!4Jj>wBy@(ghoBm9J`UX{G)Ei8sb&bk!$J*+MGT0-OL@9CR+!=XHp z!yfNb(LZLS*8vO}j!Ic4$0t}#^D7phfa+>^l@Ln=C{Fu}6=Hs4!Ywhz{FhjcPuvP4 z5MY&=R#Je}a0uMZAi2v73apV%tl^bGn3xLmQHIP)m1&|_XS(UAN*T9jFCfluXzA#T z-Q9}{P0-^X(fz)xwT5+doI3Qddt+c6%qxX^tgGrU>^wTp3at*K9|)?hnZ?$43@}q{ zJz=n?v+422AKuJt`{U9abo)G4C_cEmH~5K0ltWDGX#%O)#QhZr7 zH3)c?+A)b)17;dAS4dpx(_wAA9A>>2i-_$x>AbY5h zo?W~z8o-gB*?0{gM4P84P-aoi83NdI0`l`yQiz_YWf|n83d$q{AIWJ($mN2m&gFvO zk*I71U7O0t$b)43k8PXKcxYv)QL{1A!m*1;tPGlUqix9jBi2t*CW7-qTrns5NhAN? zVggAd51I$4|NpVqrxpJ9Vh8QlXgC?k6uJlPLt<*$y9gT(L`clg|K2#(?k<+t+FG2d zy!YbNlhj)&Af*{AJz5MB`1Iir8FfjOc$!Z@lO!V}i;ewxvn%v?`Slz5gk>Xi)*W<&VA^eSl&)pBB1`p>q zr4AeYGRn=wEroQRK=?&|O*4aX4i@F#6Ek1LR7T@Tki{oz*1Fl>|5<$$oPH0~dC$|e zUJJFI;b~f$WDgmBSpw$FuleL8%yERpm({`#%3C8qikNw)`dFxj6!Q#-ET2cHN+6Mu z^7!~0$goA*!fZd8FIu|)9%b5f-3|#ooPEU>a&~t1L_=7|#jSHVlZvJM^R4?qBFprR z??(Tqnxux}%5vX%qLLsRJ9}z;Jbgxp{B&_Y9jU0T;n~Q*0Hj`=zhKs}-jNOu_1vLI zD*5)46ed5v6js>Ky8Y8>crC!l$W0-vYzEk~_w`RV&Chx|Ew(=1-U3@?<<_R=W-nCA zZf_Cuc+Je50BWElCG|*$`e&P3?0TP%FiOQfQ~frTl$hvd5TVFkb1{sO7B;htxmh+FLKF=b6-^!ZQb8qu&a`uCcO2!PDxG0#>PhP?3AH;)4p8XGrhDvv z$EF4xQjd!U$m7kBP)G2JO-yBVw%&XKJvp}xLS}q?;dH!kpNqWr3EHHVy(8am z55G6GdEQlORKM?R!&NgMfU5iaXc6n{n>n9V652jr_VjF4SJM!UiT!*cMdfR1HS)%O zttW#^Vaiujv;aAm9a}V5Oz{6s|JdiY!)v=dNbmFKq@?N3va`Vk6EJ_`-KV8xA;!VE z87a-p67cvH!Yq~$pRJ;MKP^SYrlaAsHKK(LvV0GRaGCGKmGthL1Tqcli*L7&%}~XI@nWq-X=3&9JQK##w7J^u6ILXwq&mRhCim+UEhPzg{4boE&Ah+O~astfH#-qsfIO zJgO$=AqW{;B($yF3%WZILLtSti!F2?H|i7>@rmO#7Y9cR2`Q}2z)ykLhrY428Z8nzDQ+ZN68S{sG#0_gRrpcDGL=9^w?B_x?SD_$3MNWo(Wb}RIE(5ZbRoQLD?RPr8?RFULu}vyZ`Hr$FI3a zLKXmeK|lTK-Zg$CSU_8)3bORSyj9rG`I(k36=^yxup`n%@?Vk10{JvvsH+_ofRs(47pX z0;{s_`z4ff=RbY=`0-<$zj_=kEn~O!^)V?&WCVpJl5AgPbQJ|F-flzDC8oIVb5mtf zHk6MpYNT7Au$f(5CxEC)!Q?61l>pM9%nbh^*zbuPy=JfLoL-+l zu7}GnWHFA(vq<8)O~U+yVQy1>C=J4K%5n>HJ0}3pF zWB;_Wr(~Z8U9%4X)#tyz|0@(A-5LVmQj_{se-)!_m=aOG7QAH6nL(G zKl$`y0H;Xy3^hHsqeMiM0BPm`$I8_7gP|eZ=fOeqQ?zu9P(C`t8~vD zNO>5ER;PBA<#&~Oos4rEV>GDTyertaI^z3YDqcfH_ z{`>db7G~Ro1oA%{%UwWptgJlT2yd+#m?b62%PT~zawnjP!AQ@{sGupNS5yU3+mYOu zEX*uS&kSm(uimY?%E}IcuqI*!T=9*bo}Sm=yWdk&!(YQdoz>OZiWbfQBcD9_!i$Q@ALT*iW3ofO zef)99ZAawOpVt9+7!Xz$mfBjYt4$0IcSjP%ezaiAXTM=%Wv%G;8+!PQ42n(wdvta- zexg-?pYcgMRJjKa2f+gsFc%=pfh`6^3u^~fe`c=n<(oH@jtiex-Piky!8-Hu)}o`A z0&NtzpPq?HUTO&FhKF^O{H}+A&RSY@6=Pef=?e?o zY;1ogCSD3NU1svT^`4&EOAV!L4k`6W3E8cPQevx>TtkzsPd}29EW(~(=a`88gJf#y zLKOBf_xCSoX?HCqSUWu~7B2T2JQM|s6i$i=v791vZ^1Y#@&VeoWv`uwjsv(kSy zJvdlbP*Bn0#^3RVx0a37#;6L;0ch7Dj}70dw9y~qC(~Y|uWY5IAt)0$IUVHX)iyU{ zk&FQJx4D^^%2xUN>dK(LXlZ`Fu*NndER0zHia#BOwywpkyu6&8WU_>w^8^I)h|edW&>*|H3iVHL0qjq(wJaL)guAOCZ{9DxDT8$X#j!H% z;pF7ZpH1&4g?*C^`_kB)f$S@F;uqx1FOno0xSET5`=qdd_|o7zt`R~H4#<`6U=QDR z1nuvq_7mtwv|kUbqLtjtTHqNVjj;VyUh}yj>%dITPfN>)P!DBhL;fXG3_&xcC)M_# zN5e!md}>mGnyp6q0)EAr(ZbbJvLv*G`$;+s`Uj<>=SZTfvI4UN(!~=#T3P*l_;d0W zQJ*d$x=KJ>U&H|qyDrZf&9wMi0(Sw_j&iAZ{}1Q~f}eb9UU8c3BdQIg0iDiB%+9QScC*^J&uFR(aJF_;hBn|_lgdYb=sJf4vy5Ea%D%~S?4u8p)xylAL5dq)>e{2KN=~k>Twhk!G)rq zU(-r2C#Cf0!q3|2|1y#)KJ4Ekog_k)nO=>_j0U`KQnFPsm&7!#|M z1_4Uv#X0)c)<_&jsrNB}5zqnkk{zP%0rNcU9&7c080{a6IlK;i>Ejy8_Y#>%98ONV z*x0f6j(=c(;}VvS};za`kmPKI)txhhbSA{E`uL@sOYoDaBb5xr9Z- z8H6W)m!@1&Us3U42o&L1C69;r*)Ei$V+zp^k0 zY!M8j6SI*~Qu6sd1O~*vmXUN_>9_^%uasm>7-Z_?uE)U%wS*=mBQs|6@~Rx}$ZcMpOH2IREluCp4f6BLtCe{CKVAL) zU2G94+t=P$RsaX(tg;RMSZ@6RclW1oXk>{(7!tY0=g^1Ikwm>kVB%buVAHvQ`y5_Y z28fhiyDJ+De~ZU#$&-KVaC~me*j2lge-)oBpyee$53ziW?*Q7OhzFts_Yk4yN~7!1 zVLjjTd?UwmwEtW7`*miq;&N$PSy|4ufOTXlio5kNs&KwELKckxtsei1ssdNw=c2jz z?DyANV%u0bcvr{2PFF$iVs1*=_}%$Bt<<~O85xKp1=jWX-rmmmkzki^0ZW85WP#f? z55k(#RDef_CZDO_VR4cNr|s}H^b;|=J~M092b-~AZ;*kO)TmV{D6)-ia`~KyY=Cm5 zwnpFKbX}9&gn5Y>4T~|DW&{`c%E^2ri_d8?i|^nC4lvJI0Iwf+bF*&FA0VWuMwKKd zO;D1PH<)T`ew!0rFDlxKnP3C`ruTJ@^HtjP*C(sUGWB&$-EJq8YOi@L1_l^mHhF9> zFE4wJgCqj4}+Sta!WZv^yy!G1S=75){y@|FtII%hoQjZoBJS0h;=jme|_5 z28*!LNv4;qS&rZ&#l_VIQF+%|e|zcWH53^5;`(@X5<0OkUzp3sk(HiaTwRE)z{SNS zAvL7?#oobT9*<;SDOa$eu9ffg>;2>GcHq4Wc2kn=*2919tN4yw9m#_{C^8Ct5(uHI zXj=-t2T4gxB_-y7=D)6yL3~#UA;^fS@s&H+0lS@0o3f+8Mwh^LmZ~Af)vm?^X43oLRcpC~1 zA;u>X(1g`%{gC|G04DVSX&_@kv?>VhVuy{_{*?MK1WtQ@?0dtS7$8r8d)A_1psFFg zf!E=4`A}xL#JNY_IOgP(ny48JHwDyiTrn||+WpDy8)F64*{XzhahZdITv9Ob2XwQ2e=^xquNBD><`q}%g8F;-W`12W!KVbbwA5}xGWtm+xtz zL&#UtG0mbWJZ#8gbg;iqng^-fj8UAZbp?T#t4;MKF-P*i4R0C2!-<>uQ^({ zxmrZxP_+u7@|4NXVX*zreuuha?SO-S0L~sfT;LtD>ys2iG(KCUDqe1Om7X-Q9e4_pJI3lp%=uhe?Vye{94f7a?v z!PUar2c|840b7T|oIv;@j>B!GLo5tS%m@*J2qh;Y6&rQE!iuXg=;|o7Ajdepx{3jX z0+i36%L_=N3|+(Sv^I@xZ9oUtpZ3{`OaiGuUE?KEGVD+wGf_$vz*rgSIu#XG!hbj{ z#^I7%9mI+t)LO@s_jPAyd3iWYsGeuHySbnBTDm^$&w!%k;D8Fu0uf5mbZSTyd;8=# z*EGHS_(VilZ%~#vU4Au=ja9`8J-F}Jo1HeZR+QP>JAbgU(wm22rbX8YXhER^ElhtT zKE8(h?*nov&aSrWtsc=pxIY$Av_3F@B4pJ;k+`!p&RkwY&r(+oP-u+*C=78SD=4r6 zaVQze#H<1uE9?f8$-2Mfq%m*_laqr#cG$lg>X{-5-OXCoB?-Fq1}Ie8_?@HKz{Xpz zD-u!;b@h3kj~{+6{HQFb@V&d-kAx1qlI9>`2>NryR#{{IN@2)uIXp5Zq`KYF<0%OQ zP^&S}Kz>bRx3gN4TM#RLTd4L{>K%w829`c&=gS_&H!U`G&CNe%nh3r7?zfZw{PwB-%3Mjk%Pvg9OmLMJ+O_wqs>rm!S^-LkcF42#9X=}e}EgmDO@ z6-C9D8`|l`dU`tJY^*}}d$f=K!h3`HVqrUl(2ke#PO71#fzq$0c^W?-+Q0p+IT8OE zSG@o1(ebz~n3?0dnxu0A6VnZVLA%$hevi42x48-YbrB7UKqHu2nD$x^d;U3(Bsb3e zeCq{Cg4s5KG~M@^neTvEjgO6adHn(U1DRv zU($3iH_z2#cOvBX0GG6XxC~c;OHS-}vhtU7fI|e5k;xN~n#J!{W8^}cEE|-P$@4KG zJ|4EU)%EC287e1=0--`C79X%%z=c4^$NvDi)$ww#&SWU&WU2GV;NVLJ?&H3JC=emR zdN}T=w>kQTUPDS*{*hBg8wmI)k;;1<0s_E_F*2IUo|-g)6jWaE9xf9J7xnY>;+mn@X-N47|O#+U2MqDw=|}j+CZm>`QF~i9B)=5f4Ij z7i1|59ye@~>WC5&;cJ>Z!EKY>y=4Yl6 zzXy(s2s&fyKQ~ZXg(*Vz#NeBvBC-5LB9E`ifzRPo5|LifhUA>q`|51Xi;RrJ(9aMT z&ECTn#KN04&#AWsm9>2C$O4G^)J*;Igf_#23o!>fHHD?ve9Cy9aO0xrZFkPZ+{k3# zW=n%GdYJ*%UVNh#5bN)5NxAja_PzEG3O-MQ<#0OMDCUbOCHgciM&ciujo&9%gQ;nV znwPdTds_O8tXlqVU?JeD%$xCB7nk3B(^4_>t$;w8-(g}DLmbb~BW3H)(Fmi6AGd)d z|5cTmMJZImqkf~3g?TzD*C6W#CN0AHdDs^Yg#^@~mc3r?4U0yBSqK=PDPem2BAxyP z6&joAFJZZh=#s1PoSV@qcQ{GyIpwI_sr)L#OGTR_8Np9irrk+?hrjxLQk^mMpZ~pI zpyxXcon(FSy}{xH)QpL2{@t}L)`w3BgjP~TkT+|2Z>T@`?V&Q@o8aTan;_ic(lYSY zp#Gc+whg9MdS!UOp8EG4Q;E58vWI7!-}Q5az+Op69vK;VyT|D~CucbnnrIFzN;fl^ zI`su6#wME^Y+9^+UjH14MTh1#YUwS48F;bn5_RtUg@Pf>rNT%IpN5`jULZ3qA#-6Q z_3)^&TEU0?y$=U_71ox8Pc}-*GK~4TG2IAJ)dFU@(Ezglvp5!Mn^{6Do>VjX>A%)b zaI(XISu8)?w?YZ{7yg5nPapi$;sc$C|MmHvCK{N7{@)j$S~mY~kH}nD@N|Fw?hj9` zsuliZ+((93pd5;r%>hA%6f`!(08icOR3qKzRR&KsOs7JM^mTbF_I^b7Kf|T31zqf| zmwEiKhj}&KF5!GG`&AztO2t@vL}q4bXD2#E1j=b%G*JD<_&-&&mDEt`t@cQ(>S#t( zR8>{fR9AkM;-Pb#<7{;PjcJIB*I$@w1+8!vGkNO+kEVb~^juX;ZfGhE^+>t`zY9)1 z57C(ASH==d{KCw1P#0AtWbFf3N+$LCe)$SrTWQZMH_JfqQ$3 zW<>#mV>(lY5hBWkUx|@i!U{xhEA{m7@UoQ^!5cR|!RPsQUb!r($d3tc_}VS44*b8+ z(b2oPe4L-2H&9bS)$gmX=kqwH)I6OqJ9K*#Fo)FEwhf#_z#yn3 z(hH_;8Xq2>ji!FCuXFH+Q&%4a1{f#D^OKcMes1oR_;`54ii(sPtva+wdWI6kOpOkU z$rX+o=hxPj0l9Qlh{Wc_%a;zf=gArxSMIXt|2)C^N@jhuG=Kge1Ii;OXVKE) zw#d(W^rO4Gt*yjHv9%SEg`1mljDdrrve<>A1BBrG{CrRz@I#6&r5VjMe9X+`&lOJq zcBOqP62pu%ObiSl-M+F=^pG@PC`lnwP6ygR{z64)=*^8d!1GFz&1-SWPX@e}ko_wj0cxxvgzcq%2d|fFYicSmt?mOe?x}l@T9D#mnF(vy;+>*^df#3!qDT6$IH=A5|!9QyXn z4q!G21lT826)i5WZ0$b0$FBTfol3=PuPi2(I=bz5_1yv%_IWMQoaz3|2ksw7y+Ozm z69P;N%gc^?Q}I9(JUb)b+0j5k8UqtyflXx<9}p2kd@iS@l&1$m&>b&M*Tb~6TbGtD zp-_4tXRKd@e5=u$92*N^=0$o+Tt8Gv)m_TP;zgsPBae@cRA;9Om@5;K%XU&U0G=Um zM;&Knb@`2%pgPmm)&`(jRn_4{j3RN2wU<{I`VTHT*8AajTI!e9->O;Ib1lq!;oP(v z%ldkz+ySA+ikZ+C&29Ml6^s|wHMmhwECYXJQCo>Qh!pPTt2_v4x^|vO!G*%FjG3FR z=iPAh%nDMP*zQtlJ9ocd%gO1`($0dY+ul}~p6AkSFh8o%^U8w(-k}eFt^z;{0*nyg zGZ&UxnA)8C^s57XhfyW+CDwa z0-_?16$BSA7&;@%o)B<9#ks+W-9>%7es%*^N2j^!>U>*8M~6|MJ(xOC%B+kNK=gmj z2O5x!5}adRLVX`#Su|=AmfglVxmK4KnvH11og6{FbvONczMaRbzaq$@Sq(8xBT!67 ztIXi}D61$_Jf&9k@kp~u7nKyWLxY+Og_Mae5#Q(V+dTw^po7x7JD!OhWym(q)ui&e zZhoGtI+F)<1Yzf-Vr@}=3>Z4?kAKo6^8q!l41)kZ zdH?VbE(kW6&;1l$8gvs*ezu<+9bq%WuQYhyGIM8MgNE$TP-#!RHE=fqZP3IRufGAZ z0M1UQ*Y(Ghr({nKI8NmBlZ(Qy+2IP7j!?j86sf{&| z&@?r_1wg&;<n7sowhBje(KIpdeZr8snD+T^P*ppOBG4W1^!mFfn_XEs@b;WAsNx zGyB%R7yzw>g+)nfh?#?teKaYHP&YN@#vjG8V!FC#K5O_O&%#m( z&US95j-jPxpp@Ug-uTn}36D=Ba2&-($(h#K`04$=x!LOPSF2-QpQieMZuXI)HazV9 zq3xG4F?;;~a-+Yjs*(2h)3=?=Zv}9-KCSl>FMj6(zO~EC{gXqxR}p@aFuBTMKz*-* zFjxFK5ri^-X!CSN`r1z-vcd}TBmn4oZ~wYEX@rh6+B;oDhlhK3l49xyL{Sf);c$-VC9KuJ-o0Ref*##rkA)gg$& zm{8@N61%DRW*`{#Nx=3MdDgO zvaKpCeSBGlVHu{pmzt`n^$x<%#YGDy0Xw`YV|Pck&w(%Q{%;TaP&<1{ri+$p#dmVkdqU_$qCob z#KFP%;>GxnAFIQ|oNwR$n4f>;=(b250l7YFb$7E;H zU~jEQzrma>P1eO_Jn4mmm6f(m%TYIgpt{^%qaz=fFQ(%fng!u$(FMsm?GpXcD zl`JDSn)SAwB8Ce9Bpej)8*d|@zma8SU%=PT6aIMQsHBujFP9P$B5~$^9~wF@Um~He zZ=}DHgow@z#=?MA@!*@?Hhp@qe6z`^3uoB6r9Kp2pm0#}og z#z4WM^=(FtJ^3%77itIw<4MvvnN4hLkYW;YaxjN7NIA@bU}Dc}3x>NdFVF#fM_#Ai zv5AZ{M+teDn5bzmPZk|XOAFrH<5eb&%PE$#7PbWA9X(-(hgo^D-rna=?*7-xg0ElG z)6)ly{$^rf0RyRMSXc%vw(tal4RZh8IyA4mEIzpmEs}t~0^(5E8k!PQ(Z+x^IJ~7y zx`9P&925M7-)aL>L7d@IxgNTBGxAf$`Hjih2K^f6#-E%qRF(u?S=QG4h>=D*-(#4C zz&+4$k55U7ut@#4v^$?LxH;98iFn)|=B#Gdsi1R>7^+Tk$c(9jTne7fVieKwGKG-t z_x^D3VtiQ!p0s!bPHx0>jHT(BI-Bv&KmsTdHRCKMlZb>!kFE6f+I9cEY6m{>1D;jj z0mlZ@%_QVh-5wVyHC_4j6`_qMwC6FZ$gN`H8Ytmj6Dx*tP!&fi!gA?qq_#5CAc>CMElm<9XwBnZrw=0$3{m8gZOO`ILteTmy zo>*md_1~vQeh8!Ly4gS{=SOC`swe6(X>`6cCz#x7y(ouP_$dp4>e=M-+enq2MOam3 z6TL%&tE#4^ys5s~Mpi+wXuYCZ+lfNg?0MvFfbU7jgZFOx41;8@jRY9m< zvS@HUtqQEj^GE`+e1_1$v9+i9a3Sojp7e3p{|{Af9adHMMGK>ZilEX`BGQMF?vU>8 z6ybohbc2%8-6h@Kjnds+(k0#ft)uVn-uwOI;{ylSd+oL79COSu$5M1se$I@gT0FiIrf7>2n?Onk7$&6SY~5OdVdT`$J|#&9(1V;wu2bJw7p!7^lw9NydU&*fBnjUfqZDv~P2; zuXhl1z#6LEIojG$&ZkCtpnLUaAdmu<;e+9@@Lz@j%s>gZ!qF6&HDB)(D5DmT=|7wp z*;}7H|M-GF5FU1Si;W*yUC!_0qSrvWk#f>*F-{3Jwt#wP>!NUUq-%I2dcPFV2+%7U# z{Sl*2UJ@bsc}r6zoP!pY=hiT4&KDNi=&+3j|sJl~Pg@mk$>qT;-`=nTdmNYqdmV-yiB zp;0eak`z5y>ro62mi{OVlpgk*E-Uk(mk%46?C0X7&Jbmzp-fuY_~{X!x3x0{aNQJN z>8j7vPfGddJ9sZ&Q4y4&*LJ`z!q%>bI;_FPnU&QN%=ZZ zgoIT#Up)H(53xs>ETGG$`v51$06i)U@{jKT<2fJtCX1HfngRksz{fE8$o*LLH>ARQ zGc%FB7q!@47AJDi9MAJ4Oct9i%x4!B@bU7#;6%JrSJ57;s+t=}_SoFlc7rE*|N0d< zc&UgSP+$GKaR4zbt8iBs(N^#<9h0}1!{GHF9F{zEN(A4PZjs(4RFu;P3j_nSb zkYU8Q9EkqCT8*~i(t^+P33!}oSa{%FSAY_8&@AMg@JyUueQx?Oc!*$L6{&-`*fy`I zV5v+$=Xsai+I-#4Ea&IRxh_@4MD*0S@rf!sM@Ivb5!+YE-w3%1Oih419}&rKX9Ts? z?1x)K;cY}#A3xMnu#G>FxynwMFechhM8~R*;dn3~aU_19Sb;#7d=)l;A2@Z{G-C$k55P zcF}*eFmMF~dpXDYPYfl)&s)s7D2Z*LC@AJyQj`=eDavSz-t7FCp#6qWyEYfy`}0`PJ$((>%9_g3bKhpn|Hkiu~e! zV{2rI^^=W@i2&+zx1cfE0;< z%YJ^KEiyYDFkbtUMVc;8p3rMIqkO`|BtRa>H~#F!N62B#Ov?j^yNl_gRU+3f-JVcI zZN=xbsoYM;G@@&2kR7?8y&a^$j{>40Z@8?E*WxSMWax^+Ub14NV*~1D9cZyUyP~3E zK7=rg{Q=zE5A|b%0ERY9RtV=$Qpw_6Eg)qncpU$j%YAt?YdPHJ?vCrn`{@)Vk9JE! zi1Zn1K~PaqWMm{YnAJyk^5k4o0Y+X**7Sx&e-`h_^X_f^NQ8y)ME@ZwPxuFN*w|c+ zw(8JtAN{(31oDO9>EUUi^4zSVA!ddrEF&XXE>1VI(;NcA3HeB3{?t>+n}dGdl%m25 z5m1uTqcOJk+4;G7xh9@@hx0tdS`bV)uH-CbK}~7vLHuJA&AK9-x2QJ-LWx-P-zxAgQaXtI3=9 zH|H>!uRn(^oXYk{@ORc|WfnpLZSJPVD%;ax{Y-i2Z@J@B(Qu&t6>4n4kjiEB;C^4} zCo1x=PVX_p#eTUBI$W-AAE7|Vb4}f8y+YhLL@(e8X-?LRpl`0yO#bp5 zF5tr>C`)iECY+xf2H&XaU6-N1-!1yH^bc4g!rbZcaYmd-cK*STv5k?ywhT!V;cYnu4MM$tQV*8Ji&Q>|#=9lLe|5a8W z#P@=Ml!APqB1*{2P9vMhH4P{ZBikSQCNJurkD@`c$92XSr96Sv;Xo!mN$C3I8-4T} zScp8x>Ja`++YF&mNtqRXJK4=et7~&?tq#WRKx*Hd)Ng(REdVB z=sS^E%s<`VZBXx4+F#22|6$P&s(L?v-UhrqNjJX8DYGy<35-LBjU~Hd|AijZqORiE|8{XQMi$Y|43H1t_=wO;PAj|0U~B8VZ8y zvsr;k4gNmmYzxWx+E)56Lk}OFHljqMt^$-x5R)A+6#~klP z8D7KmX`oCBPw08wI?|5?QsSRbeLz05@UY+9 z&_jOpu+I}dRYleyj)K$7o4Uzsv(bNR_(FBaHHpax4i1uW0U7ISjqAfPmlbRLLhP`f z&tmgwgN$^)-m&cSZM*oADO3N=7N2{r{<*^L>gwj))Y9)@#~=kL8aD5I(twuZ6L)cVtW*7IebMcvOZNNz>K^cC;InW&Eim&%@$FbXnDhAfWo!7t z8JC9wd5vrc@`7piB;v7%VQ2Qn{u?&~*&U_1He!aHi=?E2iM-^80 zvlQ+H=6({?*{moUYvl`>a&11%_{+LN=R^U^`{ei%Sk2p6_YOIm**0o-#7Km(d09nx*_GY~*%6j&g9pwO?zQ znhT?k=#IvdxL_Uaebn;`F}xd-2Q>&KNP0Vr0+U)9k3`W1QdnJ@pO+V`UHiS)=2C!8 zSM1p_l0H+6K-Tghf>NM$H%BfvBHDM-p>w~%2zjcB7(+8UjMPC1EQvHVk)KpgW#6(g z7)h=}zNtz0MG2=0l#M41WXWMhq7mi^kVSP@E@n3%KxhY_ig!y@98NEG z?|puxZaP5pA4flevt^1NiNvpJ&PPEV&87({XfQI-nEg$xmuI|f@P5hlMA~m4DD_nn zuy|OfR?Vj^$~_F6P}g#oAIb8MBzMR~F>e1Zj}}XZ1^mdVLXh#dB}2#7Q^jcS^jY?QW7SJ}psDiTG{eUkEb5`gf*i0wkhm%LB4kcNtu?43xc zNh{j1 zNhBzMrrtKMvd|R(_i?$yAH(UA9plT2IkJ(Y#&;;5u+{lmoXIFczH$BiTX>!V)N1oQ zS(fjP`3wKy*)Ci2-36aNmqQnwme4c2OBehEUR98wf(Ed*lni@ant~{EYSR2A^e5&= z(RqyXXMZKkf1FIJ%akzR+q=7df{MponYLVRM3f2>#LA|a=oyadQfw zraV`bNhgSSy5I;B>YLHo$&HmA1_tNjXzE~iuO~dNmtU6CJ06Fhf`9=4;r-sh5|<6D z6Hq|Gdp==dWwpLaPt$8lOwi2jjWQmiF35Mixn|R8!oy|h?CEH#t0Q~+`J;}GyX&pW zwR-r=;DGNtGjnRPEl0Y@*BAYh`6#M6j3)jKgi!M!A5_TnvzD=m7hK<9j z(Zo1u-&|);;Qp7@3aeYCnPP$_Xb-5TkM%wc3?1dS{f=RdVzPR|4kgP-HQM%U2P+}xk> zE1p^$acXT1yS_%+*}1L_&WRk9^ONqMo~%A65fK5?S~)#Eo0KQ}O)i)o%jslFWbS>F zkKmukU*ULQ!a?BS;N;?UQSesvacHz^crE_aKGSu-g8FsM*E;o03^1|LFAe_8o9b&u z!5iV={$OR*Q~PYB<<3pkI&i6JjESAJvZyF{0Il(Ccd2Bl^k{rLv+m?mUvFQ$LzEbc z0W#JzA=gHg=e>Q@tmd<3of|63sfS5T0Z(BSetw>T#K04x4gGUY>U8m!sYZ)BJ*hyxZ2WpKh+V+&7n%x((zJ z-C)~?`Dk_b%+wt4n`m%qpZypnK0`${EB-hzduB95u4n+!?_5E7gMR+|r`O?O_)lW5 zn

voV)0@RzekK|vZ2~l9CG>lrW{X3><{S{=HlEmcAsk00Q(X4(UPCsPX z-{Q$>b?bK8dvYuP3UF}7$%nm44!N@-`V~o;WQYF}sy}6dCy}bcP+7~QO7n9!yLo6{ zb^5XBdaS5BGK%i5?`_5ru0e4L{oR)Kwx}I4%W@D!ZiIP7%lK;!&wSw4PpAF}1a;N! z?}I#dO9{T zG>(m{?-{mh;@X@BJ~c7Ao`IhvUTBs6&OD{MD1dNyu!C4g^Bxz7(>8J!1h!Q(Ie9CL z1TPJ!c48|BEv73H&XLXj3XPlM3d&*+zL79S^n^p?s}d2lYxqkoiS(*Lyc0ny^CvtF z&QIIKA1*z$bp9|vINER-pOEKMb#;lq+~6lmS7K#@AcR!TbtabC|DC0BcDn@5)eP!t zfXpbvJjo1X8uPs!6EI0vc!kcoRE#xDQ7)VUEM2!9MK9QMC*Sv(hCTR)9@c!RS|mJQ zQ0t{H`Vg2%QlahW0G0-Cw0iNZY`fE|Zkl5`(Rw(u#fOVTlOTFOWSTRvsz|dgnOb?{ zOf}h}Jzf`V3IiT9V_`i>tuFok+wm9S{5L(1g^fj|a zQ=rbnC;8!0E49cBfiIdu;2HhNi{o|Np-_#)Nn5Iz(L;u9$GXCF?#ntWMNS=M{-_I4 zn11+RasQW4RY~maiOgc7cLO5(##-+_tfX}Zicz;WK8`}kmw4R}#xKcBlV3H=*iyvO zwBbMIPv{eClwfWFCATK{Buii5X;G>dT zC>z_PQrMU6#eP4tt;GKkBtDH}m~dDjd!rai6}A4FJWsdzXWl_l`$HPW8cAZmB<2+K_zLd{{kDU~&!hiKn>H7>=m>TQsPdQ6|b? zA-|423OnVdVvUX2RW!`uKmKWX*9AiPw_F}PvMoxViGOHRYr<(t9ZDjzcKulR2EV<1 zcLKfrVsq%S7C7JzoB$;wB@}SAZ1Z;V>-hJ)rW|XE@cwD&4<71cIz1jy6Tj8vZ6kj- zUHlUjWATTL@dP*9riI+L6I`!1vYaVlEMyLDz%g9lOuMJz7vP8|Z~!^nK?5)!FvpN= zru)Zs55QA|(xFXv9_o9t-gk$uDmbI`a(Oc4L_dNXuXDNa5To&$*=OYbuu#nN#LqlKVUr6ydKFdY0)s*p$rRGT+ZUmh3!(xprt9o6a)PaEUX+xAL>2fp+Q4b$$O zi;I4tkBDb8+vb2w87Y%23<>bCbDJKwht#!pw{x^|xOv9X3&}^zY3ck=o#HySq>Xz# z$-Qv@8do;;pB~gXIAnP&Nta)dAZ;REzSx=S%M{Qv;PLizALvwjh@99(wB| zZ>_&)>nD|@MfSDFg}eI}Y#+gC_{DH<=Z^FyFz{LY zm#-g{i4RWFeH_2;OSxqePo3>Nw7J==gfAJm#)EZ*$)O!#hqpLgSs#fWU9#kc9Pa2U zey>1TxrXLJ6j{>fA4J0{MS?X6^hXauhbV9Pf}<&SF;)Ut^n$F8LeOQ!FAGBW|6noc zG4AxLYBEP~@Upy2BZGE?R&oTpL}p$eNLZq+NTN6dkF}2}tG|Le5NyKfF;^x+=qBpv zn3IAJub`?~C@W{LBE&BhP_RQPDT6O0Jl_X1M+VM}+H-2q&<97nau0T-4^{#q06%8_cl27Ri-Xs`urOx1wM=PO@PE7{S@x24=A{lq}Y_)!PpX>G{K#(GBH;I z!d{`SjLopprZ&b!*9RXCK-Gmkf)AH+3Pebu1(ds(D-D!-Sd_tIgwQ_9U9=TjlnyjX z{@^l7Ut)1<6j79wyH`1szRjPL=+Rd?LgUEAWl&y9TyBNf81{)b5<}4`5+s}A|ukqzw@GEG1$c~sfvugwy7NFkp zki$8sW7hhsn2^JtA=$(6uR<45-o+z}D4^SP247K3I_`VC;n?GDV{T6K5pi^;{0Nu zRaYP16Fg@a1O~7vwt;iPJL;ekR){Hrigus7#q{0ugHd}uZDlW@xEZMIFg3GK*U&I% z^4$Q++=-Axi^7WqN*VrNls5+`L=bSe^H$hKMSlQLYze6J$*;S(Br>w4bk26+fT8-l z`Aaqbiw_z?_kG=|Kn2ghzyMGyOe*Yu`se6pSS)Ggf`GQZ{@tevyZwj-W=Orfl0qy- zRH<%Fc~MnSS)Sd*Y zE8p4Q+27u4*55(y6qRd_NPU;8;T_i0yVveX!X6xX(7sZ2P)`r2SVhFjl6%n`Ot^xV zqx)QVhQV0@4aZ1qhH~G}URS_@sesQ{r>y9)dWzaj=jEg6{Ec7Wc%6&?8OBp;v9-ybe6HK2M-M}=4^ zBA_c^&C|HGF}JZar?jHO!O_vt)zwwuB&`}=eG|}FT3qgp+?J!bzY3dKZd`)TspzY= zHL9zrz3&52+}bZpO`Xj#Rty8hw%R!`*r1ThHLORD;9`H?XZ14tWj#%kS5tVnhs+>Q zpaoRy4UdeR-=i-O_fj^B>2w)I79#p1L2s&WO?S{_v86kS21U>j3H z06DeM-KkpZ+uYjn@%G*(*&!h&@%Hh#*hRS9b{|dGPfJ6qYm{Z32mAZ`r^Cz4%*-Nf z*p56~o0`1ry~~S=thCXiXrx?@ot;md4<3kh=Sb`-Z)=T{f!Z%=Dz zs{@+j<`8nO(B)t^xLzm8+gggKunsrdr0G_DCv#+JEydLE)?>(bV<-TmR<&L7L{`R4 zsm`uj7yj?Et6=-AYRP?(y*7ERPg|gI-~NSn=VTc(Kv%v zY%kq1<>lPx3)a-sKxVivuuo%SVq&6WqGB+xG0(BFv7#_AW21pfG3VH)4Yl>_W&P-p z23tUVG$tlCCf2`(`LAJPV`E^LT9_?YS*N^;?Q`%2rKL5yz8i(j0mXd3$9|8EjX|Md zpQNOSNr(@&mJ;IP9QVVv?pHMfjygw0JP$H1Mnv82cM&y8nSRHS=j))YOd*ezB6QXH z`~(oi=N~fi^6426zrBqa0YO2BW=8x-1x5Mxhou`Oq5JNJHex|@cRe8bRzo7UvIGKv z(&R`2mZiDOrej!layW^4D%ikVM*T&jp)5l}J~sXcIenV2O0Annz?%Gi`P#>p7`$lv zp;Up-d_K9B`_ki=Be$op4L6LbnHdT}CtFj;_sraOM|(vBMR$I8eM;mGwtDC6`OW#> z-Z!pxZhJUkDO%#oq3r`l1GTlaK89Z;RJ+zM*QbYd4<_qvGiHUVa=!GmZI&e_4zEED z^e7mZ8OaC<8~dJb%9H=UCeAaeskGbU_b%5R#&HBk1V#~f9q9-tRVm>e0TF2fNGD_j z15y$|q=t~|fS}T(2!;}dKA{SM1PBSv(7Pd$NUHRbPy>my z>d?#3`T#xTiSOMw=flBxH*H0EuAje~#m$>H&CJX!j93(gF9ZUie0;LG&Qe4SbJ z+Tb#hWSM&A)H;(f@^4gsL(g$iQa&>jOBcGxdAB07v6M%|K+NQ;UCBJK)#_q6II+tN8&D zHR`T0T?UG|KGqA^>}7sG{x3KAkByIQBhj{lw&hCYU?ngFKXp*91XBX@`g&@K)d(c>Xn!A}l#rL7-<}vKD3^5X zz219XiO4p9hHxGI*hnG*cclJ68M)l}Y{ujrV@BZd5q^jw=Du6+(P7_9xkAp# zBl4de3us8wXMv4s(WNTNYaJ`1)>ut#ZSyvN?Mb*Uc<#5GcpQJf(bz>2Hap9uflnvL z>a7}X3l^((tp^)ReCZ~l1EC)1_u1K5_Fp9|%`(}^OsD4Ep?)slNF z2UCIpa%LKt(JN=kjE{I%s={hRMZqOsa!ymtg)*CF-gF95B0>Ya3xCP_K|CjUHSRR$ z?Af!&qD|D-%8b6*pB9(pmH{9A0stx~D|=e3gauX(FskQ*gir3>8zOWV6k~cidO{D% zRdCVNA;s!A&nEBPnb~5p%$bk>Yjxfh`ii-NtCxQ4qA~*aF82RzXHbK%Ff*_<{|TKs zM?J=wPCc&G(->P?T5^P!JKEcK_wS}WoY)3l2p*W?KaVP2c(whta%xMU!D!ouYUnREcfo+OPBAa{9PDJaFw;Uw~sxDJ@0gW zcPRnt1a$~^aOTi|_+{NA8`gS?7c{$=bB@3wzdqt_C$AjUz(5K8=3rN@DC$|nUNhAY zNlT=P^}&Eo`gn7*$JoOdYze-0@o9U^-d?2nyT+OhRps3Jx*9-xk%)eGJWI$}EjsU8Y!^ENWMZSeMtC?CCUt!L z-SKhy(Q*2BCO^u^WCMqE#K>3=qU~Siro_%pbMQ9^D^xq9hFY; zRN}#s4&G5cm~OS+BMzNrO1yE~eu`@O7>sf@8@py;Xo!RH@KWz(rX43IHs29pBezkZ zU;zQtI?-O`2zPGLJj0sSbib;I8Nb3odr;oILn}>=AwORTg z3((m0@s~<#S&M7XuWmKjunrvk9igy0Jcu zzJ7k@#>SnGZ@(N2v`)2Fv;*9{^^Z{=q4!;Q5!viI~`!x%Dh*5xKq0nAJ6nsbUx|*0Yi$l%rY;fs) z!stx_$|w4y`;WZxJDdIUMSpm*k6NBvW|;ELZofbNm_A4H&;jZNAHq{87@!crIj>(7 zRpgovp)&E2Ov^q*3il*i)37fx1-STHv`ft`F|yMFPPHt!qP4THjX4-tOH%`zjC7pEzQVMpJ#LvL>{epN zXGJPYHtt_OJAP&7O@2vxv|tFxa;-CDl+2^~pI-$@$*45707-A-oCUcXi`BaL3v?Me z{@UQx|EQ_u_WDOJr=HBoVx4%`?FrkY2lu~+(0YKd`=^{{am|>ta+o_~K799kHLI_o zr_&O39tR?U1xTVz2y5N;E{X_0w_X*sH~yO}_0M8O<}d+<}SuyS1(n8z^lV-Pd$ zssE5k9z#){bOb}4kU>a`I{{!Yo54xqtsZ_`C@)Dv%(a1MU`Z42NP`<)hz4{6gAq?v zPf!&q#9|xt;&4uJVUfk@K2^h|tk+t`=tKLGd!^9n23zvXQc-8g6cpDKZfOR0|wTT}Pv_ zy}dmMIc%ApJCi?CDXyH@*LQO;lHc51XWzl$9?g24YSlt(&!nEYye=~HH&8Q%Ml5=} z2T_59LIot;=^s`GC7rCzXGmK;+pmIfoNY^8}@@ZF`X!pn>GFJ{Y6mT7auQCm9^e}8nO6p_>r%Gs=74;_)k%%O1G zycNYd6|SCNO<}N2+wrwA)B(rs4^Qmq>7&g=o?=P;im(~B+0fMB*K6-ZYn>Pw0mQ+{ z$%&A22>xsA#A($J;t2%-dge3D>}x%2sd5YqTo@E6@Dw*}(Sxol`&jB(O4|PZK5@$O zOw@M!YiqhNEjH-vSqD<*Qej#PHjS2@m%!MQSIis?4i2fStA}SB$QH;_anx7i=qP+$ zOK@D0N#DQvdYh7g>^AX`elI~)O%13CghHXZjcoc+hDk1reCzxu*x1-)5>}z3dE@I| z5xv3jHZTiOf!2oXs|F6~o*P!T0Js{gd>&mz-sf)KqO=*XNj= ze8nAABzvapB>%J782DBYVkY5#Qi8(A*jsz-E!F{(K)A z8!qU{8Ebf(nHd5JrZQiA`p*lFVke$bfw`=;;Ei5!v?$*DEr80n1K_Mo*SGyW3+Fl! zbfvpPsjm#eOScV{7m9Qtz&6}9?OJ!U1Aflw`lC_J0`MhY!VBY|N8Lb@@o|>j`M3~W zR>tRV_|vL@T0R&*`3xUFEkV);lep48iGp>Gul4}$~w=KZdEY7S5r zh2SSI$tl<>sH&>k1X0q`()1&JNWlkNbL{b#23lIBCXw3O+8b*dPaxcs7~Ye}0H!|} zjLdaa&;PkKaXB)EpftvxE1bhY*J-B8`hI3P15eL2U=D2u3nEvtHUX=C#Y0a;9js%E zUopopAZq9CK_jZT^U;Ey&YMfECzK2=k9aiVCb_ESh{f!5kt9BtEg!q!aa^$`K1A^n zMFLF4sl(zRftY0H%jg*MrH*7X?w*{-DE)k>NW(_rhm67cwwQHx}Kn7w^k zxynXuC5coJoKtH$5w&(W*Y`=;LiDHTud08lECmSQThcqiFWY}xEKclCOz`Ht2Pjsnp%g&5U7&&yMu7;DyIH2=~3LMUUxp# zOGm%g3uv9ld4V(~^L}a}0b}K$E0g-<47r!faLdBNc#&Nl%?N7J$x+LXllIz{{5p%V zYY>4vdqcetcBl~1zrztCK*I4k7+`cZE5Ue(@9t@2KF}^YP`LYKs1xZPK*LAAl~ z5}IngdTyjL*9gDPLCoXY+f8!dEMsE$G#|sp5sM?t>*6~I1nyxIv((MYIl%dm{Uczw z+Ebc0hrpqiL%DxvDrLUdre1h4P?HcHnrQE1`)!2&XZYBL`q-vCie6HL#O?cWU>7fj zg@>2YO~W$fj(PP4L`2=&-Y(AF+V2TQM8XdD%PAXl2@@8{(lEn cTzG0#Z74nA{=*%IZ};tOoo!m~{{F}R0piKC8UO$Q diff --git a/doc-src/certinstall/android.html b/doc-src/certinstall/android.html deleted file mode 100644 index 73fc4d8b5..000000000 --- a/doc-src/certinstall/android.html +++ /dev/null @@ -1,53 +0,0 @@ -The proxy situation on Android is [an -embarrasment](http://code.google.com/p/android/issues/detail?id=1273). It's -scarcely credible, but Android didn't have a global proxy setting at all until -quite recently, and it's still not supported on many common Android versions. -In the meantime the app ecosystem has grown used to life without this basic -necessity, and many apps merrily ignore it even if it's there. This situation -is improving, but in many circumstances using [transparent -mode](@!urlTo("transparent.html")!@) is mandatory for testing Android apps. - -We used both an Asus Transformer Prime TF201 (Android 4.0.3) and a Nexus 4 -(Android 4.4.4) in the examples below - your device may differ, but the broad -process should be similar. On **emulated devices**, there are some [additional -quirks](https://github.com/mitmproxy/mitmproxy/issues/204#issuecomment-32837093) -to consider. - - -## Getting the certificate onto the device - -The easiest way to get the certificate to the device is to use [the web -app](@!urlTo("webapp.html")!@). In the rare cases where the web app doesn't -work, you will need to get the __mitmproxy-ca-cert.cer__ file into the -__/sdcard__ folder on the device (/sdcard/Download on older devices). This can -be accomplished in a number of ways: - -- If you have the Android Developer Tools installed, you can use [__adb -push__](http://developer.android.com/tools/help/adb.html). -- Using a file transfer program like wget (installed on the Android device) to -copy the file over. -- Transfer the file using external media like an SD Card. - -Once we have the certificate on the local disk, we need to import it into the -list of trusted CAs. Go to Settings -> Security -> Credential Storage, -and select "Install from storage": - - - -The certificate in /sdcard is automatically located and offered for -installation. Installing the cert will delete the download file from the local -disk. - - -## Installing the certificate - -You should now see something like this (you may have to explicitly name the -certificate): - - - -Click OK, and you should then see the certificate listed in the Trusted -Credentials store: - - - diff --git a/doc-src/certinstall/firefox.html b/doc-src/certinstall/firefox.html deleted file mode 100644 index bb9ba05bb..000000000 --- a/doc-src/certinstall/firefox.html +++ /dev/null @@ -1,31 +0,0 @@ -## Get the certificate to the browser - -The easiest way to get the certificate to the browser is to use [the web -app](@!urlTo("webapp.html")!@). If this fails, do the following: - - -

    -
  1. If needed, copy the ~/.mitmproxy/mitmproxy-ca-cert.pem file to the target.
  2. - -
  3. Open preferences, click on "Advanced", then select"Certificates": - -
  4. - -
  5. Click "View Certificates", "Import", and select the certificate file: - -
  6. - -
- - -## Installing the certificate - -
    -
  1. Tick "Trust this CA to identify web sites", and click "Ok": - -
  2. - -
  3. You should now see the mitmproxy certificate listed in the Authorities - tab.
  4. -
- diff --git a/doc-src/certinstall/index.py b/doc-src/certinstall/index.py index d6b1e4178..fd422cb3e 100644 --- a/doc-src/certinstall/index.py +++ b/doc-src/certinstall/index.py @@ -2,12 +2,5 @@ from countershape import Page pages = [ Page("webapp.html", "Using the Web App"), - Page("firefox.html", "Firefox"), - Page("osx.html", "OSX"), - Page("windows7.html", "Windows 7"), - Page("ios.html", "IOS"), - Page("ios-simulator.html", "IOS Simulator"), - Page("android.html", "Android"), - Page("java.html", "Java"), Page("mitm.it-error.html", "Error: No proxy configured"), ] diff --git a/doc-src/certinstall/ios-simulator.html b/doc-src/certinstall/ios-simulator.html deleted file mode 100644 index 9eb981086..000000000 --- a/doc-src/certinstall/ios-simulator.html +++ /dev/null @@ -1,23 +0,0 @@ - -How to install the __mitmproxy__ certificate authority in the IOS simulator: - -
    - -
  1. First, check out the ADVTrustStore tool - from github.
  2. - -
  3. Now, run the following command: - -
    ./iosCertTrustManager.py -a ~/.mitmproxy/mitmproxy-ca-cert.pem
    - -
  4. - -
- - -Note that although the IOS simulator has its own certificate store, it shares -the proxy settings of the host operating system. You will therefore to have -configure your OSX host's proxy settings to use the mitmproxy instance you want -to test with. - diff --git a/doc-src/certinstall/ios.html b/doc-src/certinstall/ios.html deleted file mode 100644 index c12d65f69..000000000 --- a/doc-src/certinstall/ios.html +++ /dev/null @@ -1,27 +0,0 @@ - -## Getting the certificate onto the device - -The easiest way to get the certificate to the device is to use [the web -app](@!urlTo("webapp.html")!@). In the rare cases where the web app doesn't -work, you will need to get the __mitmproxy-ca-cert.pem__ file to the device to -install it. The easiest way to accomplish this is to set up the Mail app on the -device, and to email it over as an attachment. Open the email, tap on the -attachment, then proceed with the install. - - -## Installing the certificate - -
    -
  1. You will be prompted to install a profile. Click "Install": - -
  2. - -
  3. Accept the warning by clicking "Install" again: - -
  4. - -
  5. The certificate should now be trusted: - -
  6. - -
diff --git a/doc-src/certinstall/java.html b/doc-src/certinstall/java.html deleted file mode 100644 index f64209910..000000000 --- a/doc-src/certinstall/java.html +++ /dev/null @@ -1,13 +0,0 @@ - -You can add the mitmproxy certificates to the Java trust store using -[keytool](http://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html). -On OSX, the required command looks like this: - -
-sudo keytool -importcert -alias mitmproxy -storepass "password" \
--keystore /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts \
--trustcacerts -file ~/.mitmproxy/mitmproxy-ca-cert.pem
-
- -Note that your store password will (hopefully) be different from the one above. - diff --git a/doc-src/certinstall/osx.html b/doc-src/certinstall/osx.html deleted file mode 100644 index a532d5380..000000000 --- a/doc-src/certinstall/osx.html +++ /dev/null @@ -1,16 +0,0 @@ - -How to install the __mitmproxy__ certificate authority in OSX: - -
    - -
  1. Open Finder, and double-click on the mitmproxy-ca-cert.pem file.
  2. - -
  3. You will be prompted to add the certificate. Click "Always Trust": - - -
  4. - -
  5. You may be prompted for your password. You should now see the - mitmproxy cert listed under "Certificates".
  6. -
- diff --git a/doc-src/certinstall/windows7.html b/doc-src/certinstall/windows7.html deleted file mode 100644 index 7a4cc3d26..000000000 --- a/doc-src/certinstall/windows7.html +++ /dev/null @@ -1,35 +0,0 @@ - -How to install the __mitmproxy__ certificate authority in Windows 7: - -
    - -
  1. The easiest way to get the certificate to the device is to use the web app. If this fails for some - reason, simply copy the ~/.mitmproxy/mitmproxy-ca-cert.p12 file to the - target system and double-click it.
  2. - -
  3. - You should see a certificate import wizard: - - -
  4. - -
  5. - Click "Next" until you're prompted for the certificate store: - - - -
  6. - - -
  7. -

    Select "Place all certificates in the following store", and select "Trusted Root Certification Authorities":

    - - - -
  8. - -
  9. Click "Next" and "Finish".
  10. - -
- diff --git a/doc-src/ssl.html b/doc-src/ssl.html index de45bd29f..cccde1b78 100644 --- a/doc-src/ssl.html +++ b/doc-src/ssl.html @@ -87,13 +87,5 @@ You can use your own certificate authority by passing the --confdir o mitmproxy will then look for mitmproxy-ca.pem in the specified directory. If no such file exists, it will be generated automatically. -Installing the mitmproxy CA ---------------------------- -* [Firefox](@!urlTo("certinstall/firefox.html")!@) -* [OSX](@!urlTo("certinstall/osx.html")!@) -* [Windows 7](@!urlTo("certinstall/windows7.html")!@) -* [iPhone/iPad](@!urlTo("certinstall/ios.html")!@) -* [IOS Simulator](@!urlTo("certinstall/ios-simulator.html")!@) -* [Android](@!urlTo("certinstall/android.html")!@) diff --git a/doc-src/tutorials/gamecenter.html b/doc-src/tutorials/gamecenter.html index 5998f889f..b51b6faf9 100644 --- a/doc-src/tutorials/gamecenter.html +++ b/doc-src/tutorials/gamecenter.html @@ -2,9 +2,8 @@ ## The setup In this tutorial, I'm going to show you how simple it is to creatively -interfere with Apple Game Center traffic using mitmproxy. To set things up, I -registered my mitmproxy CA certificate with my iPhone - there's a [step by step -set of instructions](@!urlTo("certinstall/ios.html")!@) elsewhere in this manual. I then +interfere with Apple Game Center traffic using mitmproxy. To set things up, +you must install the [mitmproxy root certificate](@!urlTo("certinstall/webapp.html")!@) elsewhere in this manual. I then started mitmproxy on my desktop, and configured the iPhone to use it as a proxy. From f3dab52a6297d4ea2fe0f0bc444bf0a3265e887a Mon Sep 17 00:00:00 2001 From: Jim Shaver Date: Tue, 17 Mar 2015 00:30:18 -0400 Subject: [PATCH 004/170] Better english --- doc-src/tutorials/gamecenter.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc-src/tutorials/gamecenter.html b/doc-src/tutorials/gamecenter.html index b51b6faf9..d192232c0 100644 --- a/doc-src/tutorials/gamecenter.html +++ b/doc-src/tutorials/gamecenter.html @@ -3,7 +3,7 @@ In this tutorial, I'm going to show you how simple it is to creatively interfere with Apple Game Center traffic using mitmproxy. To set things up, -you must install the [mitmproxy root certificate](@!urlTo("certinstall/webapp.html")!@) elsewhere in this manual. I then +you must install the [mitmproxy root certificate](@!urlTo("certinstall/webapp.html")!@). I then started mitmproxy on my desktop, and configured the iPhone to use it as a proxy. From e0e36f5dae4572ea4053821e6fef1487de87642e Mon Sep 17 00:00:00 2001 From: Jim Shaver Date: Wed, 18 Mar 2015 00:22:18 -0400 Subject: [PATCH 005/170] consolidated down all SSL documentation into one document --- doc-src/_nav.html | 3 +- doc-src/certinstall/index.py | 2 +- doc-src/certinstall/webapp.html | 13 ----- doc-src/index.py | 1 - doc-src/ssl.html | 91 ------------------------------- doc-src/tutorials/gamecenter.html | 2 +- 6 files changed, 3 insertions(+), 109 deletions(-) delete mode 100644 doc-src/certinstall/webapp.html delete mode 100644 doc-src/ssl.html diff --git a/doc-src/_nav.html b/doc-src/_nav.html index 91d2118fe..3efff40ba 100644 --- a/doc-src/_nav.html +++ b/doc-src/_nav.html @@ -29,8 +29,7 @@ - $!nav("ssl.html", this, state)!$ - $!nav("certinstall/webapp.html", this, state)!$ + $!nav("certinstall/ssl.html", this, state)!$ $!nav("transparent.html", this, state)!$ diff --git a/doc-src/certinstall/index.py b/doc-src/certinstall/index.py index fd422cb3e..67e6185b8 100644 --- a/doc-src/certinstall/index.py +++ b/doc-src/certinstall/index.py @@ -1,6 +1,6 @@ from countershape import Page pages = [ - Page("webapp.html", "Using the Web App"), + Page("ssl.html", "SSL Options"), Page("mitm.it-error.html", "Error: No proxy configured"), ] diff --git a/doc-src/certinstall/webapp.html b/doc-src/certinstall/webapp.html deleted file mode 100644 index 478da96cb..000000000 --- a/doc-src/certinstall/webapp.html +++ /dev/null @@ -1,13 +0,0 @@ - -By far the easiest way to install the mitmproxy certs is to use the built-in -web app. To do this, start mitmproxy and configure your target device with the -correct proxy settings. Now start a browser on the device, and visit the magic -domain **mitm.it**. You should see something like this: - - - -Just click on the relevant icon, and then follow the setup instructions -for the platform you're on. - -Make sure you aren't using a bandwith optimizer (like Google's Data Compression -Proxy on Chrome for Android) or the page will not load. diff --git a/doc-src/index.py b/doc-src/index.py index 753f90a5c..1c1203f86 100644 --- a/doc-src/index.py +++ b/doc-src/index.py @@ -67,7 +67,6 @@ pages = [ Page("mitmdump.html", "mitmdump"), Page("config.html", "configuration"), - Page("ssl.html", "Overview"), Directory("certinstall"), Directory("scripting"), Directory("tutorials"), diff --git a/doc-src/ssl.html b/doc-src/ssl.html deleted file mode 100644 index cccde1b78..000000000 --- a/doc-src/ssl.html +++ /dev/null @@ -1,91 +0,0 @@ - -The first time __mitmproxy__ or __mitmdump__ is run, a set of certificate files -for the mitmproxy Certificate Authority are created in the config directory -(~/.mitmproxy by default). This CA is used for on-the-fly generation of dummy -certificates for SSL interception. Since your browser won't trust the -__mitmproxy__ CA out of the box (and rightly so), you will see an SSL cert -warning every time you visit a new SSL domain through __mitmproxy__. When -you're testing a single site through a browser, just accepting the bogus SSL -cert manually is not too much trouble, but there are a many circumstances where -you will want to configure your testing system or browser to trust the -__mitmproxy__ CA as a signing root authority. - - -CA and cert files ------------------ - -The files created by mitmproxy in the .mitmproxy directory are as follows: - - - - - - - - - - - - - - - - - - -
mitmproxy-ca.pemThe private key and certificate in PEM format.
mitmproxy-ca-cert.pemThe certificate in PEM format. Use this to distribute to most - non-Windows platforms.
mitmproxy-ca-cert.p12The certificate in PKCS12 format. For use on Windows.
mitmproxy-ca-cert.cerSame file as .pem, but with an extension expected by some Android - devices.
- - -Using a custom certificate --------------------------- - -You can use your own certificate by passing the --cert option to mitmproxy. mitmproxy then uses the provided -certificate for interception of the specified domains instead of generating a cert signed by its own CA. - -The certificate file is expected to be in the PEM format. -You can include intermediary certificates right below your leaf certificate, so that you PEM file roughly looks like -this: - -
------BEGIN PRIVATE KEY-----
-<private key>
------END PRIVATE KEY-----
------BEGIN CERTIFICATE-----
-<cert>
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-<intermediary cert (optional)>
------END CERTIFICATE-----
-
- -For example, you can generate a certificate in this format using these instructions: - -
-> openssl genrsa -out cert.key 8192
-> openssl req -new -x509 -key cert.key -out cert.crt
-    (Specify the mitm domain as Common Name, e.g. *.google.com)
-> cat cert.key cert.crt > cert.pem
-> mitmproxy --cert=cert.pem
-
- -Using a client side certificate ------------------------------------- -You can use a client certificate by passing the --client-certs DIRECTORY option to mitmproxy. -If you visit example.org, mitmproxy looks for a file named example.org.pem in the specified directory -and uses this as the client cert. The certificate file needs to be in the PEM format and should contain -both the unencrypted private key as well as the certificate. - - -Using a custom certificate authority ------------------------------------- - -By default, mitmproxy will (generate and) use ~/.mitmproxy/mitmproxy-ca.pem as the default certificate -authority to generate certificates for all domains for which no custom certificate is provided (see above). -You can use your own certificate authority by passing the --confdir option to mitmproxy. -mitmproxy will then look for mitmproxy-ca.pem in the specified directory. If no such file exists, -it will be generated automatically. - - - diff --git a/doc-src/tutorials/gamecenter.html b/doc-src/tutorials/gamecenter.html index d192232c0..8d2e9bc5c 100644 --- a/doc-src/tutorials/gamecenter.html +++ b/doc-src/tutorials/gamecenter.html @@ -3,7 +3,7 @@ In this tutorial, I'm going to show you how simple it is to creatively interfere with Apple Game Center traffic using mitmproxy. To set things up, -you must install the [mitmproxy root certificate](@!urlTo("certinstall/webapp.html")!@). I then +you must install the [mitmproxy root certificate](@!urlTo("certinstall/ssl.html")!@). I then started mitmproxy on my desktop, and configured the iPhone to use it as a proxy. From 36bec7b77e1a8c02211c706b3e651fee13a3b3e2 Mon Sep 17 00:00:00 2001 From: Jim Shaver Date: Wed, 18 Mar 2015 00:29:54 -0400 Subject: [PATCH 006/170] now actually tracking ssl.html --- doc-src/certinstall/ssl.html | 113 +++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 doc-src/certinstall/ssl.html diff --git a/doc-src/certinstall/ssl.html b/doc-src/certinstall/ssl.html new file mode 100644 index 000000000..8b2b8ed7d --- /dev/null +++ b/doc-src/certinstall/ssl.html @@ -0,0 +1,113 @@ +SSL traffic poses a potential problem when using mitmproxy, as it is encrypted, it is opaque to inspection. +In order to be able to decrypt the traffic, you must use a certificate that the client, whose traffic you are intercepting, trusts. +This document outlines the different options you have for either using the certificate that mitmproxy generates or using your own. + +Quick Setup +----------- + +By far the easiest way to install the mitmproxy certificates is to use the built-in +web app. To do this, start mitmproxy and configure your target device with the +correct proxy settings. Now start a browser on the device, and visit the domain **mitm.it**. +You should see something like this: + + + +Just click on the relevant icon, and then follow the setup instructions +for the platform you're on. + +Certificates are installed via several different methods depending on the client. +There are too many to go into in this document, consult the documentation for +the client that you would to have trust the mitmproxy root certificate, +for specific installation instructions. + + +More On mitmproxy Certificates +------------------------------ + +The first time __mitmproxy__ or __mitmdump__ is run, the mitmproxy Certificate +Authority(CA) is created in the config directory (~/.mitmproxy by default). +This CA is used for on-the-fly generation of dummy certificates for each of the +SSL sites that your client visits. Since your browser won't trust the +__mitmproxy__ CA out of the box , you will see an SSL certificate +warning every time you visit a new SSL domain through __mitmproxy__. When +you are testing a single site through a browser, just accepting the bogus SSL +cert manually is not too much trouble, but there are a many circumstances where +you will want to configure your testing system or browser to trust the +__mitmproxy__ CA as a signing root authority. + + +CA and cert files +----------------- + +The files created by mitmproxy in the .mitmproxy directory are as follows: + + + + + + + + + + + + + + + + + + +
mitmproxy-ca.pemThe private key and certificate in PEM format.
mitmproxy-ca-cert.pemThe certificate in PEM format. Use this to distribute to most + non-Windows platforms.
mitmproxy-ca-cert.p12The certificate in PKCS12 format. For use on Windows.
mitmproxy-ca-cert.cerSame file as .pem, but with an extension expected by some Android + devices.
+ + +Using a custom certificate +-------------------------- + +You can use your own certificate by passing the --cert option to mitmproxy. mitmproxy then uses the provided +certificate for interception of the specified domains instead of generating a certificate signed by its own CA. + +The certificate file is expected to be in the PEM format. +You can include intermediary certificates right below your leaf certificate, so that you PEM file roughly looks like +this: + +
+-----BEGIN PRIVATE KEY-----
+<private key>
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+<cert>
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+<intermediary cert (optional)>
+-----END CERTIFICATE-----
+
+ +For example, you can generate a certificate in this format using these instructions: + +
+> openssl genrsa -out cert.key 2048
+> openssl req -new -x509 -key cert.key -out cert.crt
+    (Specify the mitm domain as Common Name, e.g. *.google.com)
+> cat cert.key cert.crt > cert.pem
+> mitmproxy --cert=cert.pem
+
+ +Using a client side certificate +------------------------------------ +You can use a client certificate by passing the --client-certs DIRECTORY option to mitmproxy. +If you visit example.org, mitmproxy looks for a file named example.org.pem in the specified directory +and uses this as the client cert. The certificate file needs to be in the PEM format and should contain +both the unencrypted private key as well as the certificate. + + +Using a custom certificate authority +------------------------------------ + +By default, mitmproxy will (generate and) use ~/.mitmproxy/mitmproxy-ca.pem as the default certificate +authority to generate certificates for all domains for which no custom certificate is provided (see above). +You can use your own certificate authority by passing the --confdir option to mitmproxy. +mitmproxy will then look for mitmproxy-ca.pem in the specified directory. If no such file exists, +it will be generated automatically. From d7e53e6573426c40ac7cfbaa7754380985227eb1 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 20 Mar 2015 09:30:29 +1300 Subject: [PATCH 007/170] Fix crashes on mouse click when input is being handled --- libmproxy/console/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 198b7bbee..70b82d1da 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -617,8 +617,6 @@ class ConsoleMaster(flow.FlowMaster): self.prompt_execute(k) elif k == "enter": self.prompt_execute() - else: - self.view.keypress(self.loop.screen_size, k) else: k = self.view.keypress(self.loop.screen_size, k) if k: @@ -943,7 +941,7 @@ class ConsoleMaster(flow.FlowMaster): mkup.append(",") prompt.extend(mkup) prompt.append(")? ") - self.onekey = "".join(i[1] for i in keys) + self.onekey = set(i[1] for i in keys) self.prompt(prompt, "", callback, *args) def prompt_done(self): From a3f4296bf1ba0ac1a72d5a44a504d375707fdc39 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 20 Mar 2015 10:02:34 +1300 Subject: [PATCH 008/170] Explicitly handle keyboard interrupt in mitmproxy Fixes #522 --- libmproxy/console/__init__.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 70b82d1da..9796677fb 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -7,6 +7,7 @@ import tempfile import os import os.path import shlex +import signal import stat import subprocess import sys @@ -25,7 +26,8 @@ EVENTLOG_SIZE = 500 class _PathCompleter: def __init__(self, _testing=False): """ - _testing: disables reloading of the lookup table to make testing possible. + _testing: disables reloading of the lookup table to make testing + possible. """ self.lookup, self.offset = None, None self.final = None @@ -37,7 +39,8 @@ class _PathCompleter: def complete(self, txt): """ - Returns the next completion for txt, or None if there is no completion. + Returns the next completion for txt, or None if there is no + completion. """ path = os.path.expanduser(txt) if not self.lookup: @@ -702,14 +705,6 @@ class ConsoleMaster(flow.FlowMaster): self.edit_scripts ) ) - #if self.scripts: - # self.load_script(None) - #else: - # self.path_prompt( - # "Set script: ", - # self.state.last_script, - # self.set_script - # ) elif k == "S": if not self.server_playback: self.path_prompt( @@ -799,6 +794,14 @@ class ConsoleMaster(flow.FlowMaster): sys.exit(1) self.loop.set_alarm_in(0.01, self.ticker) + + # It's not clear why we need to handle this explicitly - without this, + # mitmproxy hangs on keyboard interrupt. Remove if we ever figure it + # out. + def exit(s, f): + raise urwid.ExitMainLoop + signal.signal(signal.SIGINT, exit) + try: self.loop.run() except Exception: From 560e44c637e4f1fcbeba1305fc1eb39e3d796013 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 20 Mar 2015 10:54:57 +1300 Subject: [PATCH 009/170] Pull PathEdit out into its own file. --- libmproxy/console/__init__.py | 69 +---------------------------------- libmproxy/console/pathedit.py | 69 +++++++++++++++++++++++++++++++++++ test/test_console.py | 43 ---------------------- test/test_console_pathedit.py | 48 ++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 110 deletions(-) create mode 100644 libmproxy/console/pathedit.py create mode 100644 test/test_console_pathedit.py diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 9796677fb..013c80034 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -18,76 +18,11 @@ import weakref from .. import controller, utils, flow, script from . import flowlist, flowview, help, common -from . import grideditor, palettes, contentview, flowdetailview +from . import grideditor, palettes, contentview, flowdetailview, pathedit EVENTLOG_SIZE = 500 -class _PathCompleter: - def __init__(self, _testing=False): - """ - _testing: disables reloading of the lookup table to make testing - possible. - """ - self.lookup, self.offset = None, None - self.final = None - self._testing = _testing - - def reset(self): - self.lookup = None - self.offset = -1 - - def complete(self, txt): - """ - Returns the next completion for txt, or None if there is no - completion. - """ - path = os.path.expanduser(txt) - if not self.lookup: - if not self._testing: - # Lookup is a set of (display value, actual value) tuples. - self.lookup = [] - if os.path.isdir(path): - files = glob.glob(os.path.join(path, "*")) - prefix = txt - else: - files = glob.glob(path+"*") - prefix = os.path.dirname(txt) - prefix = prefix or "./" - for f in files: - display = os.path.join(prefix, os.path.basename(f)) - if os.path.isdir(f): - display += "/" - self.lookup.append((display, f)) - if not self.lookup: - self.final = path - return path - self.lookup.sort() - self.offset = -1 - self.lookup.append((txt, txt)) - self.offset += 1 - if self.offset >= len(self.lookup): - self.offset = 0 - ret = self.lookup[self.offset] - self.final = ret[1] - return ret[0] - - -class PathEdit(urwid.Edit, _PathCompleter): - def __init__(self, *args, **kwargs): - urwid.Edit.__init__(self, *args, **kwargs) - _PathCompleter.__init__(self) - - def keypress(self, size, key): - if key == "tab": - comp = self.complete(self.get_edit_text()) - self.set_edit_text(comp) - self.set_edit_pos(len(comp)) - else: - self.reset() - return urwid.Edit.keypress(self, size, key) - - class ActionBar(urwid.WidgetWrap): def __init__(self): self.message("") @@ -97,7 +32,7 @@ class ActionBar(urwid.WidgetWrap): def path_prompt(self, prompt, text): self.expire = None - self._w = PathEdit(prompt, text) + self._w = pathedit.PathEdit(prompt, text) def prompt(self, prompt, text = ""): self.expire = None diff --git a/libmproxy/console/pathedit.py b/libmproxy/console/pathedit.py new file mode 100644 index 000000000..53cda3be5 --- /dev/null +++ b/libmproxy/console/pathedit.py @@ -0,0 +1,69 @@ +import glob +import os.path + +import urwid + + +class _PathCompleter: + def __init__(self, _testing=False): + """ + _testing: disables reloading of the lookup table to make testing + possible. + """ + self.lookup, self.offset = None, None + self.final = None + self._testing = _testing + + def reset(self): + self.lookup = None + self.offset = -1 + + def complete(self, txt): + """ + Returns the next completion for txt, or None if there is no + completion. + """ + path = os.path.expanduser(txt) + if not self.lookup: + if not self._testing: + # Lookup is a set of (display value, actual value) tuples. + self.lookup = [] + if os.path.isdir(path): + files = glob.glob(os.path.join(path, "*")) + prefix = txt + else: + files = glob.glob(path+"*") + prefix = os.path.dirname(txt) + prefix = prefix or "./" + for f in files: + display = os.path.join(prefix, os.path.basename(f)) + if os.path.isdir(f): + display += "/" + self.lookup.append((display, f)) + if not self.lookup: + self.final = path + return path + self.lookup.sort() + self.offset = -1 + self.lookup.append((txt, txt)) + self.offset += 1 + if self.offset >= len(self.lookup): + self.offset = 0 + ret = self.lookup[self.offset] + self.final = ret[1] + return ret[0] + + +class PathEdit(urwid.Edit, _PathCompleter): + def __init__(self, *args, **kwargs): + urwid.Edit.__init__(self, *args, **kwargs) + _PathCompleter.__init__(self) + + def keypress(self, size, key): + if key == "tab": + comp = self.complete(self.get_edit_text()) + self.set_edit_text(comp) + self.set_edit_pos(len(comp)) + else: + self.reset() + return urwid.Edit.keypress(self, size, key) diff --git a/test/test_console.py b/test/test_console.py index d66bd8b0e..419b94a78 100644 --- a/test/test_console.py +++ b/test/test_console.py @@ -104,48 +104,5 @@ def test_format_keyvals(): ) -class TestPathCompleter: - def test_lookup_construction(self): - c = console._PathCompleter() - - cd = tutils.test_data.path("completion") - ca = os.path.join(cd, "a") - assert c.complete(ca).endswith(normpath("/completion/aaa")) - assert c.complete(ca).endswith(normpath("/completion/aab")) - c.reset() - ca = os.path.join(cd, "aaa") - assert c.complete(ca).endswith(normpath("/completion/aaa")) - assert c.complete(ca).endswith(normpath("/completion/aaa")) - c.reset() - assert c.complete(cd).endswith(normpath("/completion/aaa")) - - def test_completion(self): - c = console._PathCompleter(True) - c.reset() - c.lookup = [ - ("a", "x/a"), - ("aa", "x/aa"), - ] - assert c.complete("a") == "a" - assert c.final == "x/a" - assert c.complete("a") == "aa" - assert c.complete("a") == "a" - - c = console._PathCompleter(True) - r = c.complete("l") - assert c.final.endswith(r) - - c.reset() - assert c.complete("/nonexistent") == "/nonexistent" - assert c.final == "/nonexistent" - c.reset() - assert c.complete("~") != "~" - - c.reset() - s = "thisisatotallynonexistantpathforsure" - assert c.complete(s) == s - assert c.final == s - - def test_options(): assert console.Options(kill=True) diff --git a/test/test_console_pathedit.py b/test/test_console_pathedit.py new file mode 100644 index 000000000..605e1e2f1 --- /dev/null +++ b/test/test_console_pathedit.py @@ -0,0 +1,48 @@ +import os +from os.path import normpath +from libmproxy.console import pathedit + +import tutils + + +class TestPathCompleter: + def test_lookup_construction(self): + c = pathedit._PathCompleter() + + cd = tutils.test_data.path("completion") + ca = os.path.join(cd, "a") + assert c.complete(ca).endswith(normpath("/completion/aaa")) + assert c.complete(ca).endswith(normpath("/completion/aab")) + c.reset() + ca = os.path.join(cd, "aaa") + assert c.complete(ca).endswith(normpath("/completion/aaa")) + assert c.complete(ca).endswith(normpath("/completion/aaa")) + c.reset() + assert c.complete(cd).endswith(normpath("/completion/aaa")) + + def test_completion(self): + c = pathedit._PathCompleter(True) + c.reset() + c.lookup = [ + ("a", "x/a"), + ("aa", "x/aa"), + ] + assert c.complete("a") == "a" + assert c.final == "x/a" + assert c.complete("a") == "aa" + assert c.complete("a") == "a" + + c = pathedit._PathCompleter(True) + r = c.complete("l") + assert c.final.endswith(r) + + c.reset() + assert c.complete("/nonexistent") == "/nonexistent" + assert c.final == "/nonexistent" + c.reset() + assert c.complete("~") != "~" + + c.reset() + s = "thisisatotallynonexistantpathforsure" + assert c.complete(s) == s + assert c.final == s From 558e0a41c25ed927a3bd3244e82e50f2c1ec9f1c Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 20 Mar 2015 11:00:24 +1300 Subject: [PATCH 010/170] Fix general prompt input. --- libmproxy/console/__init__.py | 3 +++ libmproxy/console/common.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 013c80034..5ff8e8d7b 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -555,6 +555,9 @@ class ConsoleMaster(flow.FlowMaster): self.prompt_execute(k) elif k == "enter": self.prompt_execute() + else: + if common.is_keypress(k): + self.view.keypress(self.loop.screen_size, k) else: k = self.view.keypress(self.loop.screen_size, k) if k: diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 3a708c7c9..90204d79f 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -31,6 +31,14 @@ METHOD_OPTIONS = [ ] +def is_keypress(k): + """ + Is this input event a keypress? + """ + if isinstance(k, basestring): + return True + + def highlight_key(s, k): l = [] parts = s.split(k, 1) From 241530eb0aa69c5a69bed979a1a2a3a23d473112 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 20 Mar 2015 11:03:46 +1300 Subject: [PATCH 011/170] Remove cruft to work around an old Urwid bug --- libmproxy/console/__init__.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 5ff8e8d7b..f3c8ee12e 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -36,11 +36,6 @@ class ActionBar(urwid.WidgetWrap): def prompt(self, prompt, text = ""): self.expire = None - # A (partial) workaround for this Urwid issue: - # https://github.com/Nic0/tyrs/issues/115 - # We can remove it once veryone is beyond 1.0.1 - if isinstance(prompt, basestring): - prompt = unicode(prompt) self._w = urwid.Edit(prompt, text or "") def message(self, message, expire=None): From 2f8ebfdce2165f1bd9196954a1d3bcdfec463494 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 20 Mar 2015 11:08:04 +1300 Subject: [PATCH 012/170] Pull console StatusBar into its own file. --- libmproxy/console/__init__.py | 189 ++------------------------------- libmproxy/console/statusbar.py | 180 +++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 182 deletions(-) create mode 100644 libmproxy/console/statusbar.py diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index f3c8ee12e..5f564a20b 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -1,6 +1,5 @@ from __future__ import absolute_import -import glob import mailcap import mimetypes import tempfile @@ -11,191 +10,17 @@ import signal import stat import subprocess import sys -import time import traceback import urwid import weakref -from .. import controller, utils, flow, script +from .. import controller, flow, script from . import flowlist, flowview, help, common -from . import grideditor, palettes, contentview, flowdetailview, pathedit +from . import grideditor, palettes, contentview, flowdetailview, statusbar EVENTLOG_SIZE = 500 -class ActionBar(urwid.WidgetWrap): - def __init__(self): - self.message("") - - def selectable(self): - return True - - def path_prompt(self, prompt, text): - self.expire = None - self._w = pathedit.PathEdit(prompt, text) - - def prompt(self, prompt, text = ""): - self.expire = None - self._w = urwid.Edit(prompt, text or "") - - def message(self, message, expire=None): - self.expire = expire - self._w = urwid.Text(message) - - -class StatusBar(urwid.WidgetWrap): - def __init__(self, master, helptext): - self.master, self.helptext = master, helptext - self.ab = ActionBar() - self.ib = urwid.WidgetWrap(urwid.Text("")) - self._w = urwid.Pile([self.ib, self.ab]) - - def get_status(self): - r = [] - - if self.master.setheaders.count(): - r.append("[") - r.append(("heading_key", "H")) - r.append("eaders]") - if self.master.replacehooks.count(): - r.append("[") - r.append(("heading_key", "R")) - r.append("eplacing]") - if self.master.client_playback: - r.append("[") - r.append(("heading_key", "cplayback")) - r.append(":%s to go]"%self.master.client_playback.count()) - if self.master.server_playback: - r.append("[") - r.append(("heading_key", "splayback")) - if self.master.nopop: - r.append(":%s in file]"%self.master.server_playback.count()) - else: - r.append(":%s to go]"%self.master.server_playback.count()) - if self.master.get_ignore_filter(): - r.append("[") - r.append(("heading_key", "I")) - r.append("gnore:%d]" % len(self.master.get_ignore_filter())) - if self.master.get_tcp_filter(): - r.append("[") - r.append(("heading_key", "T")) - r.append("CP:%d]" % len(self.master.get_tcp_filter())) - if self.master.state.intercept_txt: - r.append("[") - r.append(("heading_key", "i")) - r.append(":%s]"%self.master.state.intercept_txt) - if self.master.state.limit_txt: - r.append("[") - r.append(("heading_key", "l")) - r.append(":%s]"%self.master.state.limit_txt) - if self.master.stickycookie_txt: - r.append("[") - r.append(("heading_key", "t")) - r.append(":%s]"%self.master.stickycookie_txt) - if self.master.stickyauth_txt: - r.append("[") - r.append(("heading_key", "u")) - r.append(":%s]"%self.master.stickyauth_txt) - if self.master.state.default_body_view.name != "Auto": - r.append("[") - r.append(("heading_key", "M")) - r.append(":%s]"%self.master.state.default_body_view.name) - - opts = [] - if self.master.anticache: - opts.append("anticache") - if self.master.anticomp: - opts.append("anticomp") - if self.master.showhost: - opts.append("showhost") - if not self.master.refresh_server_playback: - opts.append("norefresh") - if self.master.killextra: - opts.append("killextra") - if self.master.server.config.no_upstream_cert: - opts.append("no-upstream-cert") - if self.master.state.follow_focus: - opts.append("following") - if self.master.stream_large_bodies: - opts.append("stream:%s" % utils.pretty_size(self.master.stream_large_bodies.max_size)) - - if opts: - r.append("[%s]"%(":".join(opts))) - - if self.master.server.config.mode in ["reverse", "upstream"]: - dst = self.master.server.config.mode.dst - scheme = "https" if dst[0] else "http" - if dst[1] != dst[0]: - scheme += "2https" if dst[1] else "http" - r.append("[dest:%s]"%utils.unparse_url(scheme, *dst[2:])) - if self.master.scripts: - r.append("[") - r.append(("heading_key", "s")) - r.append("cripts:%s]"%len(self.master.scripts)) - # r.append("[lt:%0.3f]"%self.master.looptime) - - if self.master.stream: - r.append("[W:%s]"%self.master.stream_path) - - return r - - def redraw(self): - if self.ab.expire and time.time() > self.ab.expire: - self.message("") - - fc = self.master.state.flow_count() - if self.master.state.focus is None: - offset = 0 - else: - offset = min(self.master.state.focus + 1, fc) - t = [ - ('heading', ("[%s/%s]"%(offset, fc)).ljust(9)) - ] - - if self.master.server.bound: - host = self.master.server.address.host - if host == "0.0.0.0": - host = "*" - boundaddr = "[%s:%s]"%(host, self.master.server.address.port) - else: - boundaddr = "" - t.extend(self.get_status()) - status = urwid.AttrWrap(urwid.Columns([ - urwid.Text(t), - urwid.Text( - [ - self.helptext, - boundaddr - ], - align="right" - ), - ]), "heading") - self.ib._w = status - - def update(self, text): - self.helptext = text - self.redraw() - self.master.loop.draw_screen() - - def selectable(self): - return True - - def get_edit_text(self): - return self.ab._w.get_edit_text() - - def path_prompt(self, prompt, text): - return self.ab.path_prompt(prompt, text) - - def prompt(self, prompt, text = ""): - self.ab.prompt(prompt, text) - - def message(self, msg, expire=None): - if expire: - expire = time.time() + float(expire)/1000 - self.ab.message(msg, expire) - self.master.loop.draw_screen() - - class ConsoleState(flow.State): def __init__(self): flow.State.__init__(self) @@ -763,7 +588,7 @@ class ConsoleMaster(flow.FlowMaster): self.help_context, (self.statusbar, self.body, self.header) ) - self.statusbar = StatusBar(self, help.footer) + self.statusbar = statusbar.StatusBar(self, help.footer) self.body = h self.header = None self.loop.widget = self.make_view() @@ -774,7 +599,7 @@ class ConsoleMaster(flow.FlowMaster): flow, (self.statusbar, self.body, self.header) ) - self.statusbar = StatusBar(self, flowdetailview.footer) + self.statusbar = statusbar.StatusBar(self, flowdetailview.footer) self.body = h self.header = None self.loop.widget = self.make_view() @@ -783,7 +608,7 @@ class ConsoleMaster(flow.FlowMaster): self.body = ge self.header = None self.help_context = ge.make_help() - self.statusbar = StatusBar(self, grideditor.footer) + self.statusbar = statusbar.StatusBar(self, grideditor.footer) self.loop.widget = self.make_view() def view_flowlist(self): @@ -796,7 +621,7 @@ class ConsoleMaster(flow.FlowMaster): self.body = flowlist.BodyPile(self) else: self.body = flowlist.FlowListBox(self) - self.statusbar = StatusBar(self, flowlist.footer) + self.statusbar = statusbar.StatusBar(self, flowlist.footer) self.header = None self.state.view_mode = common.VIEW_LIST @@ -806,7 +631,7 @@ class ConsoleMaster(flow.FlowMaster): def view_flow(self, flow): self.body = flowview.FlowView(self, self.state, flow) self.header = flowview.FlowViewHeader(self, flow) - self.statusbar = StatusBar(self, flowview.footer) + self.statusbar = statusbar.StatusBar(self, flowview.footer) self.state.set_focus_flow(flow) self.state.view_mode = common.VIEW_FLOW self.loop.widget = self.make_view() diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py new file mode 100644 index 000000000..4fb717cd8 --- /dev/null +++ b/libmproxy/console/statusbar.py @@ -0,0 +1,180 @@ + +import time + +import urwid + +from . import pathedit +from .. import utils + + +class ActionBar(urwid.WidgetWrap): + def __init__(self): + self.message("") + + def selectable(self): + return True + + def path_prompt(self, prompt, text): + self.expire = None + self._w = pathedit.PathEdit(prompt, text) + + def prompt(self, prompt, text = ""): + self.expire = None + self._w = urwid.Edit(prompt, text or "") + + def message(self, message, expire=None): + self.expire = expire + self._w = urwid.Text(message) + + +class StatusBar(urwid.WidgetWrap): + def __init__(self, master, helptext): + self.master, self.helptext = master, helptext + self.ab = ActionBar() + self.ib = urwid.WidgetWrap(urwid.Text("")) + self._w = urwid.Pile([self.ib, self.ab]) + + def get_status(self): + r = [] + + if self.master.setheaders.count(): + r.append("[") + r.append(("heading_key", "H")) + r.append("eaders]") + if self.master.replacehooks.count(): + r.append("[") + r.append(("heading_key", "R")) + r.append("eplacing]") + if self.master.client_playback: + r.append("[") + r.append(("heading_key", "cplayback")) + r.append(":%s to go]"%self.master.client_playback.count()) + if self.master.server_playback: + r.append("[") + r.append(("heading_key", "splayback")) + if self.master.nopop: + r.append(":%s in file]"%self.master.server_playback.count()) + else: + r.append(":%s to go]"%self.master.server_playback.count()) + if self.master.get_ignore_filter(): + r.append("[") + r.append(("heading_key", "I")) + r.append("gnore:%d]" % len(self.master.get_ignore_filter())) + if self.master.get_tcp_filter(): + r.append("[") + r.append(("heading_key", "T")) + r.append("CP:%d]" % len(self.master.get_tcp_filter())) + if self.master.state.intercept_txt: + r.append("[") + r.append(("heading_key", "i")) + r.append(":%s]"%self.master.state.intercept_txt) + if self.master.state.limit_txt: + r.append("[") + r.append(("heading_key", "l")) + r.append(":%s]"%self.master.state.limit_txt) + if self.master.stickycookie_txt: + r.append("[") + r.append(("heading_key", "t")) + r.append(":%s]"%self.master.stickycookie_txt) + if self.master.stickyauth_txt: + r.append("[") + r.append(("heading_key", "u")) + r.append(":%s]"%self.master.stickyauth_txt) + if self.master.state.default_body_view.name != "Auto": + r.append("[") + r.append(("heading_key", "M")) + r.append(":%s]"%self.master.state.default_body_view.name) + + opts = [] + if self.master.anticache: + opts.append("anticache") + if self.master.anticomp: + opts.append("anticomp") + if self.master.showhost: + opts.append("showhost") + if not self.master.refresh_server_playback: + opts.append("norefresh") + if self.master.killextra: + opts.append("killextra") + if self.master.server.config.no_upstream_cert: + opts.append("no-upstream-cert") + if self.master.state.follow_focus: + opts.append("following") + if self.master.stream_large_bodies: + opts.append("stream:%s" % utils.pretty_size(self.master.stream_large_bodies.max_size)) + + if opts: + r.append("[%s]"%(":".join(opts))) + + if self.master.server.config.mode in ["reverse", "upstream"]: + dst = self.master.server.config.mode.dst + scheme = "https" if dst[0] else "http" + if dst[1] != dst[0]: + scheme += "2https" if dst[1] else "http" + r.append("[dest:%s]"%utils.unparse_url(scheme, *dst[2:])) + if self.master.scripts: + r.append("[") + r.append(("heading_key", "s")) + r.append("cripts:%s]"%len(self.master.scripts)) + # r.append("[lt:%0.3f]"%self.master.looptime) + + if self.master.stream: + r.append("[W:%s]"%self.master.stream_path) + + return r + + def redraw(self): + if self.ab.expire and time.time() > self.ab.expire: + self.message("") + + fc = self.master.state.flow_count() + if self.master.state.focus is None: + offset = 0 + else: + offset = min(self.master.state.focus + 1, fc) + t = [ + ('heading', ("[%s/%s]"%(offset, fc)).ljust(9)) + ] + + if self.master.server.bound: + host = self.master.server.address.host + if host == "0.0.0.0": + host = "*" + boundaddr = "[%s:%s]"%(host, self.master.server.address.port) + else: + boundaddr = "" + t.extend(self.get_status()) + status = urwid.AttrWrap(urwid.Columns([ + urwid.Text(t), + urwid.Text( + [ + self.helptext, + boundaddr + ], + align="right" + ), + ]), "heading") + self.ib._w = status + + def update(self, text): + self.helptext = text + self.redraw() + self.master.loop.draw_screen() + + def selectable(self): + return True + + def get_edit_text(self): + return self.ab._w.get_edit_text() + + def path_prompt(self, prompt, text): + return self.ab.path_prompt(prompt, text) + + def prompt(self, prompt, text = ""): + self.ab.prompt(prompt, text) + + def message(self, msg, expire=None): + if expire: + expire = time.time() + float(expire)/1000 + self.ab.message(msg, expire) + self.master.loop.draw_screen() From c182133d645a07b7dee4504ecf6f99cc3f72f93a Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 20 Mar 2015 13:26:08 +1300 Subject: [PATCH 013/170] console: pull primary window frame management out into window.py --- libmproxy/console/__init__.py | 152 +-------------------------------- libmproxy/console/statusbar.py | 3 + libmproxy/console/window.py | 150 ++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 148 deletions(-) create mode 100644 libmproxy/console/window.py diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 5f564a20b..426dda58f 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -15,7 +15,7 @@ import urwid import weakref from .. import controller, flow, script -from . import flowlist, flowview, help, common +from . import flowlist, flowview, help, common, window from . import grideditor, palettes, contentview, flowdetailview, statusbar EVENTLOG_SIZE = 500 @@ -146,7 +146,6 @@ class ConsoleMaster(flow.FlowMaster): def __init__(self, server, options): flow.FlowMaster.__init__(self, server, ConsoleState()) - self.looptime = 0 self.stream_path = None self.options = options @@ -363,149 +362,6 @@ class ConsoleMaster(flow.FlowMaster): def set_palette(self, name): self.palette = palettes.palettes[name] - def input_filter(self, keys, raw): - for k in keys: - if self.prompting: - if k == "esc": - self.prompt_cancel() - elif self.onekey: - if k == "enter": - self.prompt_cancel() - elif k in self.onekey: - self.prompt_execute(k) - elif k == "enter": - self.prompt_execute() - else: - if common.is_keypress(k): - self.view.keypress(self.loop.screen_size, k) - else: - k = self.view.keypress(self.loop.screen_size, k) - if k: - self.statusbar.message("") - if k == "?": - self.view_help() - elif k == "c": - if not self.client_playback: - self.path_prompt( - "Client replay: ", - self.state.last_saveload, - self.client_playback_path - ) - else: - self.prompt_onekey( - "Stop current client replay?", - ( - ("yes", "y"), - ("no", "n"), - ), - self.stop_client_playback_prompt, - ) - elif k == "H": - self.view_grideditor( - grideditor.SetHeadersEditor( - self, - self.setheaders.get_specs(), - self.setheaders.set - ) - ) - elif k == "I": - self.view_grideditor( - grideditor.HostPatternEditor( - self, - [[x] for x in self.get_ignore_filter()], - self.edit_ignore_filter - ) - ) - elif k == "T": - self.view_grideditor( - grideditor.HostPatternEditor( - self, - [[x] for x in self.get_tcp_filter()], - self.edit_tcp_filter - ) - ) - elif k == "i": - self.prompt( - "Intercept filter: ", - self.state.intercept_txt, - self.set_intercept - ) - elif k == "Q": - raise urwid.ExitMainLoop - elif k == "q": - self.prompt_onekey( - "Quit", - ( - ("yes", "y"), - ("no", "n"), - ), - self.quit, - ) - elif k == "M": - self.prompt_onekey( - "Global default display mode", - contentview.view_prompts, - self.change_default_display_mode - ) - elif k == "R": - self.view_grideditor( - grideditor.ReplaceEditor( - self, - self.replacehooks.get_specs(), - self.replacehooks.set - ) - ) - elif k == "s": - self.view_grideditor( - grideditor.ScriptEditor( - self, - [[i.command] for i in self.scripts], - self.edit_scripts - ) - ) - elif k == "S": - if not self.server_playback: - self.path_prompt( - "Server replay path: ", - self.state.last_saveload, - self.server_playback_path - ) - else: - self.prompt_onekey( - "Stop current server replay?", - ( - ("yes", "y"), - ("no", "n"), - ), - self.stop_server_playback_prompt, - ) - elif k == "o": - self.prompt_onekey( - "Options", - ( - ("anticache", "a"), - ("anticomp", "c"), - ("showhost", "h"), - ("killextra", "k"), - ("norefresh", "n"), - ("no-upstream-certs", "u"), - ), - self._change_options - ) - elif k == "t": - self.prompt( - "Sticky cookie filter: ", - self.stickycookie_txt, - self.set_stickycookie - ) - elif k == "u": - self.prompt( - "Sticky auth filter: ", - self.stickyauth_txt, - self.set_stickyauth - ) - self.statusbar.redraw() - def ticker(self, *userdata): changed = self.tick(self.masterq, timeout=0) if changed: @@ -528,7 +384,6 @@ class ConsoleMaster(flow.FlowMaster): self.loop = urwid.MainLoop( self.view, screen = self.ui, - input_filter = self.input_filter ) self.view_flowlist() self.statusbar.redraw() @@ -574,12 +429,13 @@ class ConsoleMaster(flow.FlowMaster): self.shutdown() def make_view(self): - self.view = urwid.Frame( + self.view = window.Window( + self, self.body, header = self.header, footer = self.statusbar ) - self.view.set_focus("body") + self.statusbar.redraw() return self.view def view_help(self): diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py index 4fb717cd8..a38615b4b 100644 --- a/libmproxy/console/statusbar.py +++ b/libmproxy/console/statusbar.py @@ -34,6 +34,9 @@ class StatusBar(urwid.WidgetWrap): self.ib = urwid.WidgetWrap(urwid.Text("")) self._w = urwid.Pile([self.ib, self.ab]) + def keypress(self, *args, **kwargs): + return self.ab.keypress(*args, **kwargs) + def get_status(self): r = [] diff --git a/libmproxy/console/window.py b/libmproxy/console/window.py new file mode 100644 index 000000000..8019adcee --- /dev/null +++ b/libmproxy/console/window.py @@ -0,0 +1,150 @@ +import urwid + +class Window(urwid.Frame): + def __init__(self, master, body, header, footer): + urwid.Frame.__init__(self, body, header=header, footer=footer) + self.master = master + + def keypress(self, size, k): + if self.master.prompting: + if k == "esc": + self.master.prompt_cancel() + elif self.master.onekey: + if k == "enter": + self.master.prompt_cancel() + elif k in self.master.onekey: + self.master.prompt_execute(k) + elif k == "enter": + self.master.prompt_execute() + else: + if common.is_keypress(k): + urwid.Frame.keypress(self, self.master.loop.screen_size, k) + else: + return k + else: + k = urwid.Frame.keypress(self, self.master.loop.screen_size, k) + if k == "?": + self.master.view_help() + elif k == "c": + if not self.master.client_playback: + self.master.path_prompt( + "Client replay: ", + self.master.state.last_saveload, + self.master.client_playback_path + ) + else: + self.master.prompt_onekey( + "Stop current client replay?", + ( + ("yes", "y"), + ("no", "n"), + ), + self.master.stop_client_playback_prompt, + ) + elif k == "H": + self.master.view_grideditor( + grideditor.SetHeadersEditor( + self.master, + self.master.setheaders.get_specs(), + self.master.setheaders.set + ) + ) + elif k == "I": + self.master.view_grideditor( + grideditor.HostPatternEditor( + self.master, + [[x] for x in self.master.get_ignore_filter()], + self.master.edit_ignore_filter + ) + ) + elif k == "T": + self.master.view_grideditor( + grideditor.HostPatternEditor( + self.master, + [[x] for x in self.master.get_tcp_filter()], + self.master.edit_tcp_filter + ) + ) + elif k == "i": + self.master.prompt( + "Intercept filter: ", + self.master.state.intercept_txt, + self.master.set_intercept + ) + elif k == "Q": + raise urwid.ExitMainLoop + elif k == "q": + self.master.prompt_onekey( + "Quit", + ( + ("yes", "y"), + ("no", "n"), + ), + self.master.quit, + ) + elif k == "M": + self.master.prompt_onekey( + "Global default display mode", + contentview.view_prompts, + self.master.change_default_display_mode + ) + elif k == "R": + self.master.view_grideditor( + grideditor.ReplaceEditor( + self.master, + self.master.replacehooks.get_specs(), + self.master.replacehooks.set + ) + ) + elif k == "s": + self.master.view_grideditor( + grideditor.ScriptEditor( + self.master, + [[i.command] for i in self.master.scripts], + self.master.edit_scripts + ) + ) + elif k == "S": + if not self.master.server_playback: + self.master.path_prompt( + "Server replay path: ", + self.master.state.last_saveload, + self.master.server_playback_path + ) + else: + self.master.prompt_onekey( + "Stop current server replay?", + ( + ("yes", "y"), + ("no", "n"), + ), + self.master.stop_server_playback_prompt, + ) + elif k == "o": + self.master.prompt_onekey( + "Options", + ( + ("anticache", "a"), + ("anticomp", "c"), + ("showhost", "h"), + ("killextra", "k"), + ("norefresh", "n"), + ("no-upstream-certs", "u"), + ), + self.master._change_options + ) + elif k == "t": + self.master.prompt( + "Sticky cookie filter: ", + self.master.stickycookie_txt, + self.master.set_stickycookie + ) + elif k == "u": + self.master.prompt( + "Sticky auth filter: ", + self.master.stickyauth_txt, + self.master.set_stickyauth + ) + else: + return k + self.footer.redraw() From b475c8d6eacd0d6a100cf6aaddc9c9915fdfb149 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 20 Mar 2015 15:22:05 +1300 Subject: [PATCH 014/170] Add window.py import missed in refactoring --- libmproxy/console/window.py | 1 + 1 file changed, 1 insertion(+) diff --git a/libmproxy/console/window.py b/libmproxy/console/window.py index 8019adcee..69f351838 100644 --- a/libmproxy/console/window.py +++ b/libmproxy/console/window.py @@ -1,4 +1,5 @@ import urwid +from . import common class Window(urwid.Frame): def __init__(self, master, body, header, footer): From 8725d50d03cf21b37a78c1d2fa03ade055c8a821 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 21 Mar 2015 11:19:20 +1300 Subject: [PATCH 015/170] Add blinker dependency, start using it to refactor console app Blinker lets us set up a central pub/sub mechanism to disentangle our object structure. --- libmproxy/console/__init__.py | 22 ++++++++++++---------- libmproxy/console/common.py | 11 ++++++----- libmproxy/console/flowlist.py | 10 +++++----- libmproxy/console/flowview.py | 24 ++++++++++++------------ libmproxy/console/grideditor.py | 8 ++++---- libmproxy/console/signals.py | 4 ++++ libmproxy/console/statusbar.py | 19 +++++-------------- libmproxy/console/window.py | 2 +- setup.py | 3 ++- 9 files changed, 51 insertions(+), 52 deletions(-) create mode 100644 libmproxy/console/signals.py diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 426dda58f..b5c59ecf6 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -15,7 +15,7 @@ import urwid import weakref from .. import controller, flow, script -from . import flowlist, flowview, help, common, window +from . import flowlist, flowview, help, common, window, signals from . import grideditor, palettes, contentview, flowdetailview, statusbar EVENTLOG_SIZE = 500 @@ -238,7 +238,9 @@ class ConsoleMaster(flow.FlowMaster): try: s = script.Script(command, self) except script.ScriptError, v: - self.statusbar.message("Error loading script.") + signals.status_message.send( + message = "Error loading script." + ) self.add_event("Error loading script:\n%s"%v.args[0], "error") return @@ -257,7 +259,7 @@ class ConsoleMaster(flow.FlowMaster): return ret = self.load_script(command) if ret: - self.statusbar.message(ret) + signals.status_message.send(message=ret) self.state.last_script = command def toggle_eventlog(self): @@ -279,7 +281,7 @@ class ConsoleMaster(flow.FlowMaster): print >> sys.stderr, e.strerror sys.exit(1) else: - self.statusbar.message(e.strerror) + signals.status_message.send(message=e.strerror) return None def client_playback_path(self, path): @@ -314,7 +316,7 @@ class ConsoleMaster(flow.FlowMaster): try: subprocess.call(cmd) except: - self.statusbar.message("Can't start editor: %s" % " ".join(c)) + signals.status_message.send(message="Can't start editor: %s" % " ".join(c)) else: data = open(name, "rb").read() self.ui.start() @@ -353,8 +355,8 @@ class ConsoleMaster(flow.FlowMaster): try: subprocess.call(cmd, shell=shell) except: - self.statusbar.message( - "Can't start external viewer: %s" % " ".join(c) + signals.status_message.send( + message="Can't start external viewer: %s" % " ".join(c) ) self.ui.start() os.unlink(name) @@ -505,7 +507,7 @@ class ConsoleMaster(flow.FlowMaster): fw.add(i) f.close() except IOError, v: - self.statusbar.message(v.strerror) + signals.status_message.send(message=v.strerror) def save_one_flow(self, path, flow): return self._write_flows(path, [flow]) @@ -565,7 +567,7 @@ class ConsoleMaster(flow.FlowMaster): self.prompting = False self.onekey = False self.view.set_focus("body") - self.statusbar.message("") + signals.status_message.send(message="") def prompt_execute(self, txt=None): if not txt: @@ -574,7 +576,7 @@ class ConsoleMaster(flow.FlowMaster): self.prompt_done() msg = p(txt, *args) if msg: - self.statusbar.message(msg, 1000) + signals.status_message.send(message=msg, expire=1000) def prompt_cancel(self): self.prompt_done() diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 90204d79f..9731b6824 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -6,6 +6,7 @@ import os from .. import utils from ..protocol.http import CONTENT_MISSING, decoded +from . import signals try: import pyperclip @@ -198,7 +199,7 @@ def save_data(path, data, master, state): with file(path, "wb") as f: f.write(data) except IOError, v: - master.statusbar.message(v.strerror) + signals.status_message.send(message=v.strerror) def ask_save_path(prompt, data, master, state): @@ -248,11 +249,11 @@ def copy_flow(part, scope, flow, master, state): if not data: if scope == "q": - master.statusbar.message("No request content to copy.") + signals.status_message.send(message="No request content to copy.") elif scope == "s": - master.statusbar.message("No response content to copy.") + signals.status_message.send(message="No response content to copy.") else: - master.statusbar.message("No contents to copy.") + signals.status_message.send(message="No contents to copy.") return try: @@ -336,7 +337,7 @@ def ask_save_body(part, master, state, flow): state ) else: - master.statusbar.message("No content to save.") + signals.status_message.send(message="No content to save.") class FlowCache: diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index 5d8ad9423..c8ecf15c9 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import urwid from netlib import http -from . import common +from . import common, signals def _mkhelp(): @@ -171,7 +171,7 @@ class ConnectionItem(urwid.WidgetWrap): elif key == "r": r = self.master.replay_request(self.flow) if r: - self.master.statusbar.message(r) + signals.status_message.send(message=r) self.master.sync_list_view() elif key == "S": if not self.master.server_playback: @@ -195,11 +195,11 @@ class ConnectionItem(urwid.WidgetWrap): ) elif key == "V": if not self.flow.modified(): - self.master.statusbar.message("Flow not modified.") + signals.status_message.send(message="Flow not modified.") return self.state.revert(self.flow) self.master.sync_list_view() - self.master.statusbar.message("Reverted.") + signals.status_message.send(message="Reverted.") elif key == "w": self.master.prompt_onekey( "Save", @@ -285,7 +285,7 @@ class FlowListBox(urwid.ListBox): def new_request(self, url, method): parts = http.parse_url(str(url)) if not parts: - self.master.statusbar.message("Invalid Url") + signals.status_message.send(message="Invalid Url") return scheme, host, port, path = parts f = self.master.create_request(method, scheme, host, port, path) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 89e75aadf..b22bbb374 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import os, sys, copy import urwid -from . import common, grideditor, contentview +from . import common, grideditor, contentview, signals from .. import utils, flow, controller from ..protocol.http import HTTPRequest, HTTPResponse, CONTENT_MISSING, decoded @@ -282,10 +282,10 @@ class FlowView(urwid.WidgetWrap): if last_search_string: message = self.search(last_search_string, backwards) if message: - self.master.statusbar.message(message) + signals.status_message.send(message=message) else: message = "no previous searches have been made" - self.master.statusbar.message(message) + signals.status_message.send(message=message) return message @@ -606,7 +606,7 @@ class FlowView(urwid.WidgetWrap): else: new_flow, new_idx = self.state.get_prev(idx) if new_flow is None: - self.master.statusbar.message("No more flows!") + signals.status_message.send(message="No more flows!") return self.master.view_flow(new_flow) @@ -681,7 +681,7 @@ class FlowView(urwid.WidgetWrap): elif key == "D": f = self.master.duplicate_flow(self.flow) self.master.view_flow(f) - self.master.statusbar.message("Duplicated.") + signals.status_message.send(message="Duplicated.") elif key == "e": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: self.master.prompt_onekey( @@ -710,14 +710,14 @@ class FlowView(urwid.WidgetWrap): ) key = None elif key == "f": - self.master.statusbar.message("Loading all body data...") + signals.status_message.send(message="Loading all body data...") self.state.add_flow_setting( self.flow, (self.state.view_flow_mode, "fullcontents"), True ) self.master.refresh_flow(self.flow) - self.master.statusbar.message("") + signals.status_message.send(message="") elif key == "g": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: scope = "q" @@ -738,15 +738,15 @@ class FlowView(urwid.WidgetWrap): elif key == "r": r = self.master.replay_request(self.flow) if r: - self.master.statusbar.message(r) + signals.status_message.send(message=r) self.master.refresh_flow(self.flow) elif key == "V": if not self.flow.modified(): - self.master.statusbar.message("Flow not modified.") + signals.status_message.send(message="Flow not modified.") return self.state.revert(self.flow) self.master.refresh_flow(self.flow) - self.master.statusbar.message("Reverted.") + signals.status_message.send(message="Reverted.") elif key == "W": self.master.path_prompt( "Save this flow: ", @@ -761,7 +761,7 @@ class FlowView(urwid.WidgetWrap): if os.environ.has_key("EDITOR") or os.environ.has_key("PAGER"): self.master.spawn_external_viewer(conn.content, t) else: - self.master.statusbar.message("Error! Set $EDITOR or $PAGER.") + signals.status_message.send(message="Error! Set $EDITOR or $PAGER.") elif key == "|": self.master.path_prompt( "Send flow to script: ", self.state.last_script, @@ -785,7 +785,7 @@ class FlowView(urwid.WidgetWrap): e = conn.headers.get_first("content-encoding", "identity") if e != "identity": if not conn.decode(): - self.master.statusbar.message("Could not decode - invalid data?") + signals.status_message.send(message="Could not decode - invalid data?") else: self.master.prompt_onekey( "Select encoding: ", diff --git a/libmproxy/console/grideditor.py b/libmproxy/console/grideditor.py index fe3df5091..2d2754b11 100644 --- a/libmproxy/console/grideditor.py +++ b/libmproxy/console/grideditor.py @@ -5,7 +5,7 @@ import re import os import urwid -from . import common +from . import common, signals from .. import utils, filt, script from netlib import http_uastrings @@ -125,14 +125,14 @@ class GridWalker(urwid.ListWalker): try: val = val.decode("string-escape") except ValueError: - self.editor.master.statusbar.message( - "Invalid Python-style string encoding.", 1000 + signals.status_message.send( + self, message = "Invalid Python-style string encoding.", expure = 1000 ) return errors = self.lst[self.focus][1] emsg = self.editor.is_error(self.focus_col, val) if emsg: - self.editor.master.statusbar.message(emsg, 1000) + signals.status_message.send(message = emsg, expire = 1000) errors.add(self.focus_col) else: errors.discard(self.focus_col) diff --git a/libmproxy/console/signals.py b/libmproxy/console/signals.py new file mode 100644 index 000000000..a844ef8fa --- /dev/null +++ b/libmproxy/console/signals.py @@ -0,0 +1,4 @@ + +import blinker + +status_message = blinker.Signal() diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py index a38615b4b..7ad78f03a 100644 --- a/libmproxy/console/statusbar.py +++ b/libmproxy/console/statusbar.py @@ -3,26 +3,26 @@ import time import urwid -from . import pathedit +from . import pathedit, signals from .. import utils + class ActionBar(urwid.WidgetWrap): def __init__(self): - self.message("") + urwid.WidgetWrap.__init__(self, urwid.Text("")) + signals.status_message.connect(self.message) def selectable(self): return True def path_prompt(self, prompt, text): - self.expire = None self._w = pathedit.PathEdit(prompt, text) def prompt(self, prompt, text = ""): - self.expire = None self._w = urwid.Edit(prompt, text or "") - def message(self, message, expire=None): + def message(self, sender, message, expire=None): self.expire = expire self._w = urwid.Text(message) @@ -127,9 +127,6 @@ class StatusBar(urwid.WidgetWrap): return r def redraw(self): - if self.ab.expire and time.time() > self.ab.expire: - self.message("") - fc = self.master.state.flow_count() if self.master.state.focus is None: offset = 0 @@ -175,9 +172,3 @@ class StatusBar(urwid.WidgetWrap): def prompt(self, prompt, text = ""): self.ab.prompt(prompt, text) - - def message(self, msg, expire=None): - if expire: - expire = time.time() + float(expire)/1000 - self.ab.message(msg, expire) - self.master.loop.draw_screen() diff --git a/libmproxy/console/window.py b/libmproxy/console/window.py index 69f351838..44a5a3167 100644 --- a/libmproxy/console/window.py +++ b/libmproxy/console/window.py @@ -1,5 +1,5 @@ import urwid -from . import common +from . import common, grideditor class Window(urwid.Frame): def __init__(self, master, body, header, footer): diff --git a/setup.py b/setup.py index fd3e66576..bffce8055 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,8 @@ deps = { "pyOpenSSL>=0.14", "tornado>=4.0.2", "configargparse>=0.9.3", - "pyperclip>=1.5.8" + "pyperclip>=1.5.8", + "blinker>=1.3" } script_deps = { "mitmproxy": { From 381a56306777900153939b1b46f20e63322944c2 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 21 Mar 2015 12:37:00 +1300 Subject: [PATCH 016/170] Status bar message expiry based on signals and Urwid main loop --- libmproxy/console/__init__.py | 8 +++++++- libmproxy/console/grideditor.py | 2 +- libmproxy/console/signals.py | 1 + libmproxy/console/statusbar.py | 21 ++++++++++++++------- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index b5c59ecf6..aae7a9c42 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -212,6 +212,12 @@ class ConsoleMaster(flow.FlowMaster): if options.app: self.start_app(self.options.app_host, self.options.app_port) + signals.call_in.connect(self.sig_call_in) + + def sig_call_in(self, sender, seconds, callback, args=()): + def cb(*_): + return callback(*args) + self.loop.set_alarm_in(seconds, cb) def start_stream_to_path(self, path, mode="wb"): path = os.path.expanduser(path) @@ -576,7 +582,7 @@ class ConsoleMaster(flow.FlowMaster): self.prompt_done() msg = p(txt, *args) if msg: - signals.status_message.send(message=msg, expire=1000) + signals.status_message.send(message=msg, expire=1) def prompt_cancel(self): self.prompt_done() diff --git a/libmproxy/console/grideditor.py b/libmproxy/console/grideditor.py index 2d2754b11..0b563c527 100644 --- a/libmproxy/console/grideditor.py +++ b/libmproxy/console/grideditor.py @@ -132,7 +132,7 @@ class GridWalker(urwid.ListWalker): errors = self.lst[self.focus][1] emsg = self.editor.is_error(self.focus_col, val) if emsg: - signals.status_message.send(message = emsg, expire = 1000) + signals.status_message.send(message = emsg, expire = 1) errors.add(self.focus_col) else: errors.discard(self.focus_col) diff --git a/libmproxy/console/signals.py b/libmproxy/console/signals.py index a844ef8fa..7b0ec9375 100644 --- a/libmproxy/console/signals.py +++ b/libmproxy/console/signals.py @@ -2,3 +2,4 @@ import blinker status_message = blinker.Signal() +call_in = blinker.Signal() diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py index 7ad78f03a..a29767e45 100644 --- a/libmproxy/console/statusbar.py +++ b/libmproxy/console/statusbar.py @@ -1,4 +1,3 @@ - import time import urwid @@ -7,11 +6,14 @@ from . import pathedit, signals from .. import utils - class ActionBar(urwid.WidgetWrap): def __init__(self): - urwid.WidgetWrap.__init__(self, urwid.Text("")) - signals.status_message.connect(self.message) + urwid.WidgetWrap.__init__(self, None) + self.clear() + signals.status_message.connect(self.sig_message) + + def clear(self): + self._w = urwid.Text("") def selectable(self): return True @@ -22,9 +24,14 @@ class ActionBar(urwid.WidgetWrap): def prompt(self, prompt, text = ""): self._w = urwid.Edit(prompt, text or "") - def message(self, sender, message, expire=None): - self.expire = expire - self._w = urwid.Text(message) + def sig_message(self, sender, message, expire=None): + w = urwid.Text(message) + self._w = w + if expire: + def cb(*args): + if w == self._w: + self.clear() + signals.call_in.send(seconds=expire, callback=cb) class StatusBar(urwid.WidgetWrap): From ac5d74d42c0824b5789cc030bf39a447951e4804 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sat, 21 Mar 2015 21:55:02 +0100 Subject: [PATCH 017/170] web: fix bugs --- libmproxy/web/static/app.js | 17 ++++++++++------- web/src/js/actions.js | 1 + web/src/js/components/eventlog.js | 1 + web/src/js/components/header.js | 2 +- web/src/js/components/mainview.js | 2 ++ web/src/js/store/view.js | 8 +++----- web/src/js/utils.js | 1 + 7 files changed, 19 insertions(+), 13 deletions(-) diff --git a/libmproxy/web/static/app.js b/libmproxy/web/static/app.js index dae10a342..ef53c08f5 100644 --- a/libmproxy/web/static/app.js +++ b/libmproxy/web/static/app.js @@ -421,6 +421,7 @@ module.exports = { ConnectionActions: ConnectionActions, FlowActions: FlowActions, StoreCmds: StoreCmds, + SettingsActions: SettingsActions, Query: Query }; @@ -622,6 +623,7 @@ var common = require("./common.js"); var Query = require("../actions.js").Query; var VirtualScrollMixin = require("./virtualscroll.js"); var views = require("../store/view.js"); +var _ = require("lodash"); var LogMessage = React.createClass({displayName: "LogMessage", render: function () { @@ -775,7 +777,7 @@ var EventLog = React.createClass({displayName: "EventLog", module.exports = EventLog; -},{"../actions.js":2,"../store/view.js":19,"./common.js":4,"./virtualscroll.js":13,"react":"react"}],6:[function(require,module,exports){ +},{"../actions.js":2,"../store/view.js":19,"./common.js":4,"./virtualscroll.js":13,"lodash":"lodash","react":"react"}],6:[function(require,module,exports){ var React = require("react"); var _ = require("lodash"); @@ -1774,7 +1776,7 @@ var MainMenu = React.createClass({displayName: "MainMenu", this.setQuery(d); }, onInterceptChange: function (val) { - SettingsActions.update({intercept: val}); + actions.SettingsActions.update({intercept: val}); }, render: function () { var filter = this.getQuery()[Query.FILTER] || ""; @@ -2196,6 +2198,8 @@ var MainView = React.createClass({displayName: "MainView", actions.FlowActions.revert(flow); } break; + case toputils.Key.SHIFT: + break; default: console.debug("keydown", e.keyCode); return; @@ -4514,8 +4518,6 @@ var default_filt = function (elem) { function StoreView(store, filt, sortfun) { EventEmitter.call(this); - filt = filt || default_filt; - sortfun = sortfun || default_sort; this.store = store; @@ -4539,10 +4541,10 @@ _.extend(StoreView.prototype, EventEmitter.prototype, { this.store.removeListener("recalculate", this.recalculate); }, recalculate: function (filt, sortfun) { - filt = filt || default_filt; - sortfun = sortfun || default_sort; + filt = filt || this.filt || default_filt; + sortfun = sortfun || this.sortfun || default_sort; filt = filt.bind(this); - sortfun = sortfun.bind(this) + sortfun = sortfun.bind(this); this.filt = filt; this.sortfun = sortfun; @@ -4633,6 +4635,7 @@ var Key = { TAB: 9, SPACE: 32, BACKSPACE: 8, + SHIFT: 16 }; // Add A-Z for (var i = 65; i <= 90; i++) { diff --git a/web/src/js/actions.js b/web/src/js/actions.js index 64cd68a77..1b29438c8 100644 --- a/web/src/js/actions.js +++ b/web/src/js/actions.js @@ -117,5 +117,6 @@ module.exports = { ConnectionActions: ConnectionActions, FlowActions: FlowActions, StoreCmds: StoreCmds, + SettingsActions: SettingsActions, Query: Query }; \ No newline at end of file diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js index 23508275b..de69462bc 100644 --- a/web/src/js/components/eventlog.js +++ b/web/src/js/components/eventlog.js @@ -3,6 +3,7 @@ var common = require("./common.js"); var Query = require("../actions.js").Query; var VirtualScrollMixin = require("./virtualscroll.js"); var views = require("../store/view.js"); +var _ = require("lodash"); var LogMessage = React.createClass({ render: function () { diff --git a/web/src/js/components/header.js b/web/src/js/components/header.js index d1684fb28..eca06e748 100644 --- a/web/src/js/components/header.js +++ b/web/src/js/components/header.js @@ -173,7 +173,7 @@ var MainMenu = React.createClass({ this.setQuery(d); }, onInterceptChange: function (val) { - SettingsActions.update({intercept: val}); + actions.SettingsActions.update({intercept: val}); }, render: function () { var filter = this.getQuery()[Query.FILTER] || ""; diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js index 184ef49ff..8eda2e9cf 100644 --- a/web/src/js/components/mainview.js +++ b/web/src/js/components/mainview.js @@ -203,6 +203,8 @@ var MainView = React.createClass({ actions.FlowActions.revert(flow); } break; + case toputils.Key.SHIFT: + break; default: console.debug("keydown", e.keyCode); return; diff --git a/web/src/js/store/view.js b/web/src/js/store/view.js index 204d22da5..d13822d55 100644 --- a/web/src/js/store/view.js +++ b/web/src/js/store/view.js @@ -14,8 +14,6 @@ var default_filt = function (elem) { function StoreView(store, filt, sortfun) { EventEmitter.call(this); - filt = filt || default_filt; - sortfun = sortfun || default_sort; this.store = store; @@ -39,10 +37,10 @@ _.extend(StoreView.prototype, EventEmitter.prototype, { this.store.removeListener("recalculate", this.recalculate); }, recalculate: function (filt, sortfun) { - filt = filt || default_filt; - sortfun = sortfun || default_sort; + filt = filt || this.filt || default_filt; + sortfun = sortfun || this.sortfun || default_sort; filt = filt.bind(this); - sortfun = sortfun.bind(this) + sortfun = sortfun.bind(this); this.filt = filt; this.sortfun = sortfun; diff --git a/web/src/js/utils.js b/web/src/js/utils.js index bcd3958d8..48f698809 100644 --- a/web/src/js/utils.js +++ b/web/src/js/utils.js @@ -15,6 +15,7 @@ var Key = { TAB: 9, SPACE: 32, BACKSPACE: 8, + SHIFT: 16 }; // Add A-Z for (var i = 65; i <= 90; i++) { From 02a61ea45dc1ca6d0c88b44adf83f68b791130e7 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sat, 21 Mar 2015 22:49:51 +0100 Subject: [PATCH 018/170] structure components --- libmproxy/protocol/http.py | 2 + libmproxy/web/static/app.js | 873 +++++++++++---------- web/src/js/components/flowdetail.js | 399 ---------- web/src/js/components/flowview/details.js | 181 +++++ web/src/js/components/flowview/index.js | 74 ++ web/src/js/components/flowview/messages.js | 102 +++ web/src/js/components/flowview/nav.js | 61 ++ web/src/js/components/mainview.js | 4 +- web/src/js/flow/utils.js | 12 +- 9 files changed, 877 insertions(+), 831 deletions(-) delete mode 100644 web/src/js/components/flowdetail.js create mode 100644 web/src/js/components/flowview/details.js create mode 100644 web/src/js/components/flowview/index.js create mode 100644 web/src/js/components/flowview/messages.js create mode 100644 web/src/js/components/flowview/nav.js diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 49310ec3f..00086c211 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -119,6 +119,8 @@ class HTTPMessage(stateobject.StateObject): if short: if self.content: ret["contentLength"] = len(self.content) + elif self.content == CONTENT_MISSING: + ret["contentLength"] = None else: ret["contentLength"] = 0 return ret diff --git a/libmproxy/web/static/app.js b/libmproxy/web/static/app.js index ef53c08f5..04d6f2824 100644 --- a/libmproxy/web/static/app.js +++ b/libmproxy/web/static/app.js @@ -443,7 +443,7 @@ $(function () { -},{"./components/proxyapp.js":12,"./connection":14,"jquery":"jquery","react":"react","react-router":"react-router"}],4:[function(require,module,exports){ +},{"./components/proxyapp.js":15,"./connection":17,"jquery":"jquery","react":"react","react-router":"react-router"}],4:[function(require,module,exports){ var React = require("react"); var ReactRouter = require("react-router"); var _ = require("lodash"); @@ -777,408 +777,7 @@ var EventLog = React.createClass({displayName: "EventLog", module.exports = EventLog; -},{"../actions.js":2,"../store/view.js":19,"./common.js":4,"./virtualscroll.js":13,"lodash":"lodash","react":"react"}],6:[function(require,module,exports){ -var React = require("react"); -var _ = require("lodash"); - -var common = require("./common.js"); -var actions = require("../actions.js"); -var flowutils = require("../flow/utils.js"); -var toputils = require("../utils.js"); - -var NavAction = React.createClass({displayName: "NavAction", - onClick: function (e) { - e.preventDefault(); - this.props.onClick(); - }, - render: function () { - return ( - React.createElement("a", {title: this.props.title, - href: "#", - className: "nav-action", - onClick: this.onClick}, - React.createElement("i", {className: "fa fa-fw " + this.props.icon}) - ) - ); - } -}); - -var FlowDetailNav = React.createClass({displayName: "FlowDetailNav", - render: function () { - var flow = this.props.flow; - - var tabs = this.props.tabs.map(function (e) { - var str = e.charAt(0).toUpperCase() + e.slice(1); - var className = this.props.active === e ? "active" : ""; - var onClick = function (event) { - this.props.selectTab(e); - event.preventDefault(); - }.bind(this); - return React.createElement("a", {key: e, - href: "#", - className: className, - onClick: onClick}, str); - }.bind(this)); - - var acceptButton = null; - if(flow.intercepted){ - acceptButton = React.createElement(NavAction, {title: "[a]ccept intercepted flow", icon: "fa-play", onClick: actions.FlowActions.accept.bind(null, flow)}); - } - var revertButton = null; - if(flow.modified){ - revertButton = React.createElement(NavAction, {title: "revert changes to flow [V]", icon: "fa-history", onClick: actions.FlowActions.revert.bind(null, flow)}); - } - - return ( - React.createElement("nav", {ref: "head", className: "nav-tabs nav-tabs-sm"}, - tabs, - React.createElement(NavAction, {title: "[d]elete flow", icon: "fa-trash", onClick: actions.FlowActions.delete.bind(null, flow)}), - React.createElement(NavAction, {title: "[D]uplicate flow", icon: "fa-copy", onClick: actions.FlowActions.duplicate.bind(null, flow)}), - React.createElement(NavAction, {disabled: true, title: "[r]eplay flow", icon: "fa-repeat", onClick: actions.FlowActions.replay.bind(null, flow)}), - acceptButton, - revertButton - ) - ); - } -}); - -var Headers = React.createClass({displayName: "Headers", - render: function () { - var rows = this.props.message.headers.map(function (header, i) { - return ( - React.createElement("tr", {key: i}, - React.createElement("td", {className: "header-name"}, header[0] + ":"), - React.createElement("td", {className: "header-value"}, header[1]) - ) - ); - }); - return ( - React.createElement("table", {className: "header-table"}, - React.createElement("tbody", null, - rows - ) - ) - ); - } -}); - -var FlowDetailRequest = React.createClass({displayName: "FlowDetailRequest", - render: function () { - var flow = this.props.flow; - var first_line = [ - flow.request.method, - flowutils.RequestUtils.pretty_url(flow.request), - "HTTP/" + flow.request.httpversion.join(".") - ].join(" "); - var content = null; - if (flow.request.contentLength > 0) { - content = "Request Content Size: " + toputils.formatSize(flow.request.contentLength); - } else { - content = React.createElement("div", {className: "alert alert-info"}, "No Content"); - } - - //TODO: Styling - - return ( - React.createElement("section", null, - React.createElement("div", {className: "first-line"}, first_line ), - React.createElement(Headers, {message: flow.request}), - React.createElement("hr", null), - content - ) - ); - } -}); - -var FlowDetailResponse = React.createClass({displayName: "FlowDetailResponse", - render: function () { - var flow = this.props.flow; - var first_line = [ - "HTTP/" + flow.response.httpversion.join("."), - flow.response.code, - flow.response.msg - ].join(" "); - var content = null; - if (flow.response.contentLength > 0) { - content = "Response Content Size: " + toputils.formatSize(flow.response.contentLength); - } else { - content = React.createElement("div", {className: "alert alert-info"}, "No Content"); - } - - //TODO: Styling - - return ( - React.createElement("section", null, - React.createElement("div", {className: "first-line"}, first_line ), - React.createElement(Headers, {message: flow.response}), - React.createElement("hr", null), - content - ) - ); - } -}); - -var FlowDetailError = React.createClass({displayName: "FlowDetailError", - render: function () { - var flow = this.props.flow; - return ( - React.createElement("section", null, - React.createElement("div", {className: "alert alert-warning"}, - flow.error.msg, - React.createElement("div", null, - React.createElement("small", null, toputils.formatTimeStamp(flow.error.timestamp) ) - ) - ) - ) - ); - } -}); - -var TimeStamp = React.createClass({displayName: "TimeStamp", - render: function () { - - if (!this.props.t) { - //should be return null, but that triggers a React bug. - return React.createElement("tr", null); - } - - var ts = toputils.formatTimeStamp(this.props.t); - - var delta; - if (this.props.deltaTo) { - delta = toputils.formatTimeDelta(1000 * (this.props.t - this.props.deltaTo)); - delta = React.createElement("span", {className: "text-muted"}, "(" + delta + ")"); - } else { - delta = null; - } - - return React.createElement("tr", null, - React.createElement("td", null, this.props.title + ":"), - React.createElement("td", null, ts, " ", delta) - ); - } -}); - -var ConnectionInfo = React.createClass({displayName: "ConnectionInfo", - - render: function () { - var conn = this.props.conn; - var address = conn.address.address.join(":"); - - var sni = React.createElement("tr", {key: "sni"}); //should be null, but that triggers a React bug. - if (conn.sni) { - sni = React.createElement("tr", {key: "sni"}, - React.createElement("td", null, - React.createElement("abbr", {title: "TLS Server Name Indication"}, "TLS SNI:") - ), - React.createElement("td", null, conn.sni) - ); - } - return ( - React.createElement("table", {className: "connection-table"}, - React.createElement("tbody", null, - React.createElement("tr", {key: "address"}, - React.createElement("td", null, "Address:"), - React.createElement("td", null, address) - ), - sni - ) - ) - ); - } -}); - -var CertificateInfo = React.createClass({displayName: "CertificateInfo", - render: function () { - //TODO: We should fetch human-readable certificate representation - // from the server - var flow = this.props.flow; - var client_conn = flow.client_conn; - var server_conn = flow.server_conn; - - var preStyle = {maxHeight: 100}; - return ( - React.createElement("div", null, - client_conn.cert ? React.createElement("h4", null, "Client Certificate") : null, - client_conn.cert ? React.createElement("pre", {style: preStyle}, client_conn.cert) : null, - - server_conn.cert ? React.createElement("h4", null, "Server Certificate") : null, - server_conn.cert ? React.createElement("pre", {style: preStyle}, server_conn.cert) : null - ) - ); - } -}); - -var Timing = React.createClass({displayName: "Timing", - render: function () { - var flow = this.props.flow; - var sc = flow.server_conn; - var cc = flow.client_conn; - var req = flow.request; - var resp = flow.response; - - var timestamps = [ - { - title: "Server conn. initiated", - t: sc.timestamp_start, - deltaTo: req.timestamp_start - }, { - title: "Server conn. TCP handshake", - t: sc.timestamp_tcp_setup, - deltaTo: req.timestamp_start - }, { - title: "Server conn. SSL handshake", - t: sc.timestamp_ssl_setup, - deltaTo: req.timestamp_start - }, { - title: "Client conn. established", - t: cc.timestamp_start, - deltaTo: req.timestamp_start - }, { - title: "Client conn. SSL handshake", - t: cc.timestamp_ssl_setup, - deltaTo: req.timestamp_start - }, { - title: "First request byte", - t: req.timestamp_start, - }, { - title: "Request complete", - t: req.timestamp_end, - deltaTo: req.timestamp_start - } - ]; - - if (flow.response) { - timestamps.push( - { - title: "First response byte", - t: resp.timestamp_start, - deltaTo: req.timestamp_start - }, { - title: "Response complete", - t: resp.timestamp_end, - deltaTo: req.timestamp_start - } - ); - } - - //Add unique key for each row. - timestamps.forEach(function (e) { - e.key = e.title; - }); - - timestamps = _.sortBy(timestamps, 't'); - - var rows = timestamps.map(function (e) { - return React.createElement(TimeStamp, React.__spread({}, e)); - }); - - return ( - React.createElement("div", null, - React.createElement("h4", null, "Timing"), - React.createElement("table", {className: "timing-table"}, - React.createElement("tbody", null, - rows - ) - ) - ) - ); - } -}); - -var FlowDetailConnectionInfo = React.createClass({displayName: "FlowDetailConnectionInfo", - render: function () { - var flow = this.props.flow; - var client_conn = flow.client_conn; - var server_conn = flow.server_conn; - return ( - React.createElement("section", null, - - React.createElement("h4", null, "Client Connection"), - React.createElement(ConnectionInfo, {conn: client_conn}), - - React.createElement("h4", null, "Server Connection"), - React.createElement(ConnectionInfo, {conn: server_conn}), - - React.createElement(CertificateInfo, {flow: flow}), - - React.createElement(Timing, {flow: flow}) - - ) - ); - } -}); - -var allTabs = { - request: FlowDetailRequest, - response: FlowDetailResponse, - error: FlowDetailError, - details: FlowDetailConnectionInfo -}; - -var FlowDetail = React.createClass({displayName: "FlowDetail", - mixins: [common.StickyHeadMixin, common.Navigation, common.State], - getTabs: function (flow) { - var tabs = []; - ["request", "response", "error"].forEach(function (e) { - if (flow[e]) { - tabs.push(e); - } - }); - tabs.push("details"); - return tabs; - }, - nextTab: function (i) { - var tabs = this.getTabs(this.props.flow); - var currentIndex = tabs.indexOf(this.getParams().detailTab); - // JS modulo operator doesn't correct negative numbers, make sure that we are positive. - var nextIndex = (currentIndex + i + tabs.length) % tabs.length; - this.selectTab(tabs[nextIndex]); - }, - selectTab: function (panel) { - this.replaceWith( - "flow", - { - flowId: this.getParams().flowId, - detailTab: panel - } - ); - }, - render: function () { - var flow = this.props.flow; - var tabs = this.getTabs(flow); - var active = this.getParams().detailTab; - - if (!_.contains(tabs, active)) { - if (active === "response" && flow.error) { - active = "error"; - } else if (active === "error" && flow.response) { - active = "response"; - } else { - active = tabs[0]; - } - this.selectTab(active); - } - - var Tab = allTabs[active]; - return ( - React.createElement("div", {className: "flow-detail", onScroll: this.adjustHead}, - React.createElement(FlowDetailNav, {ref: "head", - flow: flow, - tabs: tabs, - active: active, - selectTab: this.selectTab}), - React.createElement(Tab, {flow: flow}) - ) - ); - } -}); - -module.exports = { - FlowDetail: FlowDetail -}; - -},{"../actions.js":2,"../flow/utils.js":17,"../utils.js":20,"./common.js":4,"lodash":"lodash","react":"react"}],7:[function(require,module,exports){ +},{"../actions.js":2,"../store/view.js":22,"./common.js":4,"./virtualscroll.js":16,"lodash":"lodash","react":"react"}],6:[function(require,module,exports){ var React = require("react"); var RequestUtils = require("../flow/utils.js").RequestUtils; var ResponseUtils = require("../flow/utils.js").ResponseUtils; @@ -1381,7 +980,7 @@ var all_columns = [ module.exports = all_columns; -},{"../flow/utils.js":17,"../utils.js":20,"react":"react"}],8:[function(require,module,exports){ +},{"../flow/utils.js":20,"../utils.js":23,"react":"react"}],7:[function(require,module,exports){ var React = require("react"); var common = require("./common.js"); var utils = require("../utils.js"); @@ -1581,7 +1180,433 @@ var FlowTable = React.createClass({displayName: "FlowTable", module.exports = FlowTable; -},{"../utils.js":20,"./common.js":4,"./flowtable-columns.js":7,"./virtualscroll.js":13,"lodash":"lodash","react":"react"}],9:[function(require,module,exports){ +},{"../utils.js":23,"./common.js":4,"./flowtable-columns.js":6,"./virtualscroll.js":16,"lodash":"lodash","react":"react"}],8:[function(require,module,exports){ +var React = require("react"); +var _ = require("lodash"); + +var utils = require("../../utils.js"); + +var TimeStamp = React.createClass({displayName: "TimeStamp", + render: function () { + + if (!this.props.t) { + //should be return null, but that triggers a React bug. + return React.createElement("tr", null); + } + + var ts = utils.formatTimeStamp(this.props.t); + + var delta; + if (this.props.deltaTo) { + delta = utils.formatTimeDelta(1000 * (this.props.t - this.props.deltaTo)); + delta = React.createElement("span", {className: "text-muted"}, "(" + delta + ")"); + } else { + delta = null; + } + + return React.createElement("tr", null, + React.createElement("td", null, this.props.title + ":"), + React.createElement("td", null, ts, " ", delta) + ); + } +}); + +var ConnectionInfo = React.createClass({displayName: "ConnectionInfo", + + render: function () { + var conn = this.props.conn; + var address = conn.address.address.join(":"); + + var sni = React.createElement("tr", {key: "sni"}); //should be null, but that triggers a React bug. + if (conn.sni) { + sni = React.createElement("tr", {key: "sni"}, + React.createElement("td", null, + React.createElement("abbr", {title: "TLS Server Name Indication"}, "TLS SNI:") + ), + React.createElement("td", null, conn.sni) + ); + } + return ( + React.createElement("table", {className: "connection-table"}, + React.createElement("tbody", null, + React.createElement("tr", {key: "address"}, + React.createElement("td", null, "Address:"), + React.createElement("td", null, address) + ), + sni + ) + ) + ); + } +}); + +var CertificateInfo = React.createClass({displayName: "CertificateInfo", + render: function () { + //TODO: We should fetch human-readable certificate representation + // from the server + var flow = this.props.flow; + var client_conn = flow.client_conn; + var server_conn = flow.server_conn; + + var preStyle = {maxHeight: 100}; + return ( + React.createElement("div", null, + client_conn.cert ? React.createElement("h4", null, "Client Certificate") : null, + client_conn.cert ? React.createElement("pre", {style: preStyle}, client_conn.cert) : null, + + server_conn.cert ? React.createElement("h4", null, "Server Certificate") : null, + server_conn.cert ? React.createElement("pre", {style: preStyle}, server_conn.cert) : null + ) + ); + } +}); + +var Timing = React.createClass({displayName: "Timing", + render: function () { + var flow = this.props.flow; + var sc = flow.server_conn; + var cc = flow.client_conn; + var req = flow.request; + var resp = flow.response; + + var timestamps = [ + { + title: "Server conn. initiated", + t: sc.timestamp_start, + deltaTo: req.timestamp_start + }, { + title: "Server conn. TCP handshake", + t: sc.timestamp_tcp_setup, + deltaTo: req.timestamp_start + }, { + title: "Server conn. SSL handshake", + t: sc.timestamp_ssl_setup, + deltaTo: req.timestamp_start + }, { + title: "Client conn. established", + t: cc.timestamp_start, + deltaTo: req.timestamp_start + }, { + title: "Client conn. SSL handshake", + t: cc.timestamp_ssl_setup, + deltaTo: req.timestamp_start + }, { + title: "First request byte", + t: req.timestamp_start, + }, { + title: "Request complete", + t: req.timestamp_end, + deltaTo: req.timestamp_start + } + ]; + + if (flow.response) { + timestamps.push( + { + title: "First response byte", + t: resp.timestamp_start, + deltaTo: req.timestamp_start + }, { + title: "Response complete", + t: resp.timestamp_end, + deltaTo: req.timestamp_start + } + ); + } + + //Add unique key for each row. + timestamps.forEach(function (e) { + e.key = e.title; + }); + + timestamps = _.sortBy(timestamps, 't'); + + var rows = timestamps.map(function (e) { + return React.createElement(TimeStamp, React.__spread({}, e)); + }); + + return ( + React.createElement("div", null, + React.createElement("h4", null, "Timing"), + React.createElement("table", {className: "timing-table"}, + React.createElement("tbody", null, + rows + ) + ) + ) + ); + } +}); + +var Details = React.createClass({displayName: "Details", + render: function () { + var flow = this.props.flow; + var client_conn = flow.client_conn; + var server_conn = flow.server_conn; + return ( + React.createElement("section", null, + + React.createElement("h4", null, "Client Connection"), + React.createElement(ConnectionInfo, {conn: client_conn}), + + React.createElement("h4", null, "Server Connection"), + React.createElement(ConnectionInfo, {conn: server_conn}), + + React.createElement(CertificateInfo, {flow: flow}), + + React.createElement(Timing, {flow: flow}) + + ) + ); + } +}); + +module.exports = Details; + +},{"../../utils.js":23,"lodash":"lodash","react":"react"}],9:[function(require,module,exports){ +var React = require("react"); +var _ = require("lodash"); + +var common = require("../common.js"); +var Nav = require("./nav.js"); +var Messages = require("./messages.js"); +var Details = require("./details.js"); + +var allTabs = { + request: Messages.Request, + response: Messages.Response, + error: Messages.Error, + details: Details +}; + +var FlowView = React.createClass({displayName: "FlowView", + mixins: [common.StickyHeadMixin, common.Navigation, common.State], + getTabs: function (flow) { + var tabs = []; + ["request", "response", "error"].forEach(function (e) { + if (flow[e]) { + tabs.push(e); + } + }); + tabs.push("details"); + return tabs; + }, + nextTab: function (i) { + var tabs = this.getTabs(this.props.flow); + var currentIndex = tabs.indexOf(this.getParams().detailTab); + // JS modulo operator doesn't correct negative numbers, make sure that we are positive. + var nextIndex = (currentIndex + i + tabs.length) % tabs.length; + this.selectTab(tabs[nextIndex]); + }, + selectTab: function (panel) { + this.replaceWith( + "flow", + { + flowId: this.getParams().flowId, + detailTab: panel + } + ); + }, + render: function () { + var flow = this.props.flow; + var tabs = this.getTabs(flow); + var active = this.getParams().detailTab; + + if (!_.contains(tabs, active)) { + if (active === "response" && flow.error) { + active = "error"; + } else if (active === "error" && flow.response) { + active = "response"; + } else { + active = tabs[0]; + } + this.selectTab(active); + } + + var Tab = allTabs[active]; + return ( + React.createElement("div", {className: "flow-detail", onScroll: this.adjustHead}, + React.createElement(Nav, {ref: "head", + flow: flow, + tabs: tabs, + active: active, + selectTab: this.selectTab}), + React.createElement(Tab, {flow: flow}) + ) + ); + } +}); + +module.exports = FlowView; + +},{"../common.js":4,"./details.js":8,"./messages.js":10,"./nav.js":11,"lodash":"lodash","react":"react"}],10:[function(require,module,exports){ +var React = require("react"); + +var flowutils = require("../../flow/utils.js"); +var utils = require("../../utils.js"); + +var Headers = React.createClass({displayName: "Headers", + render: function () { + var rows = this.props.message.headers.map(function (header, i) { + return ( + React.createElement("tr", {key: i}, + React.createElement("td", {className: "header-name"}, header[0] + ":"), + React.createElement("td", {className: "header-value"}, header[1]) + ) + ); + }); + return ( + React.createElement("table", {className: "header-table"}, + React.createElement("tbody", null, + rows + ) + ) + ); + } +}); + +var Request = React.createClass({displayName: "Request", + render: function () { + var flow = this.props.flow; + var first_line = [ + flow.request.method, + flowutils.RequestUtils.pretty_url(flow.request), + "HTTP/" + flow.request.httpversion.join(".") + ].join(" "); + var content = null; + if (flow.request.contentLength > 0) { + content = "Request Content Size: " + utils.formatSize(flow.request.contentLength); + } else { + content = React.createElement("div", {className: "alert alert-info"}, "No Content"); + } + + //TODO: Styling + + return ( + React.createElement("section", null, + React.createElement("div", {className: "first-line"}, first_line ), + React.createElement(Headers, {message: flow.request}), + React.createElement("hr", null), + content + ) + ); + } +}); + +var Response = React.createClass({displayName: "Response", + render: function () { + var flow = this.props.flow; + var first_line = [ + "HTTP/" + flow.response.httpversion.join("."), + flow.response.code, + flow.response.msg + ].join(" "); + var content = null; + if (flow.response.contentLength > 0) { + content = "Response Content Size: " + utils.formatSize(flow.response.contentLength); + } else { + content = React.createElement("div", {className: "alert alert-info"}, "No Content"); + } + + //TODO: Styling + + return ( + React.createElement("section", null, + React.createElement("div", {className: "first-line"}, first_line ), + React.createElement(Headers, {message: flow.response}), + React.createElement("hr", null), + content + ) + ); + } +}); + +var Error = React.createClass({displayName: "Error", + render: function () { + var flow = this.props.flow; + return ( + React.createElement("section", null, + React.createElement("div", {className: "alert alert-warning"}, + flow.error.msg, + React.createElement("div", null, + React.createElement("small", null, utils.formatTimeStamp(flow.error.timestamp) ) + ) + ) + ) + ); + } +}); + +module.exports = { + Request: Request, + Response: Response, + Error: Error +}; + +},{"../../flow/utils.js":20,"../../utils.js":23,"react":"react"}],11:[function(require,module,exports){ +var React = require("react"); + +var actions = require("../../actions.js"); + +var NavAction = React.createClass({displayName: "NavAction", + onClick: function (e) { + e.preventDefault(); + this.props.onClick(); + }, + render: function () { + return ( + React.createElement("a", {title: this.props.title, + href: "#", + className: "nav-action", + onClick: this.onClick}, + React.createElement("i", {className: "fa fa-fw " + this.props.icon}) + ) + ); + } +}); + +var Nav = React.createClass({displayName: "Nav", + render: function () { + var flow = this.props.flow; + + var tabs = this.props.tabs.map(function (e) { + var str = e.charAt(0).toUpperCase() + e.slice(1); + var className = this.props.active === e ? "active" : ""; + var onClick = function (event) { + this.props.selectTab(e); + event.preventDefault(); + }.bind(this); + return React.createElement("a", {key: e, + href: "#", + className: className, + onClick: onClick}, str); + }.bind(this)); + + var acceptButton = null; + if(flow.intercepted){ + acceptButton = React.createElement(NavAction, {title: "[a]ccept intercepted flow", icon: "fa-play", onClick: actions.FlowActions.accept.bind(null, flow)}); + } + var revertButton = null; + if(flow.modified){ + revertButton = React.createElement(NavAction, {title: "revert changes to flow [V]", icon: "fa-history", onClick: actions.FlowActions.revert.bind(null, flow)}); + } + + return ( + React.createElement("nav", {ref: "head", className: "nav-tabs nav-tabs-sm"}, + tabs, + React.createElement(NavAction, {title: "[d]elete flow", icon: "fa-trash", onClick: actions.FlowActions.delete.bind(null, flow)}), + React.createElement(NavAction, {title: "[D]uplicate flow", icon: "fa-copy", onClick: actions.FlowActions.duplicate.bind(null, flow)}), + React.createElement(NavAction, {disabled: true, title: "[r]eplay flow", icon: "fa-repeat", onClick: actions.FlowActions.replay.bind(null, flow)}), + acceptButton, + revertButton + ) + ); + } +}); + +module.exports = Nav; + +},{"../../actions.js":2,"react":"react"}],12:[function(require,module,exports){ var React = require("react"); var Footer = React.createClass({displayName: "Footer", @@ -1600,7 +1625,7 @@ var Footer = React.createClass({displayName: "Footer", module.exports = Footer; -},{"react":"react"}],10:[function(require,module,exports){ +},{"react":"react"}],13:[function(require,module,exports){ var React = require("react"); var $ = require("jquery"); @@ -1992,7 +2017,7 @@ module.exports = { Header: Header } -},{"../actions.js":2,"../filt/filt.js":16,"../utils.js":20,"./common.js":4,"jquery":"jquery","react":"react"}],11:[function(require,module,exports){ +},{"../actions.js":2,"../filt/filt.js":19,"../utils.js":23,"./common.js":4,"jquery":"jquery","react":"react"}],14:[function(require,module,exports){ var React = require("react"); var common = require("./common.js"); @@ -2002,7 +2027,7 @@ var toputils = require("../utils.js"); var views = require("../store/view.js"); var Filt = require("../filt/filt.js"); FlowTable = require("./flowtable.js"); -var flowdetail = require("./flowdetail.js"); +var FlowView = require("./flowview/index.js"); var MainView = React.createClass({displayName: "MainView", mixins: [common.Navigation, common.State], @@ -2216,7 +2241,7 @@ var MainView = React.createClass({displayName: "MainView", if (selected) { details = [ React.createElement(common.Splitter, {key: "splitter"}), - React.createElement(flowdetail.FlowDetail, {key: "flowDetails", ref: "flowDetails", flow: selected}) + React.createElement(FlowView, {key: "flowDetails", ref: "flowDetails", flow: selected}) ]; } else { details = null; @@ -2238,7 +2263,7 @@ var MainView = React.createClass({displayName: "MainView", module.exports = MainView; -},{"../actions.js":2,"../filt/filt.js":16,"../store/view.js":19,"../utils.js":20,"./common.js":4,"./flowdetail.js":6,"./flowtable.js":8,"react":"react"}],12:[function(require,module,exports){ +},{"../actions.js":2,"../filt/filt.js":19,"../store/view.js":22,"../utils.js":23,"./common.js":4,"./flowtable.js":7,"./flowview/index.js":9,"react":"react"}],15:[function(require,module,exports){ var React = require("react"); var ReactRouter = require("react-router"); var _ = require("lodash"); @@ -2333,7 +2358,7 @@ module.exports = { routes: routes }; -},{"../actions.js":2,"../store/store.js":18,"./common.js":4,"./eventlog.js":5,"./footer.js":9,"./header.js":10,"./mainview.js":11,"lodash":"lodash","react":"react","react-router":"react-router"}],13:[function(require,module,exports){ +},{"../actions.js":2,"../store/store.js":21,"./common.js":4,"./eventlog.js":5,"./footer.js":12,"./header.js":13,"./mainview.js":14,"lodash":"lodash","react":"react","react-router":"react-router"}],16:[function(require,module,exports){ var React = require("react"); var VirtualScrollMixin = { @@ -2420,7 +2445,7 @@ var VirtualScrollMixin = { module.exports = VirtualScrollMixin; -},{"react":"react"}],14:[function(require,module,exports){ +},{"react":"react"}],17:[function(require,module,exports){ var actions = require("./actions.js"); @@ -2450,7 +2475,7 @@ function Connection(url) { module.exports = Connection; -},{"./actions.js":2}],15:[function(require,module,exports){ +},{"./actions.js":2}],18:[function(require,module,exports){ var flux = require("flux"); @@ -2474,7 +2499,7 @@ module.exports = { AppDispatcher: AppDispatcher }; -},{"flux":"flux"}],16:[function(require,module,exports){ +},{"flux":"flux"}],19:[function(require,module,exports){ module.exports = (function() { /* * Generated by PEG.js 0.8.0. @@ -4250,10 +4275,10 @@ module.exports = (function() { }; })(); -},{"../flow/utils.js":17}],17:[function(require,module,exports){ +},{"../flow/utils.js":20}],20:[function(require,module,exports){ var _ = require("lodash"); -var _MessageUtils = { +var MessageUtils = { getContentType: function (message) { return this.get_first_header(message, /^Content-Type$/i); }, @@ -4295,7 +4320,7 @@ var defaultPorts = { "https": 443 }; -var RequestUtils = _.extend(_MessageUtils, { +var RequestUtils = _.extend(MessageUtils, { pretty_host: function (request) { //FIXME: Add hostheader return request.host; @@ -4309,16 +4334,16 @@ var RequestUtils = _.extend(_MessageUtils, { } }); -var ResponseUtils = _.extend(_MessageUtils, {}); +var ResponseUtils = _.extend(MessageUtils, {}); module.exports = { ResponseUtils: ResponseUtils, - RequestUtils: RequestUtils + RequestUtils: RequestUtils, + MessageUtils: MessageUtils +}; -} - -},{"lodash":"lodash"}],18:[function(require,module,exports){ +},{"lodash":"lodash"}],21:[function(require,module,exports){ var _ = require("lodash"); var $ = require("jquery"); @@ -4501,7 +4526,7 @@ module.exports = { FlowStore: FlowStore }; -},{"../actions.js":2,"../dispatcher.js":15,"../utils.js":20,"events":1,"jquery":"jquery","lodash":"lodash"}],19:[function(require,module,exports){ +},{"../actions.js":2,"../dispatcher.js":18,"../utils.js":23,"events":1,"jquery":"jquery","lodash":"lodash"}],22:[function(require,module,exports){ var EventEmitter = require('events').EventEmitter; var _ = require("lodash"); @@ -4617,7 +4642,7 @@ module.exports = { StoreView: StoreView }; -},{"../utils.js":20,"events":1,"lodash":"lodash"}],20:[function(require,module,exports){ +},{"../utils.js":23,"events":1,"lodash":"lodash"}],23:[function(require,module,exports){ var $ = require("jquery"); var _ = require("lodash"); diff --git a/web/src/js/components/flowdetail.js b/web/src/js/components/flowdetail.js deleted file mode 100644 index 1d019ffbb..000000000 --- a/web/src/js/components/flowdetail.js +++ /dev/null @@ -1,399 +0,0 @@ -var React = require("react"); -var _ = require("lodash"); - -var common = require("./common.js"); -var actions = require("../actions.js"); -var flowutils = require("../flow/utils.js"); -var toputils = require("../utils.js"); - -var NavAction = React.createClass({ - onClick: function (e) { - e.preventDefault(); - this.props.onClick(); - }, - render: function () { - return ( - - - - ); - } -}); - -var FlowDetailNav = React.createClass({ - render: function () { - var flow = this.props.flow; - - var tabs = this.props.tabs.map(function (e) { - var str = e.charAt(0).toUpperCase() + e.slice(1); - var className = this.props.active === e ? "active" : ""; - var onClick = function (event) { - this.props.selectTab(e); - event.preventDefault(); - }.bind(this); - return {str}; - }.bind(this)); - - var acceptButton = null; - if(flow.intercepted){ - acceptButton = ; - } - var revertButton = null; - if(flow.modified){ - revertButton = ; - } - - return ( - - ); - } -}); - -var Headers = React.createClass({ - render: function () { - var rows = this.props.message.headers.map(function (header, i) { - return ( - - {header[0] + ":"} - {header[1]} - - ); - }); - return ( - - - {rows} - -
- ); - } -}); - -var FlowDetailRequest = React.createClass({ - render: function () { - var flow = this.props.flow; - var first_line = [ - flow.request.method, - flowutils.RequestUtils.pretty_url(flow.request), - "HTTP/" + flow.request.httpversion.join(".") - ].join(" "); - var content = null; - if (flow.request.contentLength > 0) { - content = "Request Content Size: " + toputils.formatSize(flow.request.contentLength); - } else { - content =
No Content
; - } - - //TODO: Styling - - return ( -
-
{ first_line }
- -
- {content} -
- ); - } -}); - -var FlowDetailResponse = React.createClass({ - render: function () { - var flow = this.props.flow; - var first_line = [ - "HTTP/" + flow.response.httpversion.join("."), - flow.response.code, - flow.response.msg - ].join(" "); - var content = null; - if (flow.response.contentLength > 0) { - content = "Response Content Size: " + toputils.formatSize(flow.response.contentLength); - } else { - content =
No Content
; - } - - //TODO: Styling - - return ( -
-
{ first_line }
- -
- {content} -
- ); - } -}); - -var FlowDetailError = React.createClass({ - render: function () { - var flow = this.props.flow; - return ( -
-
- {flow.error.msg} -
- { toputils.formatTimeStamp(flow.error.timestamp) } -
-
-
- ); - } -}); - -var TimeStamp = React.createClass({ - render: function () { - - if (!this.props.t) { - //should be return null, but that triggers a React bug. - return ; - } - - var ts = toputils.formatTimeStamp(this.props.t); - - var delta; - if (this.props.deltaTo) { - delta = toputils.formatTimeDelta(1000 * (this.props.t - this.props.deltaTo)); - delta = {"(" + delta + ")"}; - } else { - delta = null; - } - - return - {this.props.title + ":"} - {ts} {delta} - ; - } -}); - -var ConnectionInfo = React.createClass({ - - render: function () { - var conn = this.props.conn; - var address = conn.address.address.join(":"); - - var sni = ; //should be null, but that triggers a React bug. - if (conn.sni) { - sni = - - TLS SNI: - - {conn.sni} - ; - } - return ( - - - - - - - {sni} - -
Address:{address}
- ); - } -}); - -var CertificateInfo = React.createClass({ - render: function () { - //TODO: We should fetch human-readable certificate representation - // from the server - var flow = this.props.flow; - var client_conn = flow.client_conn; - var server_conn = flow.server_conn; - - var preStyle = {maxHeight: 100}; - return ( -
- {client_conn.cert ?

Client Certificate

: null} - {client_conn.cert ?
{client_conn.cert}
: null} - - {server_conn.cert ?

Server Certificate

: null} - {server_conn.cert ?
{server_conn.cert}
: null} -
- ); - } -}); - -var Timing = React.createClass({ - render: function () { - var flow = this.props.flow; - var sc = flow.server_conn; - var cc = flow.client_conn; - var req = flow.request; - var resp = flow.response; - - var timestamps = [ - { - title: "Server conn. initiated", - t: sc.timestamp_start, - deltaTo: req.timestamp_start - }, { - title: "Server conn. TCP handshake", - t: sc.timestamp_tcp_setup, - deltaTo: req.timestamp_start - }, { - title: "Server conn. SSL handshake", - t: sc.timestamp_ssl_setup, - deltaTo: req.timestamp_start - }, { - title: "Client conn. established", - t: cc.timestamp_start, - deltaTo: req.timestamp_start - }, { - title: "Client conn. SSL handshake", - t: cc.timestamp_ssl_setup, - deltaTo: req.timestamp_start - }, { - title: "First request byte", - t: req.timestamp_start, - }, { - title: "Request complete", - t: req.timestamp_end, - deltaTo: req.timestamp_start - } - ]; - - if (flow.response) { - timestamps.push( - { - title: "First response byte", - t: resp.timestamp_start, - deltaTo: req.timestamp_start - }, { - title: "Response complete", - t: resp.timestamp_end, - deltaTo: req.timestamp_start - } - ); - } - - //Add unique key for each row. - timestamps.forEach(function (e) { - e.key = e.title; - }); - - timestamps = _.sortBy(timestamps, 't'); - - var rows = timestamps.map(function (e) { - return ; - }); - - return ( -
-

Timing

- - - {rows} - -
-
- ); - } -}); - -var FlowDetailConnectionInfo = React.createClass({ - render: function () { - var flow = this.props.flow; - var client_conn = flow.client_conn; - var server_conn = flow.server_conn; - return ( -
- -

Client Connection

- - -

Server Connection

- - - - - - -
- ); - } -}); - -var allTabs = { - request: FlowDetailRequest, - response: FlowDetailResponse, - error: FlowDetailError, - details: FlowDetailConnectionInfo -}; - -var FlowDetail = React.createClass({ - mixins: [common.StickyHeadMixin, common.Navigation, common.State], - getTabs: function (flow) { - var tabs = []; - ["request", "response", "error"].forEach(function (e) { - if (flow[e]) { - tabs.push(e); - } - }); - tabs.push("details"); - return tabs; - }, - nextTab: function (i) { - var tabs = this.getTabs(this.props.flow); - var currentIndex = tabs.indexOf(this.getParams().detailTab); - // JS modulo operator doesn't correct negative numbers, make sure that we are positive. - var nextIndex = (currentIndex + i + tabs.length) % tabs.length; - this.selectTab(tabs[nextIndex]); - }, - selectTab: function (panel) { - this.replaceWith( - "flow", - { - flowId: this.getParams().flowId, - detailTab: panel - } - ); - }, - render: function () { - var flow = this.props.flow; - var tabs = this.getTabs(flow); - var active = this.getParams().detailTab; - - if (!_.contains(tabs, active)) { - if (active === "response" && flow.error) { - active = "error"; - } else if (active === "error" && flow.response) { - active = "response"; - } else { - active = tabs[0]; - } - this.selectTab(active); - } - - var Tab = allTabs[active]; - return ( -
- - -
- ); - } -}); - -module.exports = { - FlowDetail: FlowDetail -}; \ No newline at end of file diff --git a/web/src/js/components/flowview/details.js b/web/src/js/components/flowview/details.js new file mode 100644 index 000000000..00e0116c9 --- /dev/null +++ b/web/src/js/components/flowview/details.js @@ -0,0 +1,181 @@ +var React = require("react"); +var _ = require("lodash"); + +var utils = require("../../utils.js"); + +var TimeStamp = React.createClass({ + render: function () { + + if (!this.props.t) { + //should be return null, but that triggers a React bug. + return ; + } + + var ts = utils.formatTimeStamp(this.props.t); + + var delta; + if (this.props.deltaTo) { + delta = utils.formatTimeDelta(1000 * (this.props.t - this.props.deltaTo)); + delta = {"(" + delta + ")"}; + } else { + delta = null; + } + + return + {this.props.title + ":"} + {ts} {delta} + ; + } +}); + +var ConnectionInfo = React.createClass({ + + render: function () { + var conn = this.props.conn; + var address = conn.address.address.join(":"); + + var sni = ; //should be null, but that triggers a React bug. + if (conn.sni) { + sni = + + TLS SNI: + + {conn.sni} + ; + } + return ( + + + + + + + {sni} + +
Address:{address}
+ ); + } +}); + +var CertificateInfo = React.createClass({ + render: function () { + //TODO: We should fetch human-readable certificate representation + // from the server + var flow = this.props.flow; + var client_conn = flow.client_conn; + var server_conn = flow.server_conn; + + var preStyle = {maxHeight: 100}; + return ( +
+ {client_conn.cert ?

Client Certificate

: null} + {client_conn.cert ?
{client_conn.cert}
: null} + + {server_conn.cert ?

Server Certificate

: null} + {server_conn.cert ?
{server_conn.cert}
: null} +
+ ); + } +}); + +var Timing = React.createClass({ + render: function () { + var flow = this.props.flow; + var sc = flow.server_conn; + var cc = flow.client_conn; + var req = flow.request; + var resp = flow.response; + + var timestamps = [ + { + title: "Server conn. initiated", + t: sc.timestamp_start, + deltaTo: req.timestamp_start + }, { + title: "Server conn. TCP handshake", + t: sc.timestamp_tcp_setup, + deltaTo: req.timestamp_start + }, { + title: "Server conn. SSL handshake", + t: sc.timestamp_ssl_setup, + deltaTo: req.timestamp_start + }, { + title: "Client conn. established", + t: cc.timestamp_start, + deltaTo: req.timestamp_start + }, { + title: "Client conn. SSL handshake", + t: cc.timestamp_ssl_setup, + deltaTo: req.timestamp_start + }, { + title: "First request byte", + t: req.timestamp_start, + }, { + title: "Request complete", + t: req.timestamp_end, + deltaTo: req.timestamp_start + } + ]; + + if (flow.response) { + timestamps.push( + { + title: "First response byte", + t: resp.timestamp_start, + deltaTo: req.timestamp_start + }, { + title: "Response complete", + t: resp.timestamp_end, + deltaTo: req.timestamp_start + } + ); + } + + //Add unique key for each row. + timestamps.forEach(function (e) { + e.key = e.title; + }); + + timestamps = _.sortBy(timestamps, 't'); + + var rows = timestamps.map(function (e) { + return ; + }); + + return ( +
+

Timing

+ + + {rows} + +
+
+ ); + } +}); + +var Details = React.createClass({ + render: function () { + var flow = this.props.flow; + var client_conn = flow.client_conn; + var server_conn = flow.server_conn; + return ( +
+ +

Client Connection

+ + +

Server Connection

+ + + + + + +
+ ); + } +}); + +module.exports = Details; \ No newline at end of file diff --git a/web/src/js/components/flowview/index.js b/web/src/js/components/flowview/index.js new file mode 100644 index 000000000..0c31aca51 --- /dev/null +++ b/web/src/js/components/flowview/index.js @@ -0,0 +1,74 @@ +var React = require("react"); +var _ = require("lodash"); + +var common = require("../common.js"); +var Nav = require("./nav.js"); +var Messages = require("./messages.js"); +var Details = require("./details.js"); + +var allTabs = { + request: Messages.Request, + response: Messages.Response, + error: Messages.Error, + details: Details +}; + +var FlowView = React.createClass({ + mixins: [common.StickyHeadMixin, common.Navigation, common.State], + getTabs: function (flow) { + var tabs = []; + ["request", "response", "error"].forEach(function (e) { + if (flow[e]) { + tabs.push(e); + } + }); + tabs.push("details"); + return tabs; + }, + nextTab: function (i) { + var tabs = this.getTabs(this.props.flow); + var currentIndex = tabs.indexOf(this.getParams().detailTab); + // JS modulo operator doesn't correct negative numbers, make sure that we are positive. + var nextIndex = (currentIndex + i + tabs.length) % tabs.length; + this.selectTab(tabs[nextIndex]); + }, + selectTab: function (panel) { + this.replaceWith( + "flow", + { + flowId: this.getParams().flowId, + detailTab: panel + } + ); + }, + render: function () { + var flow = this.props.flow; + var tabs = this.getTabs(flow); + var active = this.getParams().detailTab; + + if (!_.contains(tabs, active)) { + if (active === "response" && flow.error) { + active = "error"; + } else if (active === "error" && flow.response) { + active = "response"; + } else { + active = tabs[0]; + } + this.selectTab(active); + } + + var Tab = allTabs[active]; + return ( +
+
+ ); + } +}); + +module.exports = FlowView; \ No newline at end of file diff --git a/web/src/js/components/flowview/messages.js b/web/src/js/components/flowview/messages.js new file mode 100644 index 000000000..ffbfff437 --- /dev/null +++ b/web/src/js/components/flowview/messages.js @@ -0,0 +1,102 @@ +var React = require("react"); + +var flowutils = require("../../flow/utils.js"); +var utils = require("../../utils.js"); + +var Headers = React.createClass({ + render: function () { + var rows = this.props.message.headers.map(function (header, i) { + return ( + + {header[0] + ":"} + {header[1]} + + ); + }); + return ( + + + {rows} + +
+ ); + } +}); + +var Request = React.createClass({ + render: function () { + var flow = this.props.flow; + var first_line = [ + flow.request.method, + flowutils.RequestUtils.pretty_url(flow.request), + "HTTP/" + flow.request.httpversion.join(".") + ].join(" "); + var content = null; + if (flow.request.contentLength > 0) { + content = "Request Content Size: " + utils.formatSize(flow.request.contentLength); + } else { + content =
No Content
; + } + + //TODO: Styling + + return ( +
+
{ first_line }
+ +
+ {content} +
+ ); + } +}); + +var Response = React.createClass({ + render: function () { + var flow = this.props.flow; + var first_line = [ + "HTTP/" + flow.response.httpversion.join("."), + flow.response.code, + flow.response.msg + ].join(" "); + var content = null; + if (flow.response.contentLength > 0) { + content = "Response Content Size: " + utils.formatSize(flow.response.contentLength); + } else { + content =
No Content
; + } + + //TODO: Styling + + return ( +
+
{ first_line }
+ +
+ {content} +
+ ); + } +}); + +var Error = React.createClass({ + render: function () { + var flow = this.props.flow; + return ( +
+
+ {flow.error.msg} +
+ { utils.formatTimeStamp(flow.error.timestamp) } +
+
+
+ ); + } +}); + +module.exports = { + Request: Request, + Response: Response, + Error: Error +}; \ No newline at end of file diff --git a/web/src/js/components/flowview/nav.js b/web/src/js/components/flowview/nav.js new file mode 100644 index 000000000..46eda7079 --- /dev/null +++ b/web/src/js/components/flowview/nav.js @@ -0,0 +1,61 @@ +var React = require("react"); + +var actions = require("../../actions.js"); + +var NavAction = React.createClass({ + onClick: function (e) { + e.preventDefault(); + this.props.onClick(); + }, + render: function () { + return ( + + + + ); + } +}); + +var Nav = React.createClass({ + render: function () { + var flow = this.props.flow; + + var tabs = this.props.tabs.map(function (e) { + var str = e.charAt(0).toUpperCase() + e.slice(1); + var className = this.props.active === e ? "active" : ""; + var onClick = function (event) { + this.props.selectTab(e); + event.preventDefault(); + }.bind(this); + return {str}; + }.bind(this)); + + var acceptButton = null; + if(flow.intercepted){ + acceptButton = ; + } + var revertButton = null; + if(flow.modified){ + revertButton = ; + } + + return ( + + ); + } +}); + +module.exports = Nav; \ No newline at end of file diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js index 8eda2e9cf..81bf3b030 100644 --- a/web/src/js/components/mainview.js +++ b/web/src/js/components/mainview.js @@ -7,7 +7,7 @@ var toputils = require("../utils.js"); var views = require("../store/view.js"); var Filt = require("../filt/filt.js"); FlowTable = require("./flowtable.js"); -var flowdetail = require("./flowdetail.js"); +var FlowView = require("./flowview/index.js"); var MainView = React.createClass({ mixins: [common.Navigation, common.State], @@ -221,7 +221,7 @@ var MainView = React.createClass({ if (selected) { details = [ , - + ]; } else { details = null; diff --git a/web/src/js/flow/utils.js b/web/src/js/flow/utils.js index a95d4ffe7..dd7f763b3 100644 --- a/web/src/js/flow/utils.js +++ b/web/src/js/flow/utils.js @@ -1,6 +1,6 @@ var _ = require("lodash"); -var _MessageUtils = { +var MessageUtils = { getContentType: function (message) { return this.get_first_header(message, /^Content-Type$/i); }, @@ -42,7 +42,7 @@ var defaultPorts = { "https": 443 }; -var RequestUtils = _.extend(_MessageUtils, { +var RequestUtils = _.extend(MessageUtils, { pretty_host: function (request) { //FIXME: Add hostheader return request.host; @@ -56,11 +56,11 @@ var RequestUtils = _.extend(_MessageUtils, { } }); -var ResponseUtils = _.extend(_MessageUtils, {}); +var ResponseUtils = _.extend(MessageUtils, {}); module.exports = { ResponseUtils: ResponseUtils, - RequestUtils: RequestUtils - -} \ No newline at end of file + RequestUtils: RequestUtils, + MessageUtils: MessageUtils +}; \ No newline at end of file From 1143552e1690f8b96b3d95381f7f06cbb46ead59 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 22 Mar 2015 00:21:38 +0100 Subject: [PATCH 019/170] web: add content views --- libmproxy/web/static/app.css | 10 + libmproxy/web/static/app.js | 215 +++++++++++++++--- web/src/css/app.less | 1 + web/src/css/flowdetail.less | 3 + web/src/css/flowview.less | 9 + web/src/js/components/flowview/contentview.js | 158 +++++++++++++ web/src/js/components/flowview/messages.js | 17 +- 7 files changed, 366 insertions(+), 47 deletions(-) create mode 100644 web/src/css/flowview.less create mode 100644 web/src/js/components/flowview/contentview.js diff --git a/libmproxy/web/static/app.css b/libmproxy/web/static/app.css index 4f24ddd9a..cf2db2c6a 100644 --- a/libmproxy/web/static/app.css +++ b/libmproxy/web/static/app.css @@ -290,6 +290,9 @@ header .menu { max-height: 100px; overflow-y: auto; } +.view-selector { + margin-top: 10px; +} .flow-detail table { font-family: Menlo, Monaco, Consolas, "Courier New", monospace; width: 100%; @@ -316,6 +319,13 @@ header .menu { text-overflow: ellipsis; white-space: nowrap; } +.flowview-image { + text-align: center; +} +.flowview-image img { + max-width: 100%; + max-height: 100%; +} .eventlog { height: 200px; flex: 0 0 auto; diff --git a/libmproxy/web/static/app.js b/libmproxy/web/static/app.js index 04d6f2824..eb8ef45e4 100644 --- a/libmproxy/web/static/app.js +++ b/libmproxy/web/static/app.js @@ -443,7 +443,7 @@ $(function () { -},{"./components/proxyapp.js":15,"./connection":17,"jquery":"jquery","react":"react","react-router":"react-router"}],4:[function(require,module,exports){ +},{"./components/proxyapp.js":16,"./connection":18,"jquery":"jquery","react":"react","react-router":"react-router"}],4:[function(require,module,exports){ var React = require("react"); var ReactRouter = require("react-router"); var _ = require("lodash"); @@ -777,7 +777,7 @@ var EventLog = React.createClass({displayName: "EventLog", module.exports = EventLog; -},{"../actions.js":2,"../store/view.js":22,"./common.js":4,"./virtualscroll.js":16,"lodash":"lodash","react":"react"}],6:[function(require,module,exports){ +},{"../actions.js":2,"../store/view.js":23,"./common.js":4,"./virtualscroll.js":17,"lodash":"lodash","react":"react"}],6:[function(require,module,exports){ var React = require("react"); var RequestUtils = require("../flow/utils.js").RequestUtils; var ResponseUtils = require("../flow/utils.js").ResponseUtils; @@ -980,7 +980,7 @@ var all_columns = [ module.exports = all_columns; -},{"../flow/utils.js":20,"../utils.js":23,"react":"react"}],7:[function(require,module,exports){ +},{"../flow/utils.js":21,"../utils.js":24,"react":"react"}],7:[function(require,module,exports){ var React = require("react"); var common = require("./common.js"); var utils = require("../utils.js"); @@ -1180,7 +1180,167 @@ var FlowTable = React.createClass({displayName: "FlowTable", module.exports = FlowTable; -},{"../utils.js":23,"./common.js":4,"./flowtable-columns.js":6,"./virtualscroll.js":16,"lodash":"lodash","react":"react"}],8:[function(require,module,exports){ +},{"../utils.js":24,"./common.js":4,"./flowtable-columns.js":6,"./virtualscroll.js":17,"lodash":"lodash","react":"react"}],8:[function(require,module,exports){ +var React = require("react"); +var _ = require("lodash"); + +var MessageUtils = require("../../flow/utils.js").MessageUtils; +var utils = require("../../utils.js"); + +var image_regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i; +var Image = React.createClass({displayName: "Image", + statics: { + matches: function (message) { + return image_regex.test(MessageUtils.getContentType(message)); + } + }, + render: function () { + var message_name = this.props.flow.request === this.props.message ? "request" : "response"; + var url = "/flows/" + this.props.flow.id + "/" + message_name + "/content"; + return React.createElement("div", {className: "flowview-image"}, + React.createElement("img", {src: url, alt: "preview", className: "img-thumbnail"}) + ); + } +}); + +var Raw = React.createClass({displayName: "Raw", + statics: { + matches: function (message) { + return true; + } + }, + render: function () { + //FIXME + return React.createElement("div", null, "raw"); + } +}); + + +var Auto = React.createClass({displayName: "Auto", + statics: { + matches: function () { + return false; // don't match itself + }, + findView: function (message) { + for (var i = 0; i < all.length; i++) { + if (all[i].matches(message)) { + return all[i]; + } + } + return all[all.length - 1]; + } + }, + render: function () { + var View = Auto.findView(this.props.message); + return React.createElement(View, React.__spread({}, this.props)); + } +}); + +var all = [Auto, Image, Raw]; + + +var ContentEmpty = React.createClass({displayName: "ContentEmpty", + render: function () { + var message_name = this.props.flow.request === this.props.message ? "request" : "response"; + return React.createElement("div", {className: "alert alert-info"}, "No ", message_name, " content."); + } +}); + +var ContentMissing = React.createClass({displayName: "ContentMissing", + render: function () { + var message_name = this.props.flow.request === this.props.message ? "Request" : "Response"; + return React.createElement("div", {className: "alert alert-info"}, message_name, " content missing."); + } +}); + +var TooLarge = React.createClass({displayName: "TooLarge", + render: function () { + var size = utils.formatSize(this.props.message.contentLength); + return React.createElement("div", {className: "alert alert-warning"}, + React.createElement("button", {onClick: this.props.onClick, className: "btn btn-xs btn-warning pull-right"}, "Display anyway"), + size, " content size." + ); + } +}); + +var ViewSelector = React.createClass({displayName: "ViewSelector", + render: function () { + var views = []; + for (var i = 0; i < all.length; i++) { + var view = all[i]; + var className = "btn btn-default"; + if (view === this.props.active) { + className += " active"; + } + var text; + if (view === Auto) { + text = "auto: " + Auto.findView(this.props.message).displayName.toLowerCase(); + } else { + text = view.displayName.toLowerCase(); + } + views.push( + React.createElement("button", { + key: view.displayName, + onClick: this.props.selectView.bind(null, view), + className: className}, + text + ) + ); + } + + return React.createElement("div", {className: "view-selector btn-group btn-group-xs"}, views); + } +}); + +var ContentView = React.createClass({displayName: "ContentView", + getInitialState: function () { + return { + displayLarge: false, + View: Auto + }; + }, + propTypes: { + // It may seem a bit weird at the first glance: + // Every view takes the flow and the message as props, e.g. + // + flow: React.PropTypes.object.isRequired, + message: React.PropTypes.object.isRequired, + }, + selectView: function (view) { + this.setState({ + View: view + }); + }, + displayLarge: function () { + this.setState({displayLarge: true}); + }, + componentWillReceiveProps: function (nextProps) { + if (nextProps.message !== this.props.message) { + this.setState(this.getInitialState()); + } + }, + render: function () { + var message = this.props.message; + if (message.contentLength === 0) { + return React.createElement(ContentEmpty, React.__spread({}, this.props)); + } else if (message.contentLength === null) { + return React.createElement(ContentMissing, React.__spread({}, this.props)); + } else if (message.contentLength > 1024 * 1024 * 3 && !this.state.displayLarge) { + return React.createElement(TooLarge, React.__spread({}, this.props, {onClick: this.displayLarge})); + } + + return React.createElement("div", null, + React.createElement(this.state.View, React.__spread({}, this.props)), + React.createElement("div", {className: "text-center"}, + React.createElement(ViewSelector, {selectView: this.selectView, active: this.state.View, message: message}) + ) + ); + } +}); + +module.exports = ContentView; + +},{"../../flow/utils.js":21,"../../utils.js":24,"lodash":"lodash","react":"react"}],9:[function(require,module,exports){ var React = require("react"); var _ = require("lodash"); @@ -1363,7 +1523,7 @@ var Details = React.createClass({displayName: "Details", module.exports = Details; -},{"../../utils.js":23,"lodash":"lodash","react":"react"}],9:[function(require,module,exports){ +},{"../../utils.js":24,"lodash":"lodash","react":"react"}],10:[function(require,module,exports){ var React = require("react"); var _ = require("lodash"); @@ -1439,11 +1599,12 @@ var FlowView = React.createClass({displayName: "FlowView", module.exports = FlowView; -},{"../common.js":4,"./details.js":8,"./messages.js":10,"./nav.js":11,"lodash":"lodash","react":"react"}],10:[function(require,module,exports){ +},{"../common.js":4,"./details.js":9,"./messages.js":11,"./nav.js":12,"lodash":"lodash","react":"react"}],11:[function(require,module,exports){ var React = require("react"); var flowutils = require("../../flow/utils.js"); var utils = require("../../utils.js"); +var ContentView = require("./contentview.js"); var Headers = React.createClass({displayName: "Headers", render: function () { @@ -1473,12 +1634,6 @@ var Request = React.createClass({displayName: "Request", flowutils.RequestUtils.pretty_url(flow.request), "HTTP/" + flow.request.httpversion.join(".") ].join(" "); - var content = null; - if (flow.request.contentLength > 0) { - content = "Request Content Size: " + utils.formatSize(flow.request.contentLength); - } else { - content = React.createElement("div", {className: "alert alert-info"}, "No Content"); - } //TODO: Styling @@ -1487,7 +1642,7 @@ var Request = React.createClass({displayName: "Request", React.createElement("div", {className: "first-line"}, first_line ), React.createElement(Headers, {message: flow.request}), React.createElement("hr", null), - content + React.createElement(ContentView, {flow: flow, message: flow.request}) ) ); } @@ -1501,12 +1656,6 @@ var Response = React.createClass({displayName: "Response", flow.response.code, flow.response.msg ].join(" "); - var content = null; - if (flow.response.contentLength > 0) { - content = "Response Content Size: " + utils.formatSize(flow.response.contentLength); - } else { - content = React.createElement("div", {className: "alert alert-info"}, "No Content"); - } //TODO: Styling @@ -1515,7 +1664,7 @@ var Response = React.createClass({displayName: "Response", React.createElement("div", {className: "first-line"}, first_line ), React.createElement(Headers, {message: flow.response}), React.createElement("hr", null), - content + React.createElement(ContentView, {flow: flow, message: flow.response}) ) ); } @@ -1543,7 +1692,7 @@ module.exports = { Error: Error }; -},{"../../flow/utils.js":20,"../../utils.js":23,"react":"react"}],11:[function(require,module,exports){ +},{"../../flow/utils.js":21,"../../utils.js":24,"./contentview.js":8,"react":"react"}],12:[function(require,module,exports){ var React = require("react"); var actions = require("../../actions.js"); @@ -1606,7 +1755,7 @@ var Nav = React.createClass({displayName: "Nav", module.exports = Nav; -},{"../../actions.js":2,"react":"react"}],12:[function(require,module,exports){ +},{"../../actions.js":2,"react":"react"}],13:[function(require,module,exports){ var React = require("react"); var Footer = React.createClass({displayName: "Footer", @@ -1625,7 +1774,7 @@ var Footer = React.createClass({displayName: "Footer", module.exports = Footer; -},{"react":"react"}],13:[function(require,module,exports){ +},{"react":"react"}],14:[function(require,module,exports){ var React = require("react"); var $ = require("jquery"); @@ -2017,7 +2166,7 @@ module.exports = { Header: Header } -},{"../actions.js":2,"../filt/filt.js":19,"../utils.js":23,"./common.js":4,"jquery":"jquery","react":"react"}],14:[function(require,module,exports){ +},{"../actions.js":2,"../filt/filt.js":20,"../utils.js":24,"./common.js":4,"jquery":"jquery","react":"react"}],15:[function(require,module,exports){ var React = require("react"); var common = require("./common.js"); @@ -2263,7 +2412,7 @@ var MainView = React.createClass({displayName: "MainView", module.exports = MainView; -},{"../actions.js":2,"../filt/filt.js":19,"../store/view.js":22,"../utils.js":23,"./common.js":4,"./flowtable.js":7,"./flowview/index.js":9,"react":"react"}],15:[function(require,module,exports){ +},{"../actions.js":2,"../filt/filt.js":20,"../store/view.js":23,"../utils.js":24,"./common.js":4,"./flowtable.js":7,"./flowview/index.js":10,"react":"react"}],16:[function(require,module,exports){ var React = require("react"); var ReactRouter = require("react-router"); var _ = require("lodash"); @@ -2358,7 +2507,7 @@ module.exports = { routes: routes }; -},{"../actions.js":2,"../store/store.js":21,"./common.js":4,"./eventlog.js":5,"./footer.js":12,"./header.js":13,"./mainview.js":14,"lodash":"lodash","react":"react","react-router":"react-router"}],16:[function(require,module,exports){ +},{"../actions.js":2,"../store/store.js":22,"./common.js":4,"./eventlog.js":5,"./footer.js":13,"./header.js":14,"./mainview.js":15,"lodash":"lodash","react":"react","react-router":"react-router"}],17:[function(require,module,exports){ var React = require("react"); var VirtualScrollMixin = { @@ -2445,7 +2594,7 @@ var VirtualScrollMixin = { module.exports = VirtualScrollMixin; -},{"react":"react"}],17:[function(require,module,exports){ +},{"react":"react"}],18:[function(require,module,exports){ var actions = require("./actions.js"); @@ -2475,7 +2624,7 @@ function Connection(url) { module.exports = Connection; -},{"./actions.js":2}],18:[function(require,module,exports){ +},{"./actions.js":2}],19:[function(require,module,exports){ var flux = require("flux"); @@ -2499,7 +2648,7 @@ module.exports = { AppDispatcher: AppDispatcher }; -},{"flux":"flux"}],19:[function(require,module,exports){ +},{"flux":"flux"}],20:[function(require,module,exports){ module.exports = (function() { /* * Generated by PEG.js 0.8.0. @@ -4275,7 +4424,7 @@ module.exports = (function() { }; })(); -},{"../flow/utils.js":20}],20:[function(require,module,exports){ +},{"../flow/utils.js":21}],21:[function(require,module,exports){ var _ = require("lodash"); var MessageUtils = { @@ -4343,7 +4492,7 @@ module.exports = { MessageUtils: MessageUtils }; -},{"lodash":"lodash"}],21:[function(require,module,exports){ +},{"lodash":"lodash"}],22:[function(require,module,exports){ var _ = require("lodash"); var $ = require("jquery"); @@ -4526,7 +4675,7 @@ module.exports = { FlowStore: FlowStore }; -},{"../actions.js":2,"../dispatcher.js":18,"../utils.js":23,"events":1,"jquery":"jquery","lodash":"lodash"}],22:[function(require,module,exports){ +},{"../actions.js":2,"../dispatcher.js":19,"../utils.js":24,"events":1,"jquery":"jquery","lodash":"lodash"}],23:[function(require,module,exports){ var EventEmitter = require('events').EventEmitter; var _ = require("lodash"); @@ -4642,7 +4791,7 @@ module.exports = { StoreView: StoreView }; -},{"../utils.js":23,"events":1,"lodash":"lodash"}],23:[function(require,module,exports){ +},{"../utils.js":24,"events":1,"lodash":"lodash"}],24:[function(require,module,exports){ var $ = require("jquery"); var _ = require("lodash"); diff --git a/web/src/css/app.less b/web/src/css/app.less index 26f22572e..ecec3d9c2 100644 --- a/web/src/css/app.less +++ b/web/src/css/app.less @@ -13,5 +13,6 @@ html { @import (less) "header.less"; @import (less) "flowtable.less"; @import (less) "flowdetail.less"; +@import (less) "flowview.less"; @import (less) "eventlog.less"; @import (less) "footer.less"; \ No newline at end of file diff --git a/web/src/css/flowdetail.less b/web/src/css/flowdetail.less index 7649057f2..093ee14f8 100644 --- a/web/src/css/flowdetail.less +++ b/web/src/css/flowdetail.less @@ -29,6 +29,9 @@ } } +.view-selector { + margin-top: 10px; +} .flow-detail table { .monospace(); diff --git a/web/src/css/flowview.less b/web/src/css/flowview.less new file mode 100644 index 000000000..44ae8ac24 --- /dev/null +++ b/web/src/css/flowview.less @@ -0,0 +1,9 @@ +.flowview-image { + + text-align: center; + + img { + max-width: 100%; + max-height: 100%; + } +} \ No newline at end of file diff --git a/web/src/js/components/flowview/contentview.js b/web/src/js/components/flowview/contentview.js new file mode 100644 index 000000000..09a64bb20 --- /dev/null +++ b/web/src/js/components/flowview/contentview.js @@ -0,0 +1,158 @@ +var React = require("react"); +var _ = require("lodash"); + +var MessageUtils = require("../../flow/utils.js").MessageUtils; +var utils = require("../../utils.js"); + +var image_regex = /^image\/(png|jpe?g|gif|vnc.microsoft.icon|x-icon)$/i; +var Image = React.createClass({ + statics: { + matches: function (message) { + return image_regex.test(MessageUtils.getContentType(message)); + } + }, + render: function () { + var message_name = this.props.flow.request === this.props.message ? "request" : "response"; + var url = "/flows/" + this.props.flow.id + "/" + message_name + "/content"; + return
+ preview +
; + } +}); + +var Raw = React.createClass({ + statics: { + matches: function (message) { + return true; + } + }, + render: function () { + //FIXME + return
raw
; + } +}); + + +var Auto = React.createClass({ + statics: { + matches: function () { + return false; // don't match itself + }, + findView: function (message) { + for (var i = 0; i < all.length; i++) { + if (all[i].matches(message)) { + return all[i]; + } + } + return all[all.length - 1]; + } + }, + render: function () { + var View = Auto.findView(this.props.message); + return ; + } +}); + +var all = [Auto, Image, Raw]; + + +var ContentEmpty = React.createClass({ + render: function () { + var message_name = this.props.flow.request === this.props.message ? "request" : "response"; + return
No {message_name} content.
; + } +}); + +var ContentMissing = React.createClass({ + render: function () { + var message_name = this.props.flow.request === this.props.message ? "Request" : "Response"; + return
{message_name} content missing.
; + } +}); + +var TooLarge = React.createClass({ + render: function () { + var size = utils.formatSize(this.props.message.contentLength); + return
+ + {size} content size. +
; + } +}); + +var ViewSelector = React.createClass({ + render: function () { + var views = []; + for (var i = 0; i < all.length; i++) { + var view = all[i]; + var className = "btn btn-default"; + if (view === this.props.active) { + className += " active"; + } + var text; + if (view === Auto) { + text = "auto: " + Auto.findView(this.props.message).displayName.toLowerCase(); + } else { + text = view.displayName.toLowerCase(); + } + views.push( + + ); + } + + return
{views}
; + } +}); + +var ContentView = React.createClass({ + getInitialState: function () { + return { + displayLarge: false, + View: Auto + }; + }, + propTypes: { + // It may seem a bit weird at the first glance: + // Every view takes the flow and the message as props, e.g. + // + flow: React.PropTypes.object.isRequired, + message: React.PropTypes.object.isRequired, + }, + selectView: function (view) { + this.setState({ + View: view + }); + }, + displayLarge: function () { + this.setState({displayLarge: true}); + }, + componentWillReceiveProps: function (nextProps) { + if (nextProps.message !== this.props.message) { + this.setState(this.getInitialState()); + } + }, + render: function () { + var message = this.props.message; + if (message.contentLength === 0) { + return ; + } else if (message.contentLength === null) { + return ; + } else if (message.contentLength > 1024 * 1024 * 3 && !this.state.displayLarge) { + return ; + } + + return
+ +
+ +
+
; + } +}); + +module.exports = ContentView; \ No newline at end of file diff --git a/web/src/js/components/flowview/messages.js b/web/src/js/components/flowview/messages.js index ffbfff437..fe8fa2005 100644 --- a/web/src/js/components/flowview/messages.js +++ b/web/src/js/components/flowview/messages.js @@ -2,6 +2,7 @@ var React = require("react"); var flowutils = require("../../flow/utils.js"); var utils = require("../../utils.js"); +var ContentView = require("./contentview.js"); var Headers = React.createClass({ render: function () { @@ -31,12 +32,6 @@ var Request = React.createClass({ flowutils.RequestUtils.pretty_url(flow.request), "HTTP/" + flow.request.httpversion.join(".") ].join(" "); - var content = null; - if (flow.request.contentLength > 0) { - content = "Request Content Size: " + utils.formatSize(flow.request.contentLength); - } else { - content =
No Content
; - } //TODO: Styling @@ -45,7 +40,7 @@ var Request = React.createClass({
{ first_line }

- {content} + ); } @@ -59,12 +54,6 @@ var Response = React.createClass({ flow.response.code, flow.response.msg ].join(" "); - var content = null; - if (flow.response.contentLength > 0) { - content = "Response Content Size: " + utils.formatSize(flow.response.contentLength); - } else { - content =
No Content
; - } //TODO: Styling @@ -73,7 +62,7 @@ var Response = React.createClass({
{ first_line }

- {content} + ); } From 89d66360d6f7caa9760fe56fa146396b1b4251dc Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 22 Mar 2015 00:28:08 +0100 Subject: [PATCH 020/170] tweak css --- libmproxy/web/static/app.css | 6 + web/src/css/eventlog.less | 2 - web/src/css/flowdetail.less | 23 ++- web/src/css/flowtable.less | 212 ++++++++++---------- web/src/css/flowview.less | 10 +- web/src/css/header.less | 32 +-- web/src/css/layout.less | 2 +- web/src/css/sprites.less | 28 ++- web/src/css/vendor-bootstrap-variables.less | 11 +- web/src/css/vendor-bootstrap.less | 5 - 10 files changed, 172 insertions(+), 159 deletions(-) diff --git a/libmproxy/web/static/app.css b/libmproxy/web/static/app.css index cf2db2c6a..91e847a49 100644 --- a/libmproxy/web/static/app.css +++ b/libmproxy/web/static/app.css @@ -290,6 +290,9 @@ header .menu { max-height: 100px; overflow-y: auto; } +.flow-detail hr { + margin: 0 0 5px; +} .view-selector { margin-top: 10px; } @@ -309,6 +312,9 @@ header .menu { width: 50%; padding-right: 1em; } +.header-table td { + line-height: 1.3em; +} .header-table .header-name { width: 33%; padding-right: 1em; diff --git a/web/src/css/eventlog.less b/web/src/css/eventlog.less index 8b0a76479..26dea3ccd 100644 --- a/web/src/css/eventlog.less +++ b/web/src/css/eventlog.less @@ -6,7 +6,6 @@ display: flex; flex-direction: column; - > div { background-color: #F2F2F2; padding: 0 5px; @@ -23,7 +22,6 @@ background-color: #fcfcfc; } - .fa-close { cursor: pointer; float: right; diff --git a/web/src/css/flowdetail.less b/web/src/css/flowdetail.less index 093ee14f8..453cf425e 100644 --- a/web/src/css/flowdetail.less +++ b/web/src/css/flowdetail.less @@ -1,13 +1,12 @@ //TODO: Move into some utils -.monospace(){ +.monospace() { font-family: Menlo, Monaco, Consolas, "Courier New", monospace; } - .flow-detail { width: 100%; overflow: auto; - + nav { background-color: #F2F2F2; } @@ -27,10 +26,15 @@ max-height: 100px; overflow-y: auto; } + + hr { + margin: 0 0 5px; + } + } .view-selector { - margin-top: 10px; + margin-top: 10px; } .flow-detail table { @@ -38,10 +42,10 @@ width: 100%; table-layout: fixed; word-break: break-all; - + tr { - &:not(:first-child){ - border-top: 1px solid #f7f7f7; + &:not(:first-child) { + border-top: 1px solid #f7f7f7; } } @@ -62,12 +66,15 @@ } .header-table { + td { + line-height: 1.3em; + } .header-name { width: 33%; padding-right: 1em; } .header-value { - + } } diff --git a/web/src/css/flowtable.less b/web/src/css/flowtable.less index d94d93705..3533983ce 100644 --- a/web/src/css/flowtable.less +++ b/web/src/css/flowtable.less @@ -1,127 +1,127 @@ //TODO: move into utils .user-select (@val) { - -webkit-touch-callout: @val; - -webkit-user-select: @val; - -khtml-user-select: @val; - -moz-user-select: @val; - -ms-user-select: @val; - user-select: @val; + -webkit-touch-callout: @val; + -webkit-user-select: @val; + -khtml-user-select: @val; + -moz-user-select: @val; + -ms-user-select: @val; + user-select: @val; } .flow-table { - width: 100%; - overflow: auto; - - table { width: 100%; - table-layout: fixed; - } + overflow: auto; - thead { - background-color: #F2F2F2; - line-height: 23px; - } - - th { - font-weight: normal; - box-shadow: 0 1px 0 #a6a6a6; - position: relative !important; - padding-left: 1px; - .user-select(none); - - &.sort-asc, &.sort-desc { - background-color: lighten(#F2F2F2, 3%); - } - &.sort-asc:after, &.sort-desc:after { - font: normal normal normal 14px/1 FontAwesome; - position: absolute; - right: 3px; - top: 3px; - padding: 2px; - background-color: fadeout(lighten(#F2F2F2, 3%), 20%); - } - &.sort-asc:after { - content: "\f0de"; - } - &.sort-desc:after { - content: "\f0dd"; + table { + width: 100%; + table-layout: fixed; } - } + thead { + background-color: #F2F2F2; + line-height: 23px; + } - tr { - cursor: pointer; + th { + font-weight: normal; + box-shadow: 0 1px 0 #a6a6a6; + position: relative !important; + padding-left: 1px; + .user-select(none); - &:nth-child(even) { - background-color: rgba(0, 0, 0, 0.05); - } - &.selected { - background-color: hsla(209, 52%, 84%, 0.5) !important; - } - &.highlighted { - background-color: hsla(48, 100%, 50%, 0.4); - } - &.highlighted:nth-child(even) { - background-color: hsla(48, 100%, 50%, 0.5); - } - } + &.sort-asc, &.sort-desc { + background-color: lighten(#F2F2F2, 3%); + } + &.sort-asc:after, &.sort-desc:after { + font: normal normal normal 14px/1 FontAwesome; + position: absolute; + right: 3px; + top: 3px; + padding: 2px; + background-color: fadeout(lighten(#F2F2F2, 3%), 20%); + } + &.sort-asc:after { + content: "\f0de"; + } + &.sort-desc:after { + content: "\f0dd"; + } - td { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } + } - @interceptorange: hsl(30, 100%, 50%); + tr { + cursor: pointer; - tr.intercepted:not(.has-response) { - .col-path, .col-method { - color: @interceptorange; + &:nth-child(even) { + background-color: rgba(0, 0, 0, 0.05); + } + &.selected { + background-color: hsla(209, 52%, 84%, 0.5) !important; + } + &.highlighted { + background-color: hsla(48, 100%, 50%, 0.4); + } + &.highlighted:nth-child(even) { + background-color: hsla(48, 100%, 50%, 0.5); + } } - } - tr.intercepted.has-response { - .col-status, .col-size, .col-time { - color: @interceptorange; - } - } - .fa { - line-height: inherit; - &.pull-right { - margin-left: 0; + td { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } - } - .col-tls { - width: 10px; - } - .col-tls-https { - background-color: rgba(0, 185, 0, 0.5); - } - .col-icon { - width: 32px; - } - .col-path { - .fa-repeat { - color: green; + @interceptorange: hsl(30, 100%, 50%); + + tr.intercepted:not(.has-response) { + .col-path, .col-method { + color: @interceptorange; + } } - .fa-pause { - color: @interceptorange; + tr.intercepted.has-response { + .col-status, .col-size, .col-time { + color: @interceptorange; + } + } + + .fa { + line-height: inherit; + &.pull-right { + margin-left: 0; + } + } + + .col-tls { + width: 10px; + } + .col-tls-https { + background-color: rgba(0, 185, 0, 0.5); + } + .col-icon { + width: 32px; + } + .col-path { + .fa-repeat { + color: green; + } + .fa-pause { + color: @interceptorange; + } + } + .col-method { + width: 60px; + } + .col-status { + width: 50px; + } + .col-size { + width: 70px; + } + .col-time { + width: 50px; + } + td.col-time, td.col-size { + text-align: right; } - } - .col-method { - width: 60px; - } - .col-status { - width: 50px; - } - .col-size { - width: 70px; - } - .col-time { - width: 50px; - } - td.col-time, td.col-size { - text-align: right; - } } \ No newline at end of file diff --git a/web/src/css/flowview.less b/web/src/css/flowview.less index 44ae8ac24..aa8a2df27 100644 --- a/web/src/css/flowview.less +++ b/web/src/css/flowview.less @@ -1,9 +1,9 @@ .flowview-image { - text-align: center; + text-align: center; - img { - max-width: 100%; - max-height: 100%; - } + img { + max-width: 100%; + max-height: 100%; + } } \ No newline at end of file diff --git a/web/src/css/header.less b/web/src/css/header.less index 57f122e83..6e61b956c 100644 --- a/web/src/css/header.less +++ b/web/src/css/header.less @@ -2,30 +2,30 @@ @import (reference) '../../node_modules/bootstrap/less/mixins/grid.less'; header { - padding-top: 0.5em; - background-color: white; - @separator-color: lighten(grey, 15%); - .menu { - padding: 10px; - border-bottom: solid @separator-color 1px; - } + padding-top: 0.5em; + background-color: white; + @separator-color: lighten(grey, 15%); + .menu { + padding: 10px; + border-bottom: solid @separator-color 1px; + } } @menu-row-gutter-width: 5px; .menu-row { - .make-row(@menu-row-gutter-width); + .make-row(@menu-row-gutter-width); } .filter-input { - .make-md-column(3, @menu-row-gutter-width); + .make-md-column(3, @menu-row-gutter-width); } .filter-input .popover { - top: 27px; - display: block; - max-width: none; - .popover-content { - max-height: 500px; - overflow-y: auto; - } + top: 27px; + display: block; + max-width: none; + .popover-content { + max-height: 500px; + overflow-y: auto; + } } \ No newline at end of file diff --git a/web/src/css/layout.less b/web/src/css/layout.less index f6807f24b..4e96609b7 100644 --- a/web/src/css/layout.less +++ b/web/src/css/layout.less @@ -15,7 +15,7 @@ html, body, #container { .main-view { flex: 1 1 auto; - + display: flex; flex-direction: row; diff --git a/web/src/css/sprites.less b/web/src/css/sprites.less index 49b3600c1..74131c5e7 100644 --- a/web/src/css/sprites.less +++ b/web/src/css/sprites.less @@ -5,34 +5,42 @@ // From Chrome Dev Tools .resource-icon-css { - background-image: url(images/chrome-devtools/resourceCSSIcon.png); + background-image: url(images/chrome-devtools/resourceCSSIcon.png); } + .resource-icon-document { - background-image: url(images/chrome-devtools/resourceDocumentIcon.png); + background-image: url(images/chrome-devtools/resourceDocumentIcon.png); } + .resource-icon-js { - background-image: url(images/chrome-devtools/resourceJSIcon.png); + background-image: url(images/chrome-devtools/resourceJSIcon.png); } + .resource-icon-plain { - background-image: url(images/chrome-devtools/resourcePlainIcon.png); + background-image: url(images/chrome-devtools/resourcePlainIcon.png); } // Own .resource-icon-executable { - background-image: url(images/resourceExecutableIcon.png); + background-image: url(images/resourceExecutableIcon.png); } + .resource-icon-flash { - background-image: url(images/resourceFlashIcon.png); + background-image: url(images/resourceFlashIcon.png); } + .resource-icon-image { - background-image: url(images/resourceImageIcon.png); + background-image: url(images/resourceImageIcon.png); } + .resource-icon-java { - background-image: url(images/resourceJavaIcon.png); + background-image: url(images/resourceJavaIcon.png); } + .resource-icon-not-modified { - background-image: url(images/resourceNotModifiedIcon.png); + background-image: url(images/resourceNotModifiedIcon.png); } + .resource-icon-redirect { - background-image: url(images/resourceRedirectIcon.png); + background-image: url(images/resourceRedirectIcon.png); } \ No newline at end of file diff --git a/web/src/css/vendor-bootstrap-variables.less b/web/src/css/vendor-bootstrap-variables.less index b28189932..e2c37bf5a 100644 --- a/web/src/css/vendor-bootstrap-variables.less +++ b/web/src/css/vendor-bootstrap-variables.less @@ -1,6 +1,5 @@ - -@navbar-height: 32px; -@navbar-default-link-color: #303030; -@navbar-default-color: #303030; -@navbar-default-bg: #ffffff; -@navbar-default-border: #e0e0e0; +@navbar-height: 32px; +@navbar-default-link-color: #303030; +@navbar-default-color: #303030; +@navbar-default-bg: #ffffff; +@navbar-default-border: #e0e0e0; diff --git a/web/src/css/vendor-bootstrap.less b/web/src/css/vendor-bootstrap.less index 0b3252fe5..35fda3796 100644 --- a/web/src/css/vendor-bootstrap.less +++ b/web/src/css/vendor-bootstrap.less @@ -2,12 +2,10 @@ @import "../../node_modules/bootstrap/less/variables.less"; @import "vendor-bootstrap-variables.less"; @import "../../node_modules/bootstrap/less/mixins.less"; - // Reset and dependencies @import "../../node_modules/bootstrap/less/normalize.less"; @import "../../node_modules/bootstrap/less/print.less"; @import "../../node_modules/bootstrap/less/glyphicons.less"; - // Core CSS @import "../../node_modules/bootstrap/less/scaffolding.less"; @import "../../node_modules/bootstrap/less/type.less"; @@ -16,7 +14,6 @@ @import "../../node_modules/bootstrap/less/tables.less"; @import "../../node_modules/bootstrap/less/forms.less"; @import "../../node_modules/bootstrap/less/buttons.less"; - // Components @import "../../node_modules/bootstrap/less/component-animations.less"; @import "../../node_modules/bootstrap/less/dropdowns.less"; @@ -39,13 +36,11 @@ @import "../../node_modules/bootstrap/less/responsive-embed.less"; @import "../../node_modules/bootstrap/less/wells.less"; @import "../../node_modules/bootstrap/less/close.less"; - // Components w/ JavaScript @import "../../node_modules/bootstrap/less/modals.less"; @import "../../node_modules/bootstrap/less/tooltip.less"; @import "../../node_modules/bootstrap/less/popovers.less"; @import "../../node_modules/bootstrap/less/carousel.less"; - // Utility classes @import "../../node_modules/bootstrap/less/utilities.less"; @import "../../node_modules/bootstrap/less/responsive-utilities.less"; From 89383e9c138f68caf1cc394174250c133d21aa04 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 13:32:24 +1300 Subject: [PATCH 021/170] Refactor status bar prompting to use signal system --- libmproxy/console/__init__.py | 58 +------- libmproxy/console/common.py | 46 +++--- libmproxy/console/flowlist.py | 112 +++++++------- libmproxy/console/flowview.py | 109 ++++++++------ libmproxy/console/grideditor.py | 31 ++-- libmproxy/console/signals.py | 16 +- libmproxy/console/statusbar.py | 84 +++++++++-- libmproxy/console/window.py | 255 ++++++++++++++++---------------- test/tools/testpatt | 10 +- 9 files changed, 386 insertions(+), 335 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index aae7a9c42..d8eb8a41f 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -272,7 +272,7 @@ class ConsoleMaster(flow.FlowMaster): self.eventlog = not self.eventlog self.view_flowlist() - def _readflow(self, paths): + def _readflows(self, path): """ Utitility function that reads a list of flows or prints an error to the UI if that fails. @@ -281,7 +281,7 @@ class ConsoleMaster(flow.FlowMaster): - a list of flows, otherwise. """ try: - return flow.read_flows_from_paths(paths) + return flow.read_flows_from_paths([path]) except flow.FlowReadError as e: if not self.statusbar: print >> sys.stderr, e.strerror @@ -291,12 +291,12 @@ class ConsoleMaster(flow.FlowMaster): return None def client_playback_path(self, path): - flows = self._readflow(path) + flows = self._readflows(path) if flows: self.start_client_playback(flows, False) def server_playback_path(self, path): - flows = self._readflow(path) + flows = self._readflows(path) if flows: self.start_server_playback( flows, @@ -387,7 +387,6 @@ class ConsoleMaster(flow.FlowMaster): self.header = None self.body = None self.help_context = None - self.prompting = False self.onekey = False self.loop = urwid.MainLoop( self.view, @@ -538,55 +537,6 @@ class ConsoleMaster(flow.FlowMaster): self.sync_list_view() return reterr - def path_prompt(self, prompt, text, callback, *args): - self.statusbar.path_prompt(prompt, text) - self.view.set_focus("footer") - self.prompting = (callback, args) - - def prompt(self, prompt, text, callback, *args): - self.statusbar.prompt(prompt, text) - self.view.set_focus("footer") - self.prompting = (callback, args) - - def prompt_edit(self, prompt, text, callback): - self.statusbar.prompt(prompt + ": ", text) - self.view.set_focus("footer") - self.prompting = (callback, []) - - def prompt_onekey(self, prompt, keys, callback, *args): - """ - Keys are a set of (word, key) tuples. The appropriate key in the - word is highlighted. - """ - prompt = [prompt, " ("] - mkup = [] - for i, e in enumerate(keys): - mkup.extend(common.highlight_key(e[0], e[1])) - if i < len(keys)-1: - mkup.append(",") - prompt.extend(mkup) - prompt.append(")? ") - self.onekey = set(i[1] for i in keys) - self.prompt(prompt, "", callback, *args) - - def prompt_done(self): - self.prompting = False - self.onekey = False - self.view.set_focus("body") - signals.status_message.send(message="") - - def prompt_execute(self, txt=None): - if not txt: - txt = self.statusbar.get_edit_text() - p, args = self.prompting - self.prompt_done() - msg = p(txt, *args) - if msg: - signals.status_message.send(message=msg, expire=1) - - def prompt_cancel(self): - self.prompt_done() - def accept_all(self): self.state.accept_all(self) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 9731b6824..185480db2 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -203,13 +203,11 @@ def save_data(path, data, master, state): def ask_save_path(prompt, data, master, state): - master.path_prompt( - prompt, - state.last_saveload, - save_data, - data, - master, - state + signals.status_path_prompt.send( + prompt = prompt, + text = state.last_saveload, + callback = save_data, + args = (data, master, state) ) @@ -263,14 +261,13 @@ def copy_flow(part, scope, flow, master, state): def save(k): if k == "y": ask_save_path("Save data: ", data, master, state) - - master.prompt_onekey( - "Cannot copy binary data to clipboard. Save as file?", - ( + signals.status_prompt_onekey.send( + prompt = "Cannot copy binary data to clipboard. Save as file?", + keys = ( ("yes", "y"), ("no", "n"), ), - save + callback = save ) @@ -282,14 +279,11 @@ def ask_copy_part(scope, flow, master, state): if scope != "s": choices.append(("url", "u")) - master.prompt_onekey( - "Copy", - choices, - copy_flow, - scope, - flow, - master, - state + signals.status_prompt_onekey.send( + prompt = "Copy", + keys = choices, + callback = copy_flow, + args = (scope, flow, master, state) ) @@ -306,16 +300,14 @@ def ask_save_body(part, master, state, flow): # We first need to determine whether we want to save the request or the # response content. if request_has_content and response_has_content: - master.prompt_onekey( - "Save", - ( + signals.status_prompt_onekey.send( + prompt = "Save", + keys = ( ("request", "q"), ("response", "s"), ), - ask_save_body, - master, - state, - flow + callback = ask_save_body, + args = (master, state, flow) ) elif response_has_content: ask_save_body("s", master, state, flow) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index c8ecf15c9..d4dd89d88 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -111,17 +111,17 @@ class ConnectionItem(urwid.WidgetWrap): def save_flows_prompt(self, k): if k == "a": - self.master.path_prompt( - "Save all flows to: ", - self.state.last_saveload, - self.master.save_flows + signals.status_path_prompt.send( + prompt = "Save all flows to: ", + text = self.state.last_saveload, + callback = self.master.save_flows ) else: - self.master.path_prompt( - "Save this flow to: ", - self.state.last_saveload, - self.master.save_one_flow, - self.flow + signals.status_path_prompt.send( + prompt = "Save this flow to: ", + text = self.state.last_saveload, + callback = self.master.save_one_flow, + args = (self.flow,) ) def stop_server_playback_prompt(self, a): @@ -150,10 +150,10 @@ class ConnectionItem(urwid.WidgetWrap): self.master.options.replay_ignore_host ) else: - self.master.path_prompt( - "Server replay path: ", - self.state.last_saveload, - self.master.server_playback_path + signals.status_path_prompt.send( + prompt = "Server replay path: ", + text = self.state.last_saveload, + callback = self.master.server_playback_path ) def keypress(self, (maxcol,), key): @@ -175,23 +175,23 @@ class ConnectionItem(urwid.WidgetWrap): self.master.sync_list_view() elif key == "S": if not self.master.server_playback: - self.master.prompt_onekey( - "Server Replay", - ( + signals.status_prompt_onekey.send( + prompt = "Server Replay", + keys = ( ("all flows", "a"), ("this flow", "t"), ("file", "f"), ), - self.server_replay_prompt, + callback = self.server_replay_prompt, ) else: - self.master.prompt_onekey( - "Stop current server replay?", - ( + signals.status_prompt_onekey.send( + prompt = "Stop current server replay?", + keys = ( ("yes", "y"), ("no", "n"), ), - self.stop_server_playback_prompt, + callback = self.stop_server_playback_prompt, ) elif key == "V": if not self.flow.modified(): @@ -201,13 +201,14 @@ class ConnectionItem(urwid.WidgetWrap): self.master.sync_list_view() signals.status_message.send(message="Reverted.") elif key == "w": - self.master.prompt_onekey( - "Save", - ( + signals.status_prompt_onekey.send( + self, + prompt = "Save", + keys = ( ("all flows", "a"), ("this flow", "t"), ), - self.save_flows_prompt, + callback = self.save_flows_prompt, ) elif key == "X": self.flow.kill(self.master) @@ -215,11 +216,11 @@ class ConnectionItem(urwid.WidgetWrap): if self.flow.request: self.master.view_flow(self.flow) elif key == "|": - self.master.path_prompt( - "Send flow to script: ", - self.state.last_script, - self.master.run_script_once, - self.flow + signals.status_path_prompt.send( + prompt = "Send flow to script: ", + text = self.state.last_script, + callback = self.master.run_script_once, + args = (self.flow,) ) elif key == "g": common.ask_copy_part("a", self.flow, self.master, self.state) @@ -266,7 +267,12 @@ class FlowListBox(urwid.ListBox): def get_method(self, k): if k == "e": - self.master.prompt("Method:", "", self.get_method_raw) + signals.status_prompt.send( + self, + prompt = "Method:", + text = "", + callback = self.get_method_raw + ) else: method = "" for i in common.METHOD_OPTIONS: @@ -275,11 +281,11 @@ class FlowListBox(urwid.ListBox): self.get_url(method) def get_url(self, method): - self.master.prompt( - "URL:", - "http://www.example.com/", - self.new_request, - method + signals.status_prompt.send( + prompt = "URL:", + text = "http://www.example.com/", + callback = self.new_request, + args = (method,) ) def new_request(self, url, method): @@ -301,22 +307,23 @@ class FlowListBox(urwid.ListBox): elif key == "e": self.master.toggle_eventlog() elif key == "l": - self.master.prompt( - "Limit: ", - self.master.state.limit_txt, - self.master.set_limit + signals.status_prompt.send( + prompt = "Limit: ", + text = self.master.state.limit_txt, + callback = self.master.set_limit ) elif key == "L": - self.master.path_prompt( - "Load flows: ", - self.master.state.last_saveload, - self.master.load_flows_callback + signals.status_path_prompt.send( + self, + prompt = "Load flows: ", + text = self.master.state.last_saveload, + callback = self.master.load_flows_callback ) elif key == "n": - self.master.prompt_onekey( - "Method", - common.METHOD_OPTIONS, - self.get_method + signals.status_prompt_onekey.send( + prompt = "Method", + keys = common.METHOD_OPTIONS, + callback = self.get_method ) elif key == "F": self.master.toggle_follow_flows() @@ -324,10 +331,11 @@ class FlowListBox(urwid.ListBox): if self.master.stream: self.master.stop_stream() else: - self.master.path_prompt( - "Stream flows to: ", - self.master.state.last_saveload, - self.master.start_stream_to_path + signals.status_path_prompt.send( + self, + prompt = "Stream flows to: ", + text = self.master.state.last_saveload, + callback = self.master.start_stream_to_path ) else: return urwid.ListBox.keypress(self, size, key) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index b22bbb374..941ceb942 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -492,7 +492,11 @@ class FlowView(urwid.WidgetWrap): def edit_method(self, m): if m == "e": - self.master.prompt_edit("Method", self.flow.request.method, self.set_method_raw) + signals.status_prompt.send( + prompt = "Method: ", + text = self.flow.request.method, + callback = self.set_method_raw + ) else: for i in common.METHOD_OPTIONS: if i[1] == m: @@ -567,14 +571,14 @@ class FlowView(urwid.WidgetWrap): message.content = c.rstrip("\n") elif part == "f": if not message.get_form_urlencoded() and message.content: - self.master.prompt_onekey( - "Existing body is not a URL-encoded form. Clear and edit?", - [ + signals.status_prompt_onekey.send( + prompt = "Existing body is not a URL-encoded form. Clear and edit?", + keys = [ ("yes", "y"), ("no", "n"), ], - self.edit_form_confirm, - message + callback = self.edit_form_confirm, + args = (message,) ) else: self.edit_form(message) @@ -587,13 +591,29 @@ class FlowView(urwid.WidgetWrap): elif part == "q": self.master.view_grideditor(grideditor.QueryEditor(self.master, message.get_query().lst, self.set_query, message)) elif part == "u" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.master.prompt_edit("URL", message.url, self.set_url) + signals.status_prompt.send( + prompt = "URL: ", + text = message.url, + callback = self.set_url + ) elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.master.prompt_onekey("Method", common.METHOD_OPTIONS, self.edit_method) + signals.status_prompt_onekey.send( + prompt = "Method", + keys = common.METHOD_OPTIONS, + callback = self.edit_method + ) elif part == "c" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: - self.master.prompt_edit("Code", str(message.code), self.set_resp_code) + signals.status_prompt.send( + prompt = "Code: ", + text = str(message.code), + callback = self.set_resp_code + ) elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: - self.master.prompt_edit("Message", message.msg, self.set_resp_msg) + signals.status_prompt.send( + prompt = "Message: ", + text = message.msg, + callback = self.set_resp_msg + ) self.master.refresh_flow(self.flow) def _view_nextprev_flow(self, np, flow): @@ -684,9 +704,9 @@ class FlowView(urwid.WidgetWrap): signals.status_message.send(message="Duplicated.") elif key == "e": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: - self.master.prompt_onekey( - "Edit request", - ( + signals.status_prompt_onekey.send( + prompt = "Edit request", + keys = ( ("query", "q"), ("path", "p"), ("url", "u"), @@ -695,18 +715,18 @@ class FlowView(urwid.WidgetWrap): ("raw body", "r"), ("method", "m"), ), - self.edit + callback = self.edit ) else: - self.master.prompt_onekey( - "Edit response", - ( + signals.status_prompt_onekey.send( + prompt = "Edit response", + keys = ( ("code", "c"), ("message", "m"), ("header", "h"), ("raw body", "r"), ), - self.edit + callback = self.edit ) key = None elif key == "f": @@ -727,10 +747,11 @@ class FlowView(urwid.WidgetWrap): elif key == "m": p = list(contentview.view_prompts) p.insert(0, ("Clear", "C")) - self.master.prompt_onekey( - "Display mode", - p, - self.change_this_display_mode + signals.status_prompt_onekey.send( + self, + prompt = "Display mode", + keys = p, + callback = self.change_this_display_mode ) key = None elif key == "p": @@ -748,11 +769,11 @@ class FlowView(urwid.WidgetWrap): self.master.refresh_flow(self.flow) signals.status_message.send(message="Reverted.") elif key == "W": - self.master.path_prompt( - "Save this flow: ", - self.state.last_saveload, - self.master.save_one_flow, - self.flow + signals.status_path_prompt.send( + prompt = "Save this flow: ", + text = self.state.last_saveload, + callback = self.master.save_one_flow, + args = (self.flow,) ) elif key == "v": if conn and conn.content: @@ -763,18 +784,20 @@ class FlowView(urwid.WidgetWrap): else: signals.status_message.send(message="Error! Set $EDITOR or $PAGER.") elif key == "|": - self.master.path_prompt( - "Send flow to script: ", self.state.last_script, - self.master.run_script_once, self.flow + signals.status_path_prompt.send( + prompt = "Send flow to script: ", + text = self.state.last_script, + callback = self.master.run_script_once, + args = (self.flow,) ) elif key == "x": - self.master.prompt_onekey( - "Delete body", - ( + signals.status_prompt_onekey.send( + prompt = "Delete body", + keys = ( ("completely", "c"), ("mark as missing", "m"), ), - self.delete_body + callback = self.delete_body ) key = None elif key == "X": @@ -787,22 +810,24 @@ class FlowView(urwid.WidgetWrap): if not conn.decode(): signals.status_message.send(message="Could not decode - invalid data?") else: - self.master.prompt_onekey( - "Select encoding: ", - ( + signals.status_prompt_onekey.send( + prompt = "Select encoding: ", + keys = ( ("gzip", "z"), ("deflate", "d"), ), - self.encode_callback, - conn + callback = self.encode_callback, + args = (conn,) ) self.master.refresh_flow(self.flow) elif key == "/": last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") search_prompt = "Search body ["+last_search_string+"]: " if last_search_string else "Search body: " - self.master.prompt(search_prompt, - None, - self.search) + signals.status_prompt.send( + prompt = search_prompt, + text = "", + callback = self.search + ) elif key == "n": self.search_again(backwards=False) elif key == "N": diff --git a/libmproxy/console/grideditor.py b/libmproxy/console/grideditor.py index 0b563c527..eb66e59e8 100644 --- a/libmproxy/console/grideditor.py +++ b/libmproxy/console/grideditor.py @@ -338,11 +338,20 @@ class GridEditor(urwid.WidgetWrap): self.walker.delete_focus() elif key == "r": if self.walker.get_current_value() is not None: - self.master.path_prompt("Read file: ", "", self.read_file) + signals.status_path_prompt.send( + self, + prompt = "Read file: ", + text = "", + callback = self.read_file + ) elif key == "R": if self.walker.get_current_value() is not None: - self.master.path_prompt( - "Read unescaped file: ", "", self.read_file, True + signals.status_path_prompt.send( + self, + prompt = "Read unescaped file: ", + text = "", + callback = self.read_file, + args = (True,) ) elif key == "e": o = self.walker.get_current_value() @@ -431,10 +440,10 @@ class HeaderEditor(GridEditor): def handle_key(self, key): if key == "U": - self.master.prompt_onekey( - "Add User-Agent header:", - [(i[0], i[1]) for i in http_uastrings.UASTRINGS], - self.set_user_agent, + signals.status_prompt_onekey.send( + prompt = "Add User-Agent header:", + keys = [(i[0], i[1]) for i in http_uastrings.UASTRINGS], + callback = self.set_user_agent, ) return True @@ -500,10 +509,10 @@ class SetHeadersEditor(GridEditor): def handle_key(self, key): if key == "U": - self.master.prompt_onekey( - "Add User-Agent header:", - [(i[0], i[1]) for i in http_uastrings.UASTRINGS], - self.set_user_agent, + signals.status_prompt_onekey.send( + prompt = "Add User-Agent header:", + keys = [(i[0], i[1]) for i in http_uastrings.UASTRINGS], + callback = self.set_user_agent, ) return True diff --git a/libmproxy/console/signals.py b/libmproxy/console/signals.py index 7b0ec9375..8fb35cff9 100644 --- a/libmproxy/console/signals.py +++ b/libmproxy/console/signals.py @@ -1,5 +1,19 @@ - import blinker +# Show a status message in the action bar status_message = blinker.Signal() + +# Prompt for input +status_prompt = blinker.Signal() + +# Prompt for a path +status_path_prompt = blinker.Signal() + +# Prompt for a single keystroke +status_prompt_onekey = blinker.Signal() + +# Call a callback in N seconds call_in = blinker.Signal() + +# Focus the body, footer or header of the main window +focus = blinker.Signal() diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py index a29767e45..c1a907bdc 100644 --- a/libmproxy/console/statusbar.py +++ b/libmproxy/console/statusbar.py @@ -2,7 +2,7 @@ import time import urwid -from . import pathedit, signals +from . import pathedit, signals, common from .. import utils @@ -11,18 +11,12 @@ class ActionBar(urwid.WidgetWrap): urwid.WidgetWrap.__init__(self, None) self.clear() signals.status_message.connect(self.sig_message) + signals.status_prompt.connect(self.sig_prompt) + signals.status_path_prompt.connect(self.sig_path_prompt) + signals.status_prompt_onekey.connect(self.sig_prompt_onekey) - def clear(self): - self._w = urwid.Text("") - - def selectable(self): - return True - - def path_prompt(self, prompt, text): - self._w = pathedit.PathEdit(prompt, text) - - def prompt(self, prompt, text = ""): - self._w = urwid.Edit(prompt, text or "") + self.prompting = False + self.onekey = False def sig_message(self, sender, message, expire=None): w = urwid.Text(message) @@ -33,6 +27,72 @@ class ActionBar(urwid.WidgetWrap): self.clear() signals.call_in.send(seconds=expire, callback=cb) + def sig_prompt(self, sender, prompt, text, callback, args=()): + signals.focus.send(self, section="footer") + self._w = urwid.Edit(prompt, text or "") + self.prompting = (callback, args) + + def sig_path_prompt(self, sender, prompt, text, callback, args=()): + signals.focus.send(self, section="footer") + self._w = pathedit.PathEdit(prompt, text) + self.prompting = (callback, args) + + def sig_prompt_onekey(self, sender, prompt, keys, callback, args=()): + """ + Keys are a set of (word, key) tuples. The appropriate key in the + word is highlighted. + """ + signals.focus.send(self, section="footer") + prompt = [prompt, " ("] + mkup = [] + for i, e in enumerate(keys): + mkup.extend(common.highlight_key(e[0], e[1])) + if i < len(keys)-1: + mkup.append(",") + prompt.extend(mkup) + prompt.append(")? ") + self.onekey = set(i[1] for i in keys) + self._w = urwid.Edit(prompt, "") + self.prompting = (callback, args) + + def selectable(self): + return True + + def keypress(self, size, k): + if self.prompting: + if k == "esc": + self.prompt_done() + elif self.onekey: + if k == "enter": + self.prompt_done() + elif k in self.onekey: + self.prompt_execute(k) + elif k == "enter": + self.prompt_execute() + else: + if common.is_keypress(k): + self._w.keypress(size, k) + else: + return k + + def clear(self): + self._w = urwid.Text("") + + def prompt_done(self): + self.prompting = False + self.onekey = False + signals.status_message.send(message="") + signals.focus.send(self, section="body") + + def prompt_execute(self, txt=None): + if not txt: + txt = self._w.get_edit_text() + p, args = self.prompting + self.prompt_done() + msg = p(txt, *args) + if msg: + signals.status_message.send(message=msg, expire=1) + class StatusBar(urwid.WidgetWrap): def __init__(self, master, helptext): diff --git a/libmproxy/console/window.py b/libmproxy/console/window.py index 44a5a3167..55145c481 100644 --- a/libmproxy/console/window.py +++ b/libmproxy/console/window.py @@ -1,151 +1,144 @@ import urwid -from . import common, grideditor +from . import common, grideditor, signals, contentview class Window(urwid.Frame): def __init__(self, master, body, header, footer): urwid.Frame.__init__(self, body, header=header, footer=footer) self.master = master + signals.focus.connect(self.sig_focus) + + def sig_focus(self, sender, section): + self.focus_position = section def keypress(self, size, k): - if self.master.prompting: - if k == "esc": - self.master.prompt_cancel() - elif self.master.onekey: - if k == "enter": - self.master.prompt_cancel() - elif k in self.master.onekey: - self.master.prompt_execute(k) - elif k == "enter": - self.master.prompt_execute() + k = urwid.Frame.keypress(self, self.master.loop.screen_size, k) + if k == "?": + self.master.view_help() + elif k == "c": + if not self.master.client_playback: + signals.status_path_prompt.send( + self, + prompt = "Client replay: ", + text = self.master.state.last_saveload, + callback = self.master.client_playback_path + ) else: - if common.is_keypress(k): - urwid.Frame.keypress(self, self.master.loop.screen_size, k) - else: - return k - else: - k = urwid.Frame.keypress(self, self.master.loop.screen_size, k) - if k == "?": - self.master.view_help() - elif k == "c": - if not self.master.client_playback: - self.master.path_prompt( - "Client replay: ", - self.master.state.last_saveload, - self.master.client_playback_path - ) - else: - self.master.prompt_onekey( - "Stop current client replay?", - ( - ("yes", "y"), - ("no", "n"), - ), - self.master.stop_client_playback_prompt, - ) - elif k == "H": - self.master.view_grideditor( - grideditor.SetHeadersEditor( - self.master, - self.master.setheaders.get_specs(), - self.master.setheaders.set - ) - ) - elif k == "I": - self.master.view_grideditor( - grideditor.HostPatternEditor( - self.master, - [[x] for x in self.master.get_ignore_filter()], - self.master.edit_ignore_filter - ) - ) - elif k == "T": - self.master.view_grideditor( - grideditor.HostPatternEditor( - self.master, - [[x] for x in self.master.get_tcp_filter()], - self.master.edit_tcp_filter - ) - ) - elif k == "i": - self.master.prompt( - "Intercept filter: ", - self.master.state.intercept_txt, - self.master.set_intercept - ) - elif k == "Q": - raise urwid.ExitMainLoop - elif k == "q": - self.master.prompt_onekey( - "Quit", - ( + signals.status_prompt_onekey.send( + self, + prompt = "Stop current client replay?", + keys = ( ("yes", "y"), ("no", "n"), ), - self.master.quit, + callback = self.master.stop_client_playback_prompt, ) - elif k == "M": - self.master.prompt_onekey( - "Global default display mode", - contentview.view_prompts, - self.master.change_default_display_mode + elif k == "H": + self.master.view_grideditor( + grideditor.SetHeadersEditor( + self.master, + self.master.setheaders.get_specs(), + self.master.setheaders.set ) - elif k == "R": - self.master.view_grideditor( - grideditor.ReplaceEditor( - self.master, - self.master.replacehooks.get_specs(), - self.master.replacehooks.set - ) + ) + elif k == "I": + self.master.view_grideditor( + grideditor.HostPatternEditor( + self.master, + [[x] for x in self.master.get_ignore_filter()], + self.master.edit_ignore_filter ) - elif k == "s": - self.master.view_grideditor( - grideditor.ScriptEditor( - self.master, - [[i.command] for i in self.master.scripts], - self.master.edit_scripts - ) + ) + elif k == "T": + self.master.view_grideditor( + grideditor.HostPatternEditor( + self.master, + [[x] for x in self.master.get_tcp_filter()], + self.master.edit_tcp_filter ) - elif k == "S": - if not self.master.server_playback: - self.master.path_prompt( - "Server replay path: ", - self.master.state.last_saveload, - self.master.server_playback_path - ) - else: - self.master.prompt_onekey( - "Stop current server replay?", - ( - ("yes", "y"), - ("no", "n"), - ), - self.master.stop_server_playback_prompt, - ) - elif k == "o": - self.master.prompt_onekey( - "Options", - ( - ("anticache", "a"), - ("anticomp", "c"), - ("showhost", "h"), - ("killextra", "k"), - ("norefresh", "n"), - ("no-upstream-certs", "u"), - ), - self.master._change_options + ) + elif k == "i": + signals.status_prompt.send( + self, + prompt = "Intercept filter: ", + text = self.master.state.intercept_txt, + callback = self.master.set_intercept + ) + elif k == "Q": + raise urwid.ExitMainLoop + elif k == "q": + signals.status_prompt_onekey.send( + self, + prompt = "Quit", + keys = ( + ("yes", "y"), + ("no", "n"), + ), + callback = self.master.quit, + ) + elif k == "M": + signals.status_prompt_onekey.send( + prompt = "Global default display mode", + keys = contentview.view_prompts, + callback = self.master.change_default_display_mode + ) + elif k == "R": + self.master.view_grideditor( + grideditor.ReplaceEditor( + self.master, + self.master.replacehooks.get_specs(), + self.master.replacehooks.set ) - elif k == "t": - self.master.prompt( - "Sticky cookie filter: ", - self.master.stickycookie_txt, - self.master.set_stickycookie + ) + elif k == "s": + self.master.view_grideditor( + grideditor.ScriptEditor( + self.master, + [[i.command] for i in self.master.scripts], + self.master.edit_scripts ) - elif k == "u": - self.master.prompt( - "Sticky auth filter: ", - self.master.stickyauth_txt, - self.master.set_stickyauth + ) + elif k == "S": + if not self.master.server_playback: + signals.status_path_prompt.send( + self, + prompt = "Server replay path: ", + text = self.master.state.last_saveload, + callback = self.master.server_playback_path ) else: - return k - self.footer.redraw() + signals.status_prompt_onekey.send( + self, + prompt = "Stop current server replay?", + keys = ( + ("yes", "y"), + ("no", "n"), + ), + callback = self.master.stop_server_playback_prompt, + ) + elif k == "o": + signals.status_prompt_onekey.send( + prompt = "Options", + keys = ( + ("anticache", "a"), + ("anticomp", "c"), + ("showhost", "h"), + ("killextra", "k"), + ("norefresh", "n"), + ("no-upstream-certs", "u"), + ), + callback = self.master._change_options + ) + elif k == "t": + signals.status_prompt.send( + prompt = "Sticky cookie filter: ", + text = self.master.stickycookie_txt, + callback = self.master.set_stickycookie + ) + elif k == "u": + signals.status_prompt.send( + prompt = "Sticky auth filter: ", + text = self.master.stickyauth_txt, + callback = self.master.set_stickyauth + ) + else: + return k diff --git a/test/tools/testpatt b/test/tools/testpatt index f6d1169b2..d4546d483 100755 --- a/test/tools/testpatt +++ b/test/tools/testpatt @@ -2,8 +2,8 @@ # Generate a test pattern with pathoc PATHOD=http://localhost:9999 -pathoc localhost:8080 "get:'$PATHOD/p/200:p0,1:b@200b'" -pathoc localhost:8080 "get:'$PATHOD/p/300:p0,1:b@200b'" -pathoc localhost:8080 "get:'$PATHOD/p/400:p0,1:b@200b'" -pathoc localhost:8080 "get:'$PATHOD/p/500:p0,1:b@200b'" -pathoc localhost:8080 "get:'$PATHOD/p/600:p0,1:b@200b'" +pathoc localhost:8080 "get:'$PATHOD/p/200:p0,1:b@200b':b@200b" +pathoc localhost:8080 "get:'$PATHOD/p/300:p0,1:b@200b':b@200b" +pathoc localhost:8080 "get:'$PATHOD/p/400:p0,1:b@200b':b@200b" +pathoc localhost:8080 "get:'$PATHOD/p/500:p0,1:b@200b':b@200b" +pathoc localhost:8080 "get:'$PATHOD/p/600:p0,1:b@200b':b@200b" From 572000aa039a789ba35d4ef14e0c096256d6997d Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 13:59:34 +1300 Subject: [PATCH 022/170] Rationalise prompt calling conventions --- libmproxy/console/common.py | 8 ++++---- libmproxy/console/flowlist.py | 30 +++++++++++++++--------------- libmproxy/console/flowview.py | 18 +++++++++--------- libmproxy/console/grideditor.py | 8 ++++---- libmproxy/console/signals.py | 2 +- libmproxy/console/statusbar.py | 18 ++++++------------ libmproxy/console/window.py | 14 +++++++------- 7 files changed, 46 insertions(+), 52 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 185480db2..e4ecde916 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -203,7 +203,7 @@ def save_data(path, data, master, state): def ask_save_path(prompt, data, master, state): - signals.status_path_prompt.send( + signals.status_prompt_path.send( prompt = prompt, text = state.last_saveload, callback = save_data, @@ -260,7 +260,7 @@ def copy_flow(part, scope, flow, master, state): except RuntimeError: def save(k): if k == "y": - ask_save_path("Save data: ", data, master, state) + ask_save_path("Save data", data, master, state) signals.status_prompt_onekey.send( prompt = "Cannot copy binary data to clipboard. Save as file?", keys = ( @@ -316,14 +316,14 @@ def ask_save_body(part, master, state, flow): elif part == "q" and request_has_content: ask_save_path( - "Save request content: ", + "Save request content", flow.request.get_decoded_content(), master, state ) elif part == "s" and response_has_content: ask_save_path( - "Save response content: ", + "Save response content", flow.response.get_decoded_content(), master, state diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index d4dd89d88..f39188bb7 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -111,14 +111,14 @@ class ConnectionItem(urwid.WidgetWrap): def save_flows_prompt(self, k): if k == "a": - signals.status_path_prompt.send( - prompt = "Save all flows to: ", + signals.status_prompt_path.send( + prompt = "Save all flows to", text = self.state.last_saveload, callback = self.master.save_flows ) else: - signals.status_path_prompt.send( - prompt = "Save this flow to: ", + signals.status_prompt_path.send( + prompt = "Save this flow to", text = self.state.last_saveload, callback = self.master.save_one_flow, args = (self.flow,) @@ -150,8 +150,8 @@ class ConnectionItem(urwid.WidgetWrap): self.master.options.replay_ignore_host ) else: - signals.status_path_prompt.send( - prompt = "Server replay path: ", + signals.status_prompt_path.send( + prompt = "Server replay path", text = self.state.last_saveload, callback = self.master.server_playback_path ) @@ -216,8 +216,8 @@ class ConnectionItem(urwid.WidgetWrap): if self.flow.request: self.master.view_flow(self.flow) elif key == "|": - signals.status_path_prompt.send( - prompt = "Send flow to script: ", + signals.status_prompt_path.send( + prompt = "Send flow to script", text = self.state.last_script, callback = self.master.run_script_once, args = (self.flow,) @@ -269,7 +269,7 @@ class FlowListBox(urwid.ListBox): if k == "e": signals.status_prompt.send( self, - prompt = "Method:", + prompt = "Method", text = "", callback = self.get_method_raw ) @@ -282,7 +282,7 @@ class FlowListBox(urwid.ListBox): def get_url(self, method): signals.status_prompt.send( - prompt = "URL:", + prompt = "URL", text = "http://www.example.com/", callback = self.new_request, args = (method,) @@ -308,14 +308,14 @@ class FlowListBox(urwid.ListBox): self.master.toggle_eventlog() elif key == "l": signals.status_prompt.send( - prompt = "Limit: ", + prompt = "Limit", text = self.master.state.limit_txt, callback = self.master.set_limit ) elif key == "L": - signals.status_path_prompt.send( + signals.status_prompt_path.send( self, - prompt = "Load flows: ", + prompt = "Load flows", text = self.master.state.last_saveload, callback = self.master.load_flows_callback ) @@ -331,9 +331,9 @@ class FlowListBox(urwid.ListBox): if self.master.stream: self.master.stop_stream() else: - signals.status_path_prompt.send( + signals.status_prompt_path.send( self, - prompt = "Stream flows to: ", + prompt = "Stream flows to", text = self.master.state.last_saveload, callback = self.master.start_stream_to_path ) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 941ceb942..b9d5fbcac 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -493,7 +493,7 @@ class FlowView(urwid.WidgetWrap): def edit_method(self, m): if m == "e": signals.status_prompt.send( - prompt = "Method: ", + prompt = "Method", text = self.flow.request.method, callback = self.set_method_raw ) @@ -592,7 +592,7 @@ class FlowView(urwid.WidgetWrap): self.master.view_grideditor(grideditor.QueryEditor(self.master, message.get_query().lst, self.set_query, message)) elif part == "u" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: signals.status_prompt.send( - prompt = "URL: ", + prompt = "URL", text = message.url, callback = self.set_url ) @@ -604,13 +604,13 @@ class FlowView(urwid.WidgetWrap): ) elif part == "c" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: signals.status_prompt.send( - prompt = "Code: ", + prompt = "Code", text = str(message.code), callback = self.set_resp_code ) elif part == "m" and self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE: signals.status_prompt.send( - prompt = "Message: ", + prompt = "Message", text = message.msg, callback = self.set_resp_msg ) @@ -769,8 +769,8 @@ class FlowView(urwid.WidgetWrap): self.master.refresh_flow(self.flow) signals.status_message.send(message="Reverted.") elif key == "W": - signals.status_path_prompt.send( - prompt = "Save this flow: ", + signals.status_prompt_path.send( + prompt = "Save this flow", text = self.state.last_saveload, callback = self.master.save_one_flow, args = (self.flow,) @@ -784,8 +784,8 @@ class FlowView(urwid.WidgetWrap): else: signals.status_message.send(message="Error! Set $EDITOR or $PAGER.") elif key == "|": - signals.status_path_prompt.send( - prompt = "Send flow to script: ", + signals.status_prompt_path.send( + prompt = "Send flow to script", text = self.state.last_script, callback = self.master.run_script_once, args = (self.flow,) @@ -822,7 +822,7 @@ class FlowView(urwid.WidgetWrap): self.master.refresh_flow(self.flow) elif key == "/": last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") - search_prompt = "Search body ["+last_search_string+"]: " if last_search_string else "Search body: " + search_prompt = "Search body ["+last_search_string+"]" if last_search_string else "Search body" signals.status_prompt.send( prompt = search_prompt, text = "", diff --git a/libmproxy/console/grideditor.py b/libmproxy/console/grideditor.py index eb66e59e8..e7c9854be 100644 --- a/libmproxy/console/grideditor.py +++ b/libmproxy/console/grideditor.py @@ -338,17 +338,17 @@ class GridEditor(urwid.WidgetWrap): self.walker.delete_focus() elif key == "r": if self.walker.get_current_value() is not None: - signals.status_path_prompt.send( + signals.status_prompt_path.send( self, - prompt = "Read file: ", + prompt = "Read file", text = "", callback = self.read_file ) elif key == "R": if self.walker.get_current_value() is not None: - signals.status_path_prompt.send( + signals.status_prompt_path.send( self, - prompt = "Read unescaped file: ", + prompt = "Read unescaped file", text = "", callback = self.read_file, args = (True,) diff --git a/libmproxy/console/signals.py b/libmproxy/console/signals.py index 8fb35cff9..e8944afb6 100644 --- a/libmproxy/console/signals.py +++ b/libmproxy/console/signals.py @@ -7,7 +7,7 @@ status_message = blinker.Signal() status_prompt = blinker.Signal() # Prompt for a path -status_path_prompt = blinker.Signal() +status_prompt_path = blinker.Signal() # Prompt for a single keystroke status_prompt_onekey = blinker.Signal() diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py index c1a907bdc..7ff26b155 100644 --- a/libmproxy/console/statusbar.py +++ b/libmproxy/console/statusbar.py @@ -12,7 +12,7 @@ class ActionBar(urwid.WidgetWrap): self.clear() signals.status_message.connect(self.sig_message) signals.status_prompt.connect(self.sig_prompt) - signals.status_path_prompt.connect(self.sig_path_prompt) + signals.status_prompt_path.connect(self.sig_path_prompt) signals.status_prompt_onekey.connect(self.sig_prompt_onekey) self.prompting = False @@ -27,14 +27,17 @@ class ActionBar(urwid.WidgetWrap): self.clear() signals.call_in.send(seconds=expire, callback=cb) + def prep_prompt(self, p): + return p.strip() + ": " + def sig_prompt(self, sender, prompt, text, callback, args=()): signals.focus.send(self, section="footer") - self._w = urwid.Edit(prompt, text or "") + self._w = urwid.Edit(self.prep_prompt(prompt), text or "") self.prompting = (callback, args) def sig_path_prompt(self, sender, prompt, text, callback, args=()): signals.focus.send(self, section="footer") - self._w = pathedit.PathEdit(prompt, text) + self._w = pathedit.PathEdit(self.prep_prompt(prompt), text) self.prompting = (callback, args) def sig_prompt_onekey(self, sender, prompt, keys, callback, args=()): @@ -230,12 +233,3 @@ class StatusBar(urwid.WidgetWrap): def selectable(self): return True - - def get_edit_text(self): - return self.ab._w.get_edit_text() - - def path_prompt(self, prompt, text): - return self.ab.path_prompt(prompt, text) - - def prompt(self, prompt, text = ""): - self.ab.prompt(prompt, text) diff --git a/libmproxy/console/window.py b/libmproxy/console/window.py index 55145c481..87f06637a 100644 --- a/libmproxy/console/window.py +++ b/libmproxy/console/window.py @@ -16,9 +16,9 @@ class Window(urwid.Frame): self.master.view_help() elif k == "c": if not self.master.client_playback: - signals.status_path_prompt.send( + signals.status_prompt_path.send( self, - prompt = "Client replay: ", + prompt = "Client replay", text = self.master.state.last_saveload, callback = self.master.client_playback_path ) @@ -59,7 +59,7 @@ class Window(urwid.Frame): elif k == "i": signals.status_prompt.send( self, - prompt = "Intercept filter: ", + prompt = "Intercept filter", text = self.master.state.intercept_txt, callback = self.master.set_intercept ) @@ -99,9 +99,9 @@ class Window(urwid.Frame): ) elif k == "S": if not self.master.server_playback: - signals.status_path_prompt.send( + signals.status_prompt_path.send( self, - prompt = "Server replay path: ", + prompt = "Server replay path", text = self.master.state.last_saveload, callback = self.master.server_playback_path ) @@ -130,13 +130,13 @@ class Window(urwid.Frame): ) elif k == "t": signals.status_prompt.send( - prompt = "Sticky cookie filter: ", + prompt = "Sticky cookie filter", text = self.master.stickycookie_txt, callback = self.master.set_stickycookie ) elif k == "u": signals.status_prompt.send( - prompt = "Sticky auth filter: ", + prompt = "Sticky auth filter", text = self.master.stickyauth_txt, callback = self.master.set_stickyauth ) From 200498e7aa57effd7158c8d735f95c6556203a07 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 14:14:44 +1300 Subject: [PATCH 023/170] Simplify the way in which path prompts keep state In the past, we kept the last path the user specified for a number of different path types to pre-seed the path prompt. Now, we no longer distinguish between types, and pre-seed with the last used directory regardless. --- libmproxy/console/__init__.py | 6 ------ libmproxy/console/common.py | 2 -- libmproxy/console/flowlist.py | 6 ------ libmproxy/console/flowview.py | 2 -- libmproxy/console/grideditor.py | 2 -- libmproxy/console/statusbar.py | 22 ++++++++++++++++------ libmproxy/console/window.py | 2 -- 7 files changed, 16 insertions(+), 26 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index d8eb8a41f..34abe6f4f 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -31,8 +31,6 @@ class ConsoleState(flow.State): self.view_mode = common.VIEW_LIST self.view_flow_mode = common.VIEW_FLOW_REQUEST - self.last_script = "" - self.last_saveload = "" self.flowsettings = weakref.WeakKeyDictionary() def add_flow_setting(self, flow, key, value): @@ -258,7 +256,6 @@ class ConsoleMaster(flow.FlowMaster): self._run_script_method("error", s, f) s.unload() self.refresh_flow(f) - self.state.last_script = command def set_script(self, command): if not command: @@ -266,7 +263,6 @@ class ConsoleMaster(flow.FlowMaster): ret = self.load_script(command) if ret: signals.status_message.send(message=ret) - self.state.last_script = command def toggle_eventlog(self): self.eventlog = not self.eventlog @@ -501,7 +497,6 @@ class ConsoleMaster(flow.FlowMaster): self.help_context = flowview.help_context def _write_flows(self, path, flows): - self.state.last_saveload = path if not path: return path = os.path.expanduser(path) @@ -527,7 +522,6 @@ class ConsoleMaster(flow.FlowMaster): return ret or "Flows loaded from %s"%path def load_flows_path(self, path): - self.state.last_saveload = path reterr = None try: flow.FlowMaster.load_flows_file(self, path) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index e4ecde916..c0593af48 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -193,7 +193,6 @@ def raw_format_flow(f, focus, extended, padding): def save_data(path, data, master, state): if not path: return - state.last_saveload = path path = os.path.expanduser(path) try: with file(path, "wb") as f: @@ -205,7 +204,6 @@ def save_data(path, data, master, state): def ask_save_path(prompt, data, master, state): signals.status_prompt_path.send( prompt = prompt, - text = state.last_saveload, callback = save_data, args = (data, master, state) ) diff --git a/libmproxy/console/flowlist.py b/libmproxy/console/flowlist.py index f39188bb7..946bd97b2 100644 --- a/libmproxy/console/flowlist.py +++ b/libmproxy/console/flowlist.py @@ -113,13 +113,11 @@ class ConnectionItem(urwid.WidgetWrap): if k == "a": signals.status_prompt_path.send( prompt = "Save all flows to", - text = self.state.last_saveload, callback = self.master.save_flows ) else: signals.status_prompt_path.send( prompt = "Save this flow to", - text = self.state.last_saveload, callback = self.master.save_one_flow, args = (self.flow,) ) @@ -152,7 +150,6 @@ class ConnectionItem(urwid.WidgetWrap): else: signals.status_prompt_path.send( prompt = "Server replay path", - text = self.state.last_saveload, callback = self.master.server_playback_path ) @@ -218,7 +215,6 @@ class ConnectionItem(urwid.WidgetWrap): elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", - text = self.state.last_script, callback = self.master.run_script_once, args = (self.flow,) ) @@ -316,7 +312,6 @@ class FlowListBox(urwid.ListBox): signals.status_prompt_path.send( self, prompt = "Load flows", - text = self.master.state.last_saveload, callback = self.master.load_flows_callback ) elif key == "n": @@ -334,7 +329,6 @@ class FlowListBox(urwid.ListBox): signals.status_prompt_path.send( self, prompt = "Stream flows to", - text = self.master.state.last_saveload, callback = self.master.start_stream_to_path ) else: diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index b9d5fbcac..d63b8a8cc 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -771,7 +771,6 @@ class FlowView(urwid.WidgetWrap): elif key == "W": signals.status_prompt_path.send( prompt = "Save this flow", - text = self.state.last_saveload, callback = self.master.save_one_flow, args = (self.flow,) ) @@ -786,7 +785,6 @@ class FlowView(urwid.WidgetWrap): elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", - text = self.state.last_script, callback = self.master.run_script_once, args = (self.flow,) ) diff --git a/libmproxy/console/grideditor.py b/libmproxy/console/grideditor.py index e7c9854be..dc3bad0eb 100644 --- a/libmproxy/console/grideditor.py +++ b/libmproxy/console/grideditor.py @@ -341,7 +341,6 @@ class GridEditor(urwid.WidgetWrap): signals.status_prompt_path.send( self, prompt = "Read file", - text = "", callback = self.read_file ) elif key == "R": @@ -349,7 +348,6 @@ class GridEditor(urwid.WidgetWrap): signals.status_prompt_path.send( self, prompt = "Read unescaped file", - text = "", callback = self.read_file, args = (True,) ) diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py index 7ff26b155..30819188e 100644 --- a/libmproxy/console/statusbar.py +++ b/libmproxy/console/statusbar.py @@ -1,4 +1,5 @@ import time +import os.path import urwid @@ -15,8 +16,12 @@ class ActionBar(urwid.WidgetWrap): signals.status_prompt_path.connect(self.sig_path_prompt) signals.status_prompt_onekey.connect(self.sig_prompt_onekey) + self.last_path = "" + self.prompting = False self.onekey = False + self.pathprompt = False + def sig_message(self, sender, message, expire=None): w = urwid.Text(message) @@ -35,9 +40,13 @@ class ActionBar(urwid.WidgetWrap): self._w = urwid.Edit(self.prep_prompt(prompt), text or "") self.prompting = (callback, args) - def sig_path_prompt(self, sender, prompt, text, callback, args=()): + def sig_path_prompt(self, sender, prompt, callback, args=()): signals.focus.send(self, section="footer") - self._w = pathedit.PathEdit(self.prep_prompt(prompt), text) + self._w = pathedit.PathEdit( + self.prep_prompt(prompt), + os.path.dirname(self.last_path) + ) + self.pathprompt = True self.prompting = (callback, args) def sig_prompt_onekey(self, sender, prompt, keys, callback, args=()): @@ -71,7 +80,7 @@ class ActionBar(urwid.WidgetWrap): elif k in self.onekey: self.prompt_execute(k) elif k == "enter": - self.prompt_execute() + self.prompt_execute(self._w.get_edit_text()) else: if common.is_keypress(k): self._w.keypress(size, k) @@ -84,12 +93,13 @@ class ActionBar(urwid.WidgetWrap): def prompt_done(self): self.prompting = False self.onekey = False + self.pathprompt = False signals.status_message.send(message="") signals.focus.send(self, section="body") - def prompt_execute(self, txt=None): - if not txt: - txt = self._w.get_edit_text() + def prompt_execute(self, txt): + if self.pathprompt: + self.last_path = txt p, args = self.prompting self.prompt_done() msg = p(txt, *args) diff --git a/libmproxy/console/window.py b/libmproxy/console/window.py index 87f06637a..d686f61dd 100644 --- a/libmproxy/console/window.py +++ b/libmproxy/console/window.py @@ -19,7 +19,6 @@ class Window(urwid.Frame): signals.status_prompt_path.send( self, prompt = "Client replay", - text = self.master.state.last_saveload, callback = self.master.client_playback_path ) else: @@ -102,7 +101,6 @@ class Window(urwid.Frame): signals.status_prompt_path.send( self, prompt = "Server replay path", - text = self.master.state.last_saveload, callback = self.master.server_playback_path ) else: From 941584623281905fec22d8857c5501d196c051f7 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 22 Mar 2015 02:25:47 +0100 Subject: [PATCH 024/170] web: raw content view --- libmproxy/web/static/app.css | 3 +- libmproxy/web/static/app.js | 58 +++++++++++++++++-- web/src/css/flowdetail.less | 3 +- web/src/js/components/flowview/contentview.js | 43 ++++++++++++-- web/src/js/flow/utils.js | 13 +++++ 5 files changed, 107 insertions(+), 13 deletions(-) diff --git a/libmproxy/web/static/app.css b/libmproxy/web/static/app.css index 91e847a49..ccaefe92b 100644 --- a/libmproxy/web/static/app.css +++ b/libmproxy/web/static/app.css @@ -271,7 +271,8 @@ header .menu { } .flow-detail { width: 100%; - overflow: auto; + overflow-x: auto; + overflow-y: scroll; } .flow-detail nav { background-color: #F2F2F2; diff --git a/libmproxy/web/static/app.js b/libmproxy/web/static/app.js index eb8ef45e4..2254b4154 100644 --- a/libmproxy/web/static/app.js +++ b/libmproxy/web/static/app.js @@ -1195,23 +1195,56 @@ var Image = React.createClass({displayName: "Image", } }, render: function () { - var message_name = this.props.flow.request === this.props.message ? "request" : "response"; - var url = "/flows/" + this.props.flow.id + "/" + message_name + "/content"; + var url = MessageUtils.getContentURL(this.props.flow, this.props.message); return React.createElement("div", {className: "flowview-image"}, React.createElement("img", {src: url, alt: "preview", className: "img-thumbnail"}) ); } }); +var RawMixin = { + getInitialState: function () { + return { + content: undefined + } + }, + requestContent: function (nextProps) { + this.setState({content: undefined}); + var request = MessageUtils.getContent(nextProps.flow, nextProps.message); + request.done(function (data) { + this.setState({content: data}); + }.bind(this)).fail(function (jqXHR, textStatus, errorThrown) { + this.setState({content: "AJAX Error: " + textStatus}); + }.bind(this)); + + }, + componentWillMount: function () { + this.requestContent(this.props); + }, + componentWillReceiveProps: function (nextProps) { + if (nextProps.message !== this.props.message) { + this.requestContent(nextProps); + } + }, + render: function () { + if (!this.state.content) { + return React.createElement("div", {className: "text-center"}, + React.createElement("i", {className: "fa fa-spinner fa-spin"}) + ); + } + return this.renderContent(); + } +}; + var Raw = React.createClass({displayName: "Raw", + mixins: [RawMixin], statics: { matches: function (message) { return true; } }, - render: function () { - //FIXME - return React.createElement("div", null, "raw"); + renderContent: function () { + return React.createElement("pre", null, this.state.content); } }); @@ -4426,6 +4459,7 @@ module.exports = (function() { },{"../flow/utils.js":21}],21:[function(require,module,exports){ var _ = require("lodash"); +var $ = require("jquery"); var MessageUtils = { getContentType: function (message) { @@ -4461,6 +4495,18 @@ var MessageUtils = { } } return false; + }, + getContentURL: function(flow, message){ + if(message === flow.request){ + message = "request"; + } else if (message === flow.response){ + message = "response"; + } + return "/flows/" + flow.id + "/" + message + "/content"; + }, + getContent: function(flow, message){ + var url = MessageUtils.getContentURL(flow, message); + return $.get(url); } }; @@ -4492,7 +4538,7 @@ module.exports = { MessageUtils: MessageUtils }; -},{"lodash":"lodash"}],22:[function(require,module,exports){ +},{"jquery":"jquery","lodash":"lodash"}],22:[function(require,module,exports){ var _ = require("lodash"); var $ = require("jquery"); diff --git a/web/src/css/flowdetail.less b/web/src/css/flowdetail.less index 453cf425e..9feb72452 100644 --- a/web/src/css/flowdetail.less +++ b/web/src/css/flowdetail.less @@ -5,7 +5,8 @@ .flow-detail { width: 100%; - overflow: auto; + overflow-x: auto; + overflow-y: scroll; nav { background-color: #F2F2F2; diff --git a/web/src/js/components/flowview/contentview.js b/web/src/js/components/flowview/contentview.js index 09a64bb20..30a40faab 100644 --- a/web/src/js/components/flowview/contentview.js +++ b/web/src/js/components/flowview/contentview.js @@ -12,23 +12,56 @@ var Image = React.createClass({ } }, render: function () { - var message_name = this.props.flow.request === this.props.message ? "request" : "response"; - var url = "/flows/" + this.props.flow.id + "/" + message_name + "/content"; + var url = MessageUtils.getContentURL(this.props.flow, this.props.message); return
preview
; } }); +var RawMixin = { + getInitialState: function () { + return { + content: undefined + } + }, + requestContent: function (nextProps) { + this.setState({content: undefined}); + var request = MessageUtils.getContent(nextProps.flow, nextProps.message); + request.done(function (data) { + this.setState({content: data}); + }.bind(this)).fail(function (jqXHR, textStatus, errorThrown) { + this.setState({content: "AJAX Error: " + textStatus}); + }.bind(this)); + + }, + componentWillMount: function () { + this.requestContent(this.props); + }, + componentWillReceiveProps: function (nextProps) { + if (nextProps.message !== this.props.message) { + this.requestContent(nextProps); + } + }, + render: function () { + if (!this.state.content) { + return
+ +
; + } + return this.renderContent(); + } +}; + var Raw = React.createClass({ + mixins: [RawMixin], statics: { matches: function (message) { return true; } }, - render: function () { - //FIXME - return
raw
; + renderContent: function () { + return
{this.state.content}
; } }); diff --git a/web/src/js/flow/utils.js b/web/src/js/flow/utils.js index dd7f763b3..a67db94f7 100644 --- a/web/src/js/flow/utils.js +++ b/web/src/js/flow/utils.js @@ -1,4 +1,5 @@ var _ = require("lodash"); +var $ = require("jquery"); var MessageUtils = { getContentType: function (message) { @@ -34,6 +35,18 @@ var MessageUtils = { } } return false; + }, + getContentURL: function(flow, message){ + if(message === flow.request){ + message = "request"; + } else if (message === flow.response){ + message = "response"; + } + return "/flows/" + flow.id + "/" + message + "/content"; + }, + getContent: function(flow, message){ + var url = MessageUtils.getContentURL(flow, message); + return $.get(url); } }; From c9a09754464e27a5f34295d8a1c0b435248c104c Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 15:11:54 +1300 Subject: [PATCH 025/170] console: observe state objects for changes, fire event to update status bar. --- libmproxy/console/__init__.py | 9 +++++++++ libmproxy/console/signals.py | 3 +++ libmproxy/console/statusbar.py | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index 34abe6f4f..b593d2821 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -33,6 +33,10 @@ class ConsoleState(flow.State): self.flowsettings = weakref.WeakKeyDictionary() + def __setattr__(self, name, value): + self.__dict__[name] = value + signals.update_settings.send(self) + def add_flow_setting(self, flow, key, value): d = self.flowsettings.setdefault(flow, {}) d[key] = value @@ -212,6 +216,10 @@ class ConsoleMaster(flow.FlowMaster): self.start_app(self.options.app_host, self.options.app_port) signals.call_in.connect(self.sig_call_in) + def __setattr__(self, name, value): + self.__dict__[name] = value + signals.update_settings.send(self) + def sig_call_in(self, sender, seconds, callback, args=()): def cb(*_): return callback(*args) @@ -598,6 +606,7 @@ class ConsoleMaster(flow.FlowMaster): elif a == "u": self.server.config.no_upstream_cert =\ not self.server.config.no_upstream_cert + signals.update_settings.send(self) def shutdown(self): self.state.killall(self) diff --git a/libmproxy/console/signals.py b/libmproxy/console/signals.py index e8944afb6..a62b2a4e1 100644 --- a/libmproxy/console/signals.py +++ b/libmproxy/console/signals.py @@ -17,3 +17,6 @@ call_in = blinker.Signal() # Focus the body, footer or header of the main window focus = blinker.Signal() + +# Fired when settings change +update_settings = blinker.Signal() diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py index 30819188e..7663ee44b 100644 --- a/libmproxy/console/statusbar.py +++ b/libmproxy/console/statusbar.py @@ -113,6 +113,10 @@ class StatusBar(urwid.WidgetWrap): self.ab = ActionBar() self.ib = urwid.WidgetWrap(urwid.Text("")) self._w = urwid.Pile([self.ib, self.ab]) + signals.update_settings.connect(self.sig_update_settings) + + def sig_update_settings(self, sender): + self.redraw() def keypress(self, *args, **kwargs): return self.ab.keypress(*args, **kwargs) From aa9a38522f5fbfef556578b6018ad365ad5e844d Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 15:58:32 +1300 Subject: [PATCH 026/170] Remove refresh_flow mechanism in favor of a signal-based implementation --- libmproxy/console/__init__.py | 21 +++++-------- libmproxy/console/flowview.py | 58 +++++++++++++++++++---------------- libmproxy/console/signals.py | 3 ++ 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index b593d2821..d988ba841 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -263,7 +263,7 @@ class ConsoleMaster(flow.FlowMaster): if f.error: self._run_script_method("error", s, f) s.unload() - self.refresh_flow(f) + signals.flow_change.send(self, flow = f) def set_script(self, command): if not command: @@ -378,7 +378,7 @@ class ConsoleMaster(flow.FlowMaster): changed = self.tick(self.masterq, timeout=0) if changed: self.loop.draw_screen() - self.statusbar.redraw() + signals.update_settings.send() self.loop.set_alarm_in(0.01, self.ticker) def run(self): @@ -397,7 +397,6 @@ class ConsoleMaster(flow.FlowMaster): screen = self.ui, ) self.view_flowlist() - self.statusbar.redraw() self.server.start_slave( controller.Slave, @@ -446,7 +445,6 @@ class ConsoleMaster(flow.FlowMaster): header = self.header, footer = self.statusbar ) - self.statusbar.redraw() return self.view def view_help(self): @@ -633,15 +631,10 @@ class ConsoleMaster(flow.FlowMaster): def refresh_focus(self): if self.state.view: - self.refresh_flow(self.state.view[self.state.focus]) - - def refresh_flow(self, c): - if hasattr(self.header, "refresh_flow"): - self.header.refresh_flow(c) - if hasattr(self.body, "refresh_flow"): - self.body.refresh_flow(c) - if hasattr(self.statusbar, "refresh_flow"): - self.statusbar.refresh_flow(c) + signals.flow_change.send( + self, + flow = self.state.view[self.state.focus] + ) def process_flow(self, f): if self.state.intercept and f.match(self.state.intercept) and not f.request.is_replay: @@ -649,7 +642,7 @@ class ConsoleMaster(flow.FlowMaster): else: f.reply() self.sync_list_view() - self.refresh_flow(f) + signals.flow_change.send(self, flow = f) def clear_events(self): self.eventlist[:] = [] diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index d63b8a8cc..2dd2cb824 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -88,10 +88,17 @@ class FlowViewHeader(urwid.WidgetWrap): def __init__(self, master, f): self.master, self.flow = master, f self._w = common.format_flow(f, False, extended=True, padding=0, hostheader=self.master.showhost) + signals.flow_change.connect(self.sig_flow_change) - def refresh_flow(self, f): - if f == self.flow: - self._w = common.format_flow(f, False, extended=True, padding=0, hostheader=self.master.showhost) + def sig_flow_change(self, sender, flow): + if flow == self.flow: + self._w = common.format_flow( + flow, + False, + extended=True, + padding=0, + hostheader=self.master.showhost + ) class CallbackCache: @@ -119,6 +126,14 @@ class FlowView(urwid.WidgetWrap): self.view_response() else: self.view_request() + signals.flow_change.connect(self.sig_flow_change) + + def sig_flow_change(self, sender, flow): + if flow == self.flow: + if self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE and self.flow.response: + self.view_response() + else: + self.view_request() def _cached_content_view(self, viewmode, hdrItems, content, limit, is_request): return contentview.get_content_view(viewmode, hdrItems, content, limit, self.master.add_event, is_request) @@ -332,7 +347,7 @@ class FlowView(urwid.WidgetWrap): list_box = urwid.ListBox(merged) list_box.set_focus(focus_position + 2) self._w = self.wrap_body(const, list_box) - self.master.statusbar.redraw() + signals.update_settings.send(self) self.last_displayed_body = list_box @@ -456,7 +471,6 @@ class FlowView(urwid.WidgetWrap): self.state.view_flow_mode = common.VIEW_FLOW_REQUEST body = self.conn_text(self.flow.request) self._w = self.wrap_body(common.VIEW_FLOW_REQUEST, body) - self.master.statusbar.redraw() def view_response(self): self.state.view_flow_mode = common.VIEW_FLOW_RESPONSE @@ -476,19 +490,11 @@ class FlowView(urwid.WidgetWrap): ] ) self._w = self.wrap_body(common.VIEW_FLOW_RESPONSE, body) - self.master.statusbar.redraw() - - def refresh_flow(self, c=None): - if c == self.flow: - if self.state.view_flow_mode == common.VIEW_FLOW_RESPONSE and self.flow.response: - self.view_response() - else: - self.view_request() def set_method_raw(self, m): if m: self.flow.request.method = m - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def edit_method(self, m): if m == "e": @@ -501,7 +507,7 @@ class FlowView(urwid.WidgetWrap): for i in common.METHOD_OPTIONS: if i[1] == m: self.flow.request.method = i[0].upper() - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def set_url(self, url): request = self.flow.request @@ -509,7 +515,7 @@ class FlowView(urwid.WidgetWrap): request.url = str(url) except ValueError: return "Invalid URL." - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def set_resp_code(self, code): response = self.flow.response @@ -520,12 +526,12 @@ class FlowView(urwid.WidgetWrap): import BaseHTTPServer if BaseHTTPServer.BaseHTTPRequestHandler.responses.has_key(int(code)): response.msg = BaseHTTPServer.BaseHTTPRequestHandler.responses[int(code)][0] - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def set_resp_msg(self, msg): response = self.flow.response response.msg = msg - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def set_headers(self, lst, conn): conn.headers = flow.ODictCaseless(lst) @@ -614,7 +620,7 @@ class FlowView(urwid.WidgetWrap): text = message.msg, callback = self.set_resp_msg ) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def _view_nextprev_flow(self, np, flow): try: @@ -642,7 +648,7 @@ class FlowView(urwid.WidgetWrap): (self.state.view_flow_mode, "prettyview"), contentview.get_by_shortcut(t) ) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def delete_body(self, t): if t == "m": @@ -653,7 +659,7 @@ class FlowView(urwid.WidgetWrap): self.flow.request.content = val else: self.flow.response.content = val - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) def keypress(self, size, key): if key == " ": @@ -736,7 +742,7 @@ class FlowView(urwid.WidgetWrap): (self.state.view_flow_mode, "fullcontents"), True ) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) signals.status_message.send(message="") elif key == "g": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: @@ -760,13 +766,13 @@ class FlowView(urwid.WidgetWrap): r = self.master.replay_request(self.flow) if r: signals.status_message.send(message=r) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) elif key == "V": if not self.flow.modified(): signals.status_message.send(message="Flow not modified.") return self.state.revert(self.flow) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) signals.status_message.send(message="Reverted.") elif key == "W": signals.status_prompt_path.send( @@ -817,7 +823,7 @@ class FlowView(urwid.WidgetWrap): callback = self.encode_callback, args = (conn,) ) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) elif key == "/": last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") search_prompt = "Search body ["+last_search_string+"]" if last_search_string else "Search body" @@ -839,4 +845,4 @@ class FlowView(urwid.WidgetWrap): "d": "deflate", } conn.encode(encoding_map[key]) - self.master.refresh_flow(self.flow) + signals.flow_change.send(self, flow = self.flow) diff --git a/libmproxy/console/signals.py b/libmproxy/console/signals.py index a62b2a4e1..9afde6f45 100644 --- a/libmproxy/console/signals.py +++ b/libmproxy/console/signals.py @@ -20,3 +20,6 @@ focus = blinker.Signal() # Fired when settings change update_settings = blinker.Signal() + +# Fired when a flow changes +flow_change = blinker.Signal() From 120c8db8a413018bde60d156f480ade001b492ef Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 16:59:11 +1300 Subject: [PATCH 027/170] console: refactor the way we keep global view state --- libmproxy/console/__init__.py | 99 ++++++++++++++--------------- libmproxy/console/flowdetailview.py | 5 +- libmproxy/console/grideditor.py | 10 +-- libmproxy/console/help.py | 5 +- libmproxy/console/statusbar.py | 7 +- 5 files changed, 60 insertions(+), 66 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index d988ba841..f6f8e7210 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -188,8 +188,6 @@ class ConsoleMaster(flow.FlowMaster): self.eventlog = options.eventlog self.eventlist = urwid.SimpleListWalker([]) - self.statusbar = None - if options.client_replay: self.client_playback_path(options.client_replay) @@ -287,12 +285,7 @@ class ConsoleMaster(flow.FlowMaster): try: return flow.read_flows_from_paths([path]) except flow.FlowReadError as e: - if not self.statusbar: - print >> sys.stderr, e.strerror - sys.exit(1) - else: - signals.status_message.send(message=e.strerror) - return None + signals.status_message.send(message=e.strerror) def client_playback_path(self, path): flows = self._readflows(path) @@ -326,7 +319,9 @@ class ConsoleMaster(flow.FlowMaster): try: subprocess.call(cmd) except: - signals.status_message.send(message="Can't start editor: %s" % " ".join(c)) + signals.status_message.send( + message = "Can't start editor: %s" % " ".join(c) + ) else: data = open(name, "rb").read() self.ui.start() @@ -386,17 +381,11 @@ class ConsoleMaster(flow.FlowMaster): self.ui.set_terminal_properties(256) self.ui.register_palette(self.palette.palette()) self.flow_list_walker = flowlist.FlowListWalker(self, self.state) - self.view = None - self.statusbar = None - self.header = None - self.body = None self.help_context = None - self.onekey = False self.loop = urwid.MainLoop( - self.view, + urwid.SolidFill("x"), screen = self.ui, ) - self.view_flowlist() self.server.start_slave( controller.Slave, @@ -425,6 +414,11 @@ class ConsoleMaster(flow.FlowMaster): raise urwid.ExitMainLoop signal.signal(signal.SIGINT, exit) + self.loop.set_alarm_in( + 0.0001, + lambda *args: self.view_flowlist() + ) + try: self.loop.run() except Exception: @@ -438,43 +432,38 @@ class ConsoleMaster(flow.FlowMaster): sys.stderr.flush() self.shutdown() - def make_view(self): - self.view = window.Window( - self, - self.body, - header = self.header, - footer = self.statusbar - ) - return self.view - def view_help(self): - h = help.HelpView( + self.loop.widget = window.Window( self, - self.help_context, - (self.statusbar, self.body, self.header) + help.HelpView( + self, + self.help_context, + self.loop.widget, + ), + None, + statusbar.StatusBar(self, help.footer) ) - self.statusbar = statusbar.StatusBar(self, help.footer) - self.body = h - self.header = None - self.loop.widget = self.make_view() def view_flowdetails(self, flow): - h = flowdetailview.FlowDetailsView( + self.loop.widget = window.Window( self, - flow, - (self.statusbar, self.body, self.header) + flowdetailview.FlowDetailsView( + self, + flow, + self.loop.widget + ), + None, + statusbar.StatusBar(self, flowdetailview.footer) ) - self.statusbar = statusbar.StatusBar(self, flowdetailview.footer) - self.body = h - self.header = None - self.loop.widget = self.make_view() def view_grideditor(self, ge): - self.body = ge - self.header = None self.help_context = ge.make_help() - self.statusbar = statusbar.StatusBar(self, grideditor.footer) - self.loop.widget = self.make_view() + self.loop.widget = window.Window( + self, + ge, + None, + statusbar.StatusBar(self, grideditor.FOOTER) + ) def view_flowlist(self): if self.ui.started: @@ -483,24 +472,30 @@ class ConsoleMaster(flow.FlowMaster): self.state.set_focus(self.state.flow_count()) if self.eventlog: - self.body = flowlist.BodyPile(self) + body = flowlist.BodyPile(self) else: - self.body = flowlist.FlowListBox(self) - self.statusbar = statusbar.StatusBar(self, flowlist.footer) - self.header = None + body = flowlist.FlowListBox(self) self.state.view_mode = common.VIEW_LIST - self.loop.widget = self.make_view() self.help_context = flowlist.help_context + self.loop.widget = window.Window( + self, + body, + None, + statusbar.StatusBar(self, flowlist.footer) + ) + self.loop.draw_screen() def view_flow(self, flow): - self.body = flowview.FlowView(self, self.state, flow) - self.header = flowview.FlowViewHeader(self, flow) - self.statusbar = statusbar.StatusBar(self, flowview.footer) self.state.set_focus_flow(flow) self.state.view_mode = common.VIEW_FLOW - self.loop.widget = self.make_view() self.help_context = flowview.help_context + self.loop.widget = window.Window( + self, + flowview.FlowView(self, self.state, flow), + flowview.FlowViewHeader(self, flow), + statusbar.StatusBar(self, flowview.footer) + ) def _write_flows(self, path, flows): if not path: diff --git a/libmproxy/console/flowdetailview.py b/libmproxy/console/flowdetailview.py index f351bff10..15350ea19 100644 --- a/libmproxy/console/flowdetailview.py +++ b/libmproxy/console/flowdetailview.py @@ -18,10 +18,7 @@ class FlowDetailsView(urwid.ListBox): def keypress(self, size, key): key = common.shortcuts(key) if key == "q": - self.master.statusbar = self.state[0] - self.master.body = self.state[1] - self.master.header = self.state[2] - self.master.loop.widget = self.master.make_view() + self.master.loop.widget = self.state return None elif key == "?": key = None diff --git a/libmproxy/console/grideditor.py b/libmproxy/console/grideditor.py index dc3bad0eb..a1d662c8c 100644 --- a/libmproxy/console/grideditor.py +++ b/libmproxy/console/grideditor.py @@ -10,11 +10,11 @@ from .. import utils, filt, script from netlib import http_uastrings -footer = [ +FOOTER = [ ('heading_key', "enter"), ":edit ", ('heading_key', "q"), ":back ", ] -footer_editing = [ +FOOTER_EDITING = [ ('heading_key', "esc"), ":stop editing ", ] @@ -164,12 +164,12 @@ class GridWalker(urwid.ListWalker): self.editing = GridRow( self.focus_col, True, self.editor, self.lst[self.focus] ) - self.editor.master.statusbar.update(footer_editing) + self.editor.master.loop.widget.footer.update(FOOTER_EDITING) self._modified() def stop_edit(self): if self.editing: - self.editor.master.statusbar.update(footer) + self.editor.master.loop.widget.footer.update(FOOTER) self.set_current_value(self.editing.get_edit_value(), False) self.editing = False self._modified() @@ -268,7 +268,7 @@ class GridEditor(urwid.WidgetWrap): self.lb, header = urwid.Pile([title, h]) ) - self.master.statusbar.update("") + self.master.loop.widget.footer.update("") self.show_empty_msg() def show_empty_msg(self): diff --git a/libmproxy/console/help.py b/libmproxy/console/help.py index 6bb49a921..109a97920 100644 --- a/libmproxy/console/help.py +++ b/libmproxy/console/help.py @@ -180,10 +180,7 @@ class HelpView(urwid.ListBox): def keypress(self, size, key): key = common.shortcuts(key) if key == "q": - self.master.statusbar = self.state[0] - self.master.body = self.state[1] - self.master.header = self.state[2] - self.master.loop.widget = self.master.make_view() + self.master.loop.widget = self.state return None elif key == "?": key = None diff --git a/libmproxy/console/statusbar.py b/libmproxy/console/statusbar.py index 7663ee44b..7fb15aa60 100644 --- a/libmproxy/console/statusbar.py +++ b/libmproxy/console/statusbar.py @@ -114,6 +114,7 @@ class StatusBar(urwid.WidgetWrap): self.ib = urwid.WidgetWrap(urwid.Text("")) self._w = urwid.Pile([self.ib, self.ab]) signals.update_settings.connect(self.sig_update_settings) + self.redraw() def sig_update_settings(self, sender): self.redraw() @@ -188,7 +189,11 @@ class StatusBar(urwid.WidgetWrap): if self.master.state.follow_focus: opts.append("following") if self.master.stream_large_bodies: - opts.append("stream:%s" % utils.pretty_size(self.master.stream_large_bodies.max_size)) + opts.append( + "stream:%s" % utils.pretty_size( + self.master.stream_large_bodies.max_size + ) + ) if opts: r.append("[%s]"%(":".join(opts))) From 08bb07653306ed0f84932391732391227ee07ba2 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 17:18:53 +1300 Subject: [PATCH 028/170] console: signal-based view stack, unifying mechanisms for help, flow views, etc. --- libmproxy/console/__init__.py | 36 ++++++++++++++--------------- libmproxy/console/common.py | 3 --- libmproxy/console/flowdetailview.py | 8 +++---- libmproxy/console/flowview.py | 12 ++++------ libmproxy/console/grideditor.py | 2 +- libmproxy/console/help.py | 7 +++--- libmproxy/console/signals.py | 5 ++++ 7 files changed, 35 insertions(+), 38 deletions(-) diff --git a/libmproxy/console/__init__.py b/libmproxy/console/__init__.py index f6f8e7210..90c8bd89d 100644 --- a/libmproxy/console/__init__.py +++ b/libmproxy/console/__init__.py @@ -28,7 +28,6 @@ class ConsoleState(flow.State): self.follow_focus = None self.default_body_view = contentview.get("Auto") - self.view_mode = common.VIEW_LIST self.view_flow_mode = common.VIEW_FLOW_REQUEST self.flowsettings = weakref.WeakKeyDictionary() @@ -210,9 +209,13 @@ class ConsoleMaster(flow.FlowMaster): print >> sys.stderr, "Stream file error:", err sys.exit(1) + self.view_stack = [] + if options.app: self.start_app(self.options.app_host, self.options.app_port) signals.call_in.connect(self.sig_call_in) + signals.pop_view_state.connect(self.sig_pop_view_state) + signals.push_view_state.connect(self.sig_push_view_state) def __setattr__(self, name, value): self.__dict__[name] = value @@ -223,6 +226,13 @@ class ConsoleMaster(flow.FlowMaster): return callback(*args) self.loop.set_alarm_in(seconds, cb) + def sig_pop_view_state(self, sender): + if self.view_stack: + self.loop.widget = self.view_stack.pop() + + def sig_push_view_state(self, sender): + self.view_stack.append(self.loop.widget) + def start_stream_to_path(self, path, mode="wb"): path = os.path.expanduser(path) try: @@ -433,30 +443,25 @@ class ConsoleMaster(flow.FlowMaster): self.shutdown() def view_help(self): + signals.push_view_state.send(self) self.loop.widget = window.Window( self, - help.HelpView( - self, - self.help_context, - self.loop.widget, - ), + help.HelpView(self.help_context), None, statusbar.StatusBar(self, help.footer) ) def view_flowdetails(self, flow): + signals.push_view_state.send(self) self.loop.widget = window.Window( self, - flowdetailview.FlowDetailsView( - self, - flow, - self.loop.widget - ), + flowdetailview.FlowDetailsView(low), None, statusbar.StatusBar(self, flowdetailview.footer) ) def view_grideditor(self, ge): + signals.push_view_state.send(self) self.help_context = ge.make_help() self.loop.widget = window.Window( self, @@ -475,7 +480,6 @@ class ConsoleMaster(flow.FlowMaster): body = flowlist.BodyPile(self) else: body = flowlist.FlowListBox(self) - self.state.view_mode = common.VIEW_LIST self.help_context = flowlist.help_context self.loop.widget = window.Window( @@ -487,8 +491,8 @@ class ConsoleMaster(flow.FlowMaster): self.loop.draw_screen() def view_flow(self, flow): + signals.push_view_state.send(self) self.state.set_focus_flow(flow) - self.state.view_mode = common.VIEW_FLOW self.help_context = flowview.help_context self.loop.widget = window.Window( self, @@ -548,12 +552,6 @@ class ConsoleMaster(flow.FlowMaster): self.state.default_body_view = v self.refresh_focus() - def pop_view(self): - if self.state.view_mode == common.VIEW_FLOW: - self.view_flow(self.state.view[self.state.focus]) - else: - self.view_flowlist() - def edit_scripts(self, scripts): commands = [x[0] for x in scripts] # remove outer array if commands == [s.command for s in self.scripts]: diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index c0593af48..a0590bb1d 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -13,9 +13,6 @@ try: except: pyperclip = False -VIEW_LIST = 0 -VIEW_FLOW = 1 - VIEW_FLOW_REQUEST = 0 VIEW_FLOW_RESPONSE = 1 diff --git a/libmproxy/console/flowdetailview.py b/libmproxy/console/flowdetailview.py index 15350ea19..8bfdae4a7 100644 --- a/libmproxy/console/flowdetailview.py +++ b/libmproxy/console/flowdetailview.py @@ -1,6 +1,6 @@ from __future__ import absolute_import import urwid -from . import common +from . import common, signals from .. import utils footer = [ @@ -8,8 +8,8 @@ footer = [ ] class FlowDetailsView(urwid.ListBox): - def __init__(self, master, flow, state): - self.master, self.flow, self.state = master, flow, state + def __init__(self, flow): + self.flow = flow urwid.ListBox.__init__( self, self.flowtext() @@ -18,7 +18,7 @@ class FlowDetailsView(urwid.ListBox): def keypress(self, size, key): key = common.shortcuts(key) if key == "q": - self.master.loop.widget = self.state + signals.pop_view_state.send(self) return None elif key == "?": key = None diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 2dd2cb824..fcb967ccd 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -114,9 +114,6 @@ cache = CallbackCache() class FlowView(urwid.WidgetWrap): - REQ = 0 - RESP = 1 - highlight_color = "focusfield" def __init__(self, master, state, flow): @@ -633,8 +630,9 @@ class FlowView(urwid.WidgetWrap): new_flow, new_idx = self.state.get_prev(idx) if new_flow is None: signals.status_message.send(message="No more flows!") - return - self.master.view_flow(new_flow) + else: + signals.pop_view_state.send(self) + self.master.view_flow(new_flow) def view_next_flow(self, flow): return self._view_nextprev_flow("next", flow) @@ -673,8 +671,8 @@ class FlowView(urwid.WidgetWrap): conn = self.flow.response if key == "q": - self.master.view_flowlist() - key = None + signals.pop_view_state.send(self) + return None elif key == "tab": if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: self.view_response() diff --git a/libmproxy/console/grideditor.py b/libmproxy/console/grideditor.py index a1d662c8c..4bcc01717 100644 --- a/libmproxy/console/grideditor.py +++ b/libmproxy/console/grideditor.py @@ -323,7 +323,7 @@ class GridEditor(urwid.WidgetWrap): if not i[1] and any([x.strip() for x in i[0]]): res.append(i[0]) self.callback(res, *self.cb_args, **self.cb_kwargs) - self.master.pop_view() + signals.pop_view_state.send(self) elif key in ["h", "left"]: self.walker.left() elif key in ["l", "right"]: diff --git a/libmproxy/console/help.py b/libmproxy/console/help.py index 109a97920..73cd8a50f 100644 --- a/libmproxy/console/help.py +++ b/libmproxy/console/help.py @@ -2,7 +2,7 @@ from __future__ import absolute_import import urwid -from . import common +from . import common, signals from .. import filt, version footer = [ @@ -12,8 +12,7 @@ footer = [ class HelpView(urwid.ListBox): - def __init__(self, master, help_context, state): - self.master, self.state = master, state + def __init__(self, help_context): self.help_context = help_context or [] urwid.ListBox.__init__( self, @@ -180,7 +179,7 @@ class HelpView(urwid.ListBox): def keypress(self, size, key): key = common.shortcuts(key) if key == "q": - self.master.loop.widget = self.state + signals.pop_view_state.send(self) return None elif key == "?": key = None diff --git a/libmproxy/console/signals.py b/libmproxy/console/signals.py index 9afde6f45..e4c11f5ab 100644 --- a/libmproxy/console/signals.py +++ b/libmproxy/console/signals.py @@ -23,3 +23,8 @@ update_settings = blinker.Signal() # Fired when a flow changes flow_change = blinker.Signal() + + +# Pop and push view state onto a stack +pop_view_state = blinker.Signal() +push_view_state = blinker.Signal() From a1c21d9774a1b0e77bcb8116cad20973b2561c28 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 17:23:27 +1300 Subject: [PATCH 029/170] Fix unit tests --- test/test_console_help.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_console_help.py b/test/test_console_help.py index a410bd2e5..24517439f 100644 --- a/test/test_console_help.py +++ b/test/test_console_help.py @@ -19,12 +19,12 @@ class DummyMaster: class TestHelp: def test_helptext(self): - h = help.HelpView(None, "foo", None) + h = help.HelpView(None) assert h.helptext() def test_keypress(self): master = DummyMaster() - h = help.HelpView(master, "foo", [1, 2, 3]) + h = help.HelpView([1, 2, 3]) assert not h.keypress((0, 0), "q") assert not h.keypress((0, 0), "?") assert h.keypress((0, 0), "o") == "o" From 15f65d63f633b6b6a540f74006efe542796aa7e4 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 17:28:13 +1300 Subject: [PATCH 030/170] Trigger flow change when flow elements are edited --- libmproxy/console/flowview.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index fcb967ccd..044408886 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -532,19 +532,28 @@ class FlowView(urwid.WidgetWrap): def set_headers(self, lst, conn): conn.headers = flow.ODictCaseless(lst) + signals.flow_change.send(self, flow = self.flow) def set_query(self, lst, conn): conn.set_query(flow.ODict(lst)) + signals.flow_change.send(self, flow = self.flow) def set_path_components(self, lst, conn): conn.set_path_components([i[0] for i in lst]) + signals.flow_change.send(self, flow = self.flow) def set_form(self, lst, conn): conn.set_form_urlencoded(flow.ODict(lst)) + signals.flow_change.send(self, flow = self.flow) def edit_form(self, conn): self.master.view_grideditor( - grideditor.URLEncodedFormEditor(self.master, conn.get_form_urlencoded().lst, self.set_form, conn) + grideditor.URLEncodedFormEditor( + self.master, + conn.get_form_urlencoded().lst, + self.set_form, + conn + ) ) def edit_form_confirm(self, key, conn): @@ -586,7 +595,14 @@ class FlowView(urwid.WidgetWrap): else: self.edit_form(message) elif part == "h": - self.master.view_grideditor(grideditor.HeaderEditor(self.master, message.headers.lst, self.set_headers, message)) + self.master.view_grideditor( + grideditor.HeaderEditor( + self.master, + message.headers.lst, + self.set_headers, + message + ) + ) elif part == "p": p = message.get_path_components() p = [[i] for i in p] From a2da38cc8339887abef4efa23cc54fa02c981f3f Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 17:33:25 +1300 Subject: [PATCH 031/170] Whitespace, indentation, formatting --- libmproxy/console/flowview.py | 128 +++++++++++++++++++++++++++------- 1 file changed, 102 insertions(+), 26 deletions(-) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 044408886..e864cf471 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -87,7 +87,13 @@ footer = [ class FlowViewHeader(urwid.WidgetWrap): def __init__(self, master, f): self.master, self.flow = master, f - self._w = common.format_flow(f, False, extended=True, padding=0, hostheader=self.master.showhost) + self._w = common.format_flow( + f, + False, + extended=True, + padding=0, + hostheader=self.master.showhost + ) signals.flow_change.connect(self.sig_flow_change) def sig_flow_change(self, sender, flow): @@ -133,7 +139,14 @@ class FlowView(urwid.WidgetWrap): self.view_request() def _cached_content_view(self, viewmode, hdrItems, content, limit, is_request): - return contentview.get_content_view(viewmode, hdrItems, content, limit, self.master.add_event, is_request) + return contentview.get_content_view( + viewmode, + hdrItems, + content, + limit, + self.master.add_event, + is_request + ) def content_view(self, viewmode, conn): full = self.state.get_flow_setting( @@ -219,7 +232,8 @@ class FlowView(urwid.WidgetWrap): def conn_text(self, conn): """ - Same as conn_text_raw, but returns result wrapped in a listbox ready for usage. + Same as conn_text_raw, but returns result wrapped in a listbox ready for + usage. """ headers, msg, body = self.conn_text_raw(conn) merged = self.conn_text_merge(headers, msg, body) @@ -290,7 +304,9 @@ class FlowView(urwid.WidgetWrap): """ runs the previous search again, forwards or backwards. """ - last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") + last_search_string = self.state.get_flow_setting( + self.flow, "last_search_string" + ) if last_search_string: message = self.search(last_search_string, backwards) if message: @@ -331,7 +347,11 @@ class FlowView(urwid.WidgetWrap): # generate the body, highlight the words and get focus headers, msg, body = self.conn_text_raw(text) try: - body, focus_position = self.search_highlight_text(body, search_string, backwards=backwards) + body, focus_position = self.search_highlight_text( + body, + search_string, + backwards=backwards + ) except SearchError: return "Search not supported in this view." @@ -348,7 +368,11 @@ class FlowView(urwid.WidgetWrap): self.last_displayed_body = list_box - wrapped, wrapped_message = self.search_wrapped_around(last_find_line, last_search_index, backwards) + wrapped, wrapped_message = self.search_wrapped_around( + last_find_line, + last_search_index, + backwards + ) if wrapped: return wrapped_message @@ -356,9 +380,15 @@ class FlowView(urwid.WidgetWrap): def search_get_start(self, search_string): start_line = 0 start_index = 0 - last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") + last_search_string = self.state.get_flow_setting( + self.flow, + "last_search_string" + ) if search_string == last_search_string: - start_line = self.state.get_flow_setting(self.flow, "last_find_line") + start_line = self.state.get_flow_setting( + self.flow, + "last_find_line" + ) start_index = self.state.get_flow_setting(self.flow, "last_search_index") @@ -403,7 +433,10 @@ class FlowView(urwid.WidgetWrap): found = False text_objects = copy.deepcopy(text_objects) - loop_range = self.search_get_range(len(text_objects), start_line, backwards) + loop_range = self.search_get_range( + len(text_objects), + start_line, backwards + ) for i in loop_range: text_object = text_objects[i] @@ -415,10 +448,19 @@ class FlowView(urwid.WidgetWrap): if i != start_line: start_index = 0 - find_index = self.search_find(text, search_string, start_index, backwards) + find_index = self.search_find( + text, + search_string, + start_index, + backwards + ) if find_index != -1: - new_text = self.search_highlight_object(text, find_index, search_string) + new_text = self.search_highlight_object( + text, + find_index, + search_string + ) text_objects[i] = new_text found = True @@ -436,14 +478,26 @@ class FlowView(urwid.WidgetWrap): focus_pos = None else: if not backwards: - self.state.add_flow_setting(self.flow, "last_search_index", 0) - self.state.add_flow_setting(self.flow, "last_find_line", 0) + self.state.add_flow_setting( + self.flow, "last_search_index", 0 + ) + self.state.add_flow_setting( + self.flow, "last_find_line", 0 + ) else: - self.state.add_flow_setting(self.flow, "last_search_index", None) - self.state.add_flow_setting(self.flow, "last_find_line", len(text_objects) - 1) + self.state.add_flow_setting( + self.flow, "last_search_index", None + ) + self.state.add_flow_setting( + self.flow, "last_find_line", len(text_objects) - 1 + ) - text_objects, focus_pos = self.search_highlight_text(text_objects, - search_string, looping=True, backwards=backwards) + text_objects, focus_pos = self.search_highlight_text( + text_objects, + search_string, + looping=True, + backwards=backwards + ) return text_objects, focus_pos @@ -575,10 +629,12 @@ class FlowView(urwid.WidgetWrap): self.flow.backup() if part == "r": with decoded(message): - # Fix an issue caused by some editors when editing a request/response body. - # Many editors make it hard to save a file without a terminating newline on the last - # line. When editing message bodies, this can cause problems. For now, I just - # strip the newlines off the end of the body when we return from an editor. + # Fix an issue caused by some editors when editing a + # request/response body. Many editors make it hard to save a + # file without a terminating newline on the last line. When + # editing message bodies, this can cause problems. For now, I + # just strip the newlines off the end of the body when we return + # from an editor. c = self.master.spawn_editor(message.content or "") message.content = c.rstrip("\n") elif part == "f": @@ -606,9 +662,22 @@ class FlowView(urwid.WidgetWrap): elif part == "p": p = message.get_path_components() p = [[i] for i in p] - self.master.view_grideditor(grideditor.PathEditor(self.master, p, self.set_path_components, message)) + self.master.view_grideditor( + grideditor.PathEditor( + self.master, + p, + self.set_path_components, + message + ) + ) elif part == "q": - self.master.view_grideditor(grideditor.QueryEditor(self.master, message.get_query().lst, self.set_query, message)) + self.master.view_grideditor( + grideditor.QueryEditor( + self.master, + message.get_query().lst, + self.set_query, message + ) + ) elif part == "u" and self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: signals.status_prompt.send( prompt = "URL", @@ -801,7 +870,9 @@ class FlowView(urwid.WidgetWrap): if os.environ.has_key("EDITOR") or os.environ.has_key("PAGER"): self.master.spawn_external_viewer(conn.content, t) else: - signals.status_message.send(message="Error! Set $EDITOR or $PAGER.") + signals.status_message.send( + message = "Error! Set $EDITOR or $PAGER." + ) elif key == "|": signals.status_prompt_path.send( prompt = "Send flow to script", @@ -826,7 +897,9 @@ class FlowView(urwid.WidgetWrap): e = conn.headers.get_first("content-encoding", "identity") if e != "identity": if not conn.decode(): - signals.status_message.send(message="Could not decode - invalid data?") + signals.status_message.send( + message = "Could not decode - invalid data?" + ) else: signals.status_prompt_onekey.send( prompt = "Select encoding: ", @@ -839,7 +912,10 @@ class FlowView(urwid.WidgetWrap): ) signals.flow_change.send(self, flow = self.flow) elif key == "/": - last_search_string = self.state.get_flow_setting(self.flow, "last_search_string") + last_search_string = self.state.get_flow_setting( + self.flow, + "last_search_string" + ) search_prompt = "Search body ["+last_search_string+"]" if last_search_string else "Search body" signals.status_prompt.send( prompt = search_prompt, From 842e23d3e386169d9a90cef2a634c55a3e5fdd8e Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 21:00:41 +1300 Subject: [PATCH 032/170] Replace far-too-clever decorator LRU cache with something simpler --- libmproxy/console/common.py | 9 +++---- libmproxy/console/flowview.py | 15 +++-------- libmproxy/utils.py | 51 +++++++++++++++-------------------- test/test_utils.py | 26 +++++++++--------- test/tools/testpatt | 10 +++---- 5 files changed, 46 insertions(+), 65 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index a0590bb1d..2f143f013 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -327,11 +327,7 @@ def ask_save_body(part, master, state, flow): signals.status_message.send(message="No content to save.") -class FlowCache: - @utils.LRUCache(200) - def format_flow(self, *args): - return raw_format_flow(*args) -flowcache = FlowCache() +flowcache = utils.LRUCache(800) def format_flow(f, focus, extended=False, hostheader=False, padding=2): @@ -370,6 +366,7 @@ def format_flow(f, focus, extended=False, hostheader=False, padding=2): d["resp_ctype"] = t[0].split(";")[0] else: d["resp_ctype"] = "" - return flowcache.format_flow( + return flowcache.get( + raw_format_flow, tuple(sorted(d.items())), focus, extended, padding ) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index e864cf471..2c847fbaf 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -107,16 +107,7 @@ class FlowViewHeader(urwid.WidgetWrap): ) -class CallbackCache: - @utils.LRUCache(200) - def _callback(self, method, *args, **kwargs): - return getattr(self.obj, method)(*args, **kwargs) - - def callback(self, obj, method, *args, **kwargs): - # obj varies! - self.obj = obj - return self._callback(method, *args, **kwargs) -cache = CallbackCache() +cache = utils.LRUCache(200) class FlowView(urwid.WidgetWrap): @@ -158,8 +149,8 @@ class FlowView(urwid.WidgetWrap): limit = sys.maxint else: limit = contentview.VIEW_CUTOFF - description, text_objects = cache.callback( - self, "_cached_content_view", + description, text_objects = cache.get( + self._cached_content_view, viewmode, tuple(tuple(i) for i in conn.headers.lst), conn.content, diff --git a/libmproxy/utils.py b/libmproxy/utils.py index 51f2dc26a..5ed70a45e 100644 --- a/libmproxy/utils.py +++ b/libmproxy/utils.py @@ -119,40 +119,33 @@ pkg_data = Data(__name__) class LRUCache: """ - A decorator that implements a self-expiring LRU cache for class - methods (not functions!). - - Cache data is tracked as attributes on the object itself. There is - therefore a separate cache for each object instance. + A simple LRU cache for generated values. """ def __init__(self, size=100): self.size = size + self.cache = {} + self.cacheList = [] - def __call__(self, f): - cacheName = "_cached_%s"%f.__name__ - cacheListName = "_cachelist_%s"%f.__name__ - size = self.size + def get(self, gen, *args): + """ + gen: A (presumably expensive) generator function. The identity of + gen is NOT taken into account by the cache. + *args: A list of immutable arguments, used to establish identiy by + *the cache, and passed to gen to generate values. + """ + if self.cache.has_key(args): + self.cacheList.remove(args) + self.cacheList.insert(0, args) + return self.cache[args] + else: + ret = gen(*args) + self.cacheList.insert(0, args) + self.cache[args] = ret + if len(self.cacheList) > self.size: + d = self.cacheList.pop() + self.cache.pop(d) + return ret - @functools.wraps(f) - def wrap(self, *args): - if not hasattr(self, cacheName): - setattr(self, cacheName, {}) - setattr(self, cacheListName, []) - cache = getattr(self, cacheName) - cacheList = getattr(self, cacheListName) - if cache.has_key(args): - cacheList.remove(args) - cacheList.insert(0, args) - return cache[args] - else: - ret = f(self, *args) - cacheList.insert(0, args) - cache[args] = ret - if len(cacheList) > size: - d = cacheList.pop() - cache.pop(d) - return ret - return wrap def parse_content_type(c): """ diff --git a/test/test_utils.py b/test/test_utils.py index 78d1c0725..1678a7dee 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -62,38 +62,39 @@ def test_pretty_duration(): assert utils.pretty_duration(10) == "10.0s" assert utils.pretty_duration(100) == "100s" assert utils.pretty_duration(1000) == "1000s" - assert utils.pretty_duration(10000) == "10000s" + assert utils.pretty_duration(10000) == "10000s" assert utils.pretty_duration(1.123) == "1.12s" assert utils.pretty_duration(0.123) == "123ms" def test_LRUCache(): + cache = utils.LRUCache(2) class Foo: ran = False - @utils.LRUCache(2) - def one(self, x): + def gen(self, x): self.ran = True return x - f = Foo() - assert f.one(1) == 1 + + assert not f.ran + assert cache.get(f.gen, 1) == 1 assert f.ran f.ran = False - assert f.one(1) == 1 + assert cache.get(f.gen, 1) == 1 assert not f.ran f.ran = False - assert f.one(1) == 1 + assert cache.get(f.gen, 1) == 1 assert not f.ran - assert f.one(2) == 2 - assert f.one(3) == 3 + assert cache.get(f.gen, 2) == 2 + assert cache.get(f.gen, 3) == 3 assert f.ran f.ran = False - assert f.one(1) == 1 + assert cache.get(f.gen, 1) == 1 assert f.ran - assert len(f._cached_one) == 2 - assert len(f._cachelist_one) == 2 + assert len(cache.cacheList) == 2 + assert len(cache.cache) == 2 def test_unparse_url(): @@ -128,4 +129,3 @@ def test_safe_subn(): def test_urlencode(): assert utils.urlencode([('foo','bar')]) - diff --git a/test/tools/testpatt b/test/tools/testpatt index d4546d483..5ee1ea025 100755 --- a/test/tools/testpatt +++ b/test/tools/testpatt @@ -2,8 +2,8 @@ # Generate a test pattern with pathoc PATHOD=http://localhost:9999 -pathoc localhost:8080 "get:'$PATHOD/p/200:p0,1:b@200b':b@200b" -pathoc localhost:8080 "get:'$PATHOD/p/300:p0,1:b@200b':b@200b" -pathoc localhost:8080 "get:'$PATHOD/p/400:p0,1:b@200b':b@200b" -pathoc localhost:8080 "get:'$PATHOD/p/500:p0,1:b@200b':b@200b" -pathoc localhost:8080 "get:'$PATHOD/p/600:p0,1:b@200b':b@200b" +pathoc localhost:8080 "get:'$PATHOD/p/200:p0,1:b@2048b':b@2048b" +pathoc localhost:8080 "get:'$PATHOD/p/300:p0,1:b@2048b':b@2048b" +pathoc localhost:8080 "get:'$PATHOD/p/400:p0,1:b@2048b':b@2048b" +pathoc localhost:8080 "get:'$PATHOD/p/500:p0,1:b@2048b':b@2048b" +pathoc localhost:8080 "get:'$PATHOD/p/600:p0,1:b@2048b':b@2048b" From 6fb661dab518c036e9333d360f2efc91bc2631ab Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 22 Mar 2015 21:08:18 +1300 Subject: [PATCH 033/170] Unwind twisty maze of cache layers. Holy confusing, Batman. --- libmproxy/console/flowview.py | 59 ++++++++++++++--------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 2c847fbaf..1aebb0f05 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -129,43 +129,30 @@ class FlowView(urwid.WidgetWrap): else: self.view_request() - def _cached_content_view(self, viewmode, hdrItems, content, limit, is_request): - return contentview.get_content_view( - viewmode, - hdrItems, - content, - limit, - self.master.add_event, - is_request - ) - def content_view(self, viewmode, conn): - full = self.state.get_flow_setting( - self.flow, - (self.state.view_flow_mode, "fullcontents"), - False - ) - if full: - limit = sys.maxint - else: - limit = contentview.VIEW_CUTOFF - description, text_objects = cache.get( - self._cached_content_view, - viewmode, - tuple(tuple(i) for i in conn.headers.lst), - conn.content, - limit, - isinstance(conn, HTTPRequest) - ) - return (description, text_objects) - - def cont_view_handle_missing(self, conn, viewmode): - if conn.content == CONTENT_MISSING: - msg, body = "", [urwid.Text([("error", "[content missing]")])] - else: - msg, body = self.content_view(viewmode, conn) - + if conn.content == CONTENT_MISSING: + msg, body = "", [urwid.Text([("error", "[content missing]")])] return (msg, body) + else: + full = self.state.get_flow_setting( + self.flow, + (self.state.view_flow_mode, "fullcontents"), + False + ) + if full: + limit = sys.maxint + else: + limit = contentview.VIEW_CUTOFF + description, text_objects = cache.get( + contentview.get_content_view, + viewmode, + tuple(tuple(i) for i in conn.headers.lst), + conn.content, + limit, + self.master.add_event, + isinstance(conn, HTTPRequest) + ) + return (description, text_objects) def viewmode_get(self, override): return self.state.default_body_view if override is None else override @@ -186,7 +173,7 @@ class FlowView(urwid.WidgetWrap): ) override = self.override_get() viewmode = self.viewmode_get(override) - msg, body = self.cont_view_handle_missing(conn, viewmode) + msg, body = self.content_view(viewmode, conn) return headers, msg, body def conn_text_merge(self, headers, msg, body): From cf9f91b0b4abe2020c544981d6dc2e2e85f4b4bd Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 22 Mar 2015 14:33:42 +0100 Subject: [PATCH 034/170] web: upgrade to react 0.13 --- libmproxy/web/static/app.js | 44 +- libmproxy/web/static/vendor.css | 46 +- libmproxy/web/static/vendor.js | 11157 +++++++++++++++++------------- web/package.json | 100 +- web/src/js/components/common.js | 30 +- web/src/js/components/header.js | 14 +- 6 files changed, 6648 insertions(+), 4743 deletions(-) diff --git a/libmproxy/web/static/app.js b/libmproxy/web/static/app.js index 2254b4154..4f3998a9b 100644 --- a/libmproxy/web/static/app.js +++ b/libmproxy/web/static/app.js @@ -478,31 +478,43 @@ var StickyHeadMixin = { var Navigation = _.extend({}, ReactRouter.Navigation, { setQuery: function (dict) { - var q = this.context.getCurrentQuery(); + var q = this.context.router.getCurrentQuery(); for(var i in dict){ if(dict.hasOwnProperty(i)){ q[i] = dict[i] || undefined; //falsey values shall be removed. } } q._ = "_"; // workaround for https://github.com/rackt/react-router/pull/957 - this.replaceWith(this.context.getCurrentPath(), this.context.getCurrentParams(), q); + this.replaceWith(this.context.router.getCurrentPath(), this.context.router.getCurrentParams(), q); }, replaceWith: function(routeNameOrPath, params, query) { if(routeNameOrPath === undefined){ - routeNameOrPath = this.context.getCurrentPath(); + routeNameOrPath = this.context.router.getCurrentPath(); } if(params === undefined){ - params = this.context.getCurrentParams(); + params = this.context.router.getCurrentParams(); } if(query === undefined) { - query = this.context.getCurrentQuery(); + query = this.context.router.getCurrentQuery(); } - // FIXME: react-router is just broken. - ReactRouter.Navigation.replaceWith.call(this, routeNameOrPath, params, query); + // FIXME: react-router is just broken, + // we hopefully just need to wait for the next release with https://github.com/rackt/react-router/pull/957. + this.context.router.replaceWith(routeNameOrPath, params, query); + } +}); + +// react-router is fairly good at changing its API regularly. +// We keep the old method for now - if it should turn out that their changes are permanent, +// we may remove this mixin and access react-router directly again. +var State = _.extend({}, ReactRouter.State, { + getQuery: function(){ + return this.context.router.getCurrentQuery(); + }, + getParams: function(){ + return this.context.router.getCurrentParams(); } }); -_.extend(Navigation.contextTypes, ReactRouter.State.contextTypes); var Splitter = React.createClass({displayName: "Splitter", getDefaultProps: function () { @@ -610,7 +622,7 @@ var Splitter = React.createClass({displayName: "Splitter", }); module.exports = { - State: ReactRouter.State, // keep here - react-router is pretty buggy, we may need workarounds in the future. + State: State, Navigation: Navigation, StickyHeadMixin: StickyHeadMixin, AutoScrollMixin: AutoScrollMixin, @@ -2166,15 +2178,17 @@ var Header = React.createClass({displayName: "Header", }, render: function () { var header = header_entries.map(function (entry, i) { - var classes = React.addons.classSet({ - active: entry == this.state.active - }); + var className; + if(entry === this.state.active){ + className = "active"; + } else { + className = ""; + } return ( React.createElement("a", {key: i, href: "#", - className: classes, - onClick: this.handleClick.bind(this, entry) - }, + className: className, + onClick: this.handleClick.bind(this, entry)}, entry.title ) ); diff --git a/libmproxy/web/static/vendor.css b/libmproxy/web/static/vendor.css index 149372c81..a170c49a9 100644 --- a/libmproxy/web/static/vendor.css +++ b/libmproxy/web/static/vendor.css @@ -945,12 +945,24 @@ th { .glyphicon-bitcoin:before { content: "\e227"; } +.glyphicon-btc:before { + content: "\e227"; +} +.glyphicon-xbt:before { + content: "\e227"; +} .glyphicon-yen:before { content: "\00a5"; } +.glyphicon-jpy:before { + content: "\00a5"; +} .glyphicon-ruble:before { content: "\20bd"; } +.glyphicon-rub:before { + content: "\20bd"; +} .glyphicon-scale:before { content: "\e230"; } @@ -1147,6 +1159,9 @@ hr { overflow: visible; clip: auto; } +[role="button"] { + cursor: pointer; +} h1, h2, h3, @@ -2548,10 +2563,13 @@ output { .form-control[disabled], .form-control[readonly], fieldset[disabled] .form-control { - cursor: not-allowed; background-color: #eeeeee; opacity: 1; } +.form-control[disabled], +fieldset[disabled] .form-control { + cursor: not-allowed; +} textarea.form-control { height: auto; } @@ -2618,6 +2636,7 @@ input[type="search"] { } .radio-inline, .checkbox-inline { + position: relative; display: inline-block; padding-left: 20px; margin-bottom: 0; @@ -2654,6 +2673,7 @@ fieldset[disabled] .checkbox label { padding-top: 7px; padding-bottom: 7px; margin-bottom: 0; + min-height: 34px; } .form-control-static.input-lg, .form-control-static.input-sm { @@ -2695,6 +2715,7 @@ select[multiple].form-group-sm .form-control { padding: 5px 10px; font-size: 12px; line-height: 1.5; + min-height: 32px; } .input-lg { height: 46px; @@ -2731,6 +2752,7 @@ select[multiple].form-group-lg .form-control { padding: 10px 16px; font-size: 18px; line-height: 1.3333333; + min-height: 38px; } .has-feedback { position: relative; @@ -3348,11 +3370,9 @@ input[type="button"].btn-block { } .collapse { display: none; - visibility: hidden; } .collapse.in { display: block; - visibility: visible; } tr.collapse.in { display: table-row; @@ -3377,7 +3397,7 @@ tbody.collapse.in { height: 0; margin-left: 2px; vertical-align: middle; - border-top: 4px solid; + border-top: 4px dashed; border-right: 4px solid transparent; border-left: 4px solid transparent; } @@ -4016,11 +4036,9 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .tab-content > .tab-pane { display: none; - visibility: hidden; } .tab-content > .active { display: block; - visibility: visible; } .nav-tabs .dropdown-menu { margin-top: -1px; @@ -4062,7 +4080,6 @@ select[multiple].input-group-sm > .input-group-btn > .btn { } .navbar-collapse.collapse { display: block !important; - visibility: visible !important; height: auto !important; padding-bottom: 0; overflow: visible !important; @@ -4791,7 +4808,8 @@ a.label:focus { position: relative; top: -1px; } -.btn-xs .badge { +.btn-xs .badge, +.btn-group-xs > .btn .badge { top: 0; padding: 1px 5px; } @@ -5614,10 +5632,10 @@ a.list-group-item-danger.active:focus { width: 100%; border: 0; } -.embed-responsive.embed-responsive-16by9 { +.embed-responsive-16by9 { padding-bottom: 56.25%; } -.embed-responsive.embed-responsive-4by3 { +.embed-responsive-4by3 { padding-bottom: 75%; } .well { @@ -5678,7 +5696,7 @@ button.close { right: 0; bottom: 0; left: 0; - z-index: 1040; + z-index: 1050; -webkit-overflow-scrolling: touch; outline: 0; } @@ -5719,10 +5737,12 @@ button.close { outline: 0; } .modal-backdrop { - position: absolute; + position: fixed; top: 0; right: 0; + bottom: 0; left: 0; + z-index: 1040; background-color: #000000; } .modal-backdrop.fade { @@ -5793,7 +5813,6 @@ button.close { position: absolute; z-index: 1070; display: block; - visibility: visible; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 12px; font-weight: normal; @@ -6316,7 +6335,6 @@ button.close { } .hidden { display: none !important; - visibility: hidden !important; } .affix { position: fixed; diff --git a/libmproxy/web/static/vendor.js b/libmproxy/web/static/vendor.js index d98e50d98..6b34edb91 100644 --- a/libmproxy/web/static/vendor.js +++ b/libmproxy/web/static/vendor.js @@ -394,6 +394,422 @@ var invariant = function(condition, format, a, b, c, d, e, f) { module.exports = invariant; },{}],4:[function(require,module,exports){ +module.exports = require('./lib/'); + +},{"./lib/":5}],5:[function(require,module,exports){ +// Load modules + +var Stringify = require('./stringify'); +var Parse = require('./parse'); + + +// Declare internals + +var internals = {}; + + +module.exports = { + stringify: Stringify, + parse: Parse +}; + +},{"./parse":6,"./stringify":7}],6:[function(require,module,exports){ +// Load modules + +var Utils = require('./utils'); + + +// Declare internals + +var internals = { + delimiter: '&', + depth: 5, + arrayLimit: 20, + parameterLimit: 1000 +}; + + +internals.parseValues = function (str, options) { + + var obj = {}; + var parts = str.split(options.delimiter, options.parameterLimit === Infinity ? undefined : options.parameterLimit); + + for (var i = 0, il = parts.length; i < il; ++i) { + var part = parts[i]; + var pos = part.indexOf(']=') === -1 ? part.indexOf('=') : part.indexOf(']=') + 1; + + if (pos === -1) { + obj[Utils.decode(part)] = ''; + } + else { + var key = Utils.decode(part.slice(0, pos)); + var val = Utils.decode(part.slice(pos + 1)); + + if (Object.prototype.hasOwnProperty(key)) { + continue; + } + + if (!obj.hasOwnProperty(key)) { + obj[key] = val; + } + else { + obj[key] = [].concat(obj[key]).concat(val); + } + } + } + + return obj; +}; + + +internals.parseObject = function (chain, val, options) { + + if (!chain.length) { + return val; + } + + var root = chain.shift(); + + var obj = {}; + if (root === '[]') { + obj = []; + obj = obj.concat(internals.parseObject(chain, val, options)); + } + else { + var cleanRoot = root[0] === '[' && root[root.length - 1] === ']' ? root.slice(1, root.length - 1) : root; + var index = parseInt(cleanRoot, 10); + var indexString = '' + index; + if (!isNaN(index) && + root !== cleanRoot && + indexString === cleanRoot && + index >= 0 && + index <= options.arrayLimit) { + + obj = []; + obj[index] = internals.parseObject(chain, val, options); + } + else { + obj[cleanRoot] = internals.parseObject(chain, val, options); + } + } + + return obj; +}; + + +internals.parseKeys = function (key, val, options) { + + if (!key) { + return; + } + + // The regex chunks + + var parent = /^([^\[\]]*)/; + var child = /(\[[^\[\]]*\])/g; + + // Get the parent + + var segment = parent.exec(key); + + // Don't allow them to overwrite object prototype properties + + if (Object.prototype.hasOwnProperty(segment[1])) { + return; + } + + // Stash the parent if it exists + + var keys = []; + if (segment[1]) { + keys.push(segment[1]); + } + + // Loop through children appending to the array until we hit depth + + var i = 0; + while ((segment = child.exec(key)) !== null && i < options.depth) { + + ++i; + if (!Object.prototype.hasOwnProperty(segment[1].replace(/\[|\]/g, ''))) { + keys.push(segment[1]); + } + } + + // If there's a remainder, just add whatever is left + + if (segment) { + keys.push('[' + key.slice(segment.index) + ']'); + } + + return internals.parseObject(keys, val, options); +}; + + +module.exports = function (str, options) { + + if (str === '' || + str === null || + typeof str === 'undefined') { + + return {}; + } + + options = options || {}; + options.delimiter = typeof options.delimiter === 'string' || Utils.isRegExp(options.delimiter) ? options.delimiter : internals.delimiter; + options.depth = typeof options.depth === 'number' ? options.depth : internals.depth; + options.arrayLimit = typeof options.arrayLimit === 'number' ? options.arrayLimit : internals.arrayLimit; + options.parameterLimit = typeof options.parameterLimit === 'number' ? options.parameterLimit : internals.parameterLimit; + + var tempObj = typeof str === 'string' ? internals.parseValues(str, options) : str; + var obj = {}; + + // Iterate over the keys and setup the new object + + var keys = Object.keys(tempObj); + for (var i = 0, il = keys.length; i < il; ++i) { + var key = keys[i]; + var newObj = internals.parseKeys(key, tempObj[key], options); + obj = Utils.merge(obj, newObj); + } + + return Utils.compact(obj); +}; + +},{"./utils":8}],7:[function(require,module,exports){ +// Load modules + +var Utils = require('./utils'); + + +// Declare internals + +var internals = { + delimiter: '&', + arrayPrefixGenerators: { + brackets: function (prefix, key) { + return prefix + '[]'; + }, + indices: function (prefix, key) { + return prefix + '[' + key + ']'; + }, + repeat: function (prefix, key) { + return prefix; + } + } +}; + + +internals.stringify = function (obj, prefix, generateArrayPrefix) { + + if (Utils.isBuffer(obj)) { + obj = obj.toString(); + } + else if (obj instanceof Date) { + obj = obj.toISOString(); + } + else if (obj === null) { + obj = ''; + } + + if (typeof obj === 'string' || + typeof obj === 'number' || + typeof obj === 'boolean') { + + return [encodeURIComponent(prefix) + '=' + encodeURIComponent(obj)]; + } + + var values = []; + + if (typeof obj === 'undefined') { + return values; + } + + var objKeys = Object.keys(obj); + for (var i = 0, il = objKeys.length; i < il; ++i) { + var key = objKeys[i]; + if (Array.isArray(obj)) { + values = values.concat(internals.stringify(obj[key], generateArrayPrefix(prefix, key), generateArrayPrefix)); + } + else { + values = values.concat(internals.stringify(obj[key], prefix + '[' + key + ']', generateArrayPrefix)); + } + } + + return values; +}; + + +module.exports = function (obj, options) { + + options = options || {}; + var delimiter = typeof options.delimiter === 'undefined' ? internals.delimiter : options.delimiter; + + var keys = []; + + if (typeof obj !== 'object' || + obj === null) { + + return ''; + } + + var arrayFormat; + if (options.arrayFormat in internals.arrayPrefixGenerators) { + arrayFormat = options.arrayFormat; + } + else if ('indices' in options) { + arrayFormat = options.indices ? 'indices' : 'repeat'; + } + else { + arrayFormat = 'indices'; + } + + var generateArrayPrefix = internals.arrayPrefixGenerators[arrayFormat]; + + var objKeys = Object.keys(obj); + for (var i = 0, il = objKeys.length; i < il; ++i) { + var key = objKeys[i]; + keys = keys.concat(internals.stringify(obj[key], key, generateArrayPrefix)); + } + + return keys.join(delimiter); +}; + +},{"./utils":8}],8:[function(require,module,exports){ +// Load modules + + +// Declare internals + +var internals = {}; + + +exports.arrayToObject = function (source) { + + var obj = {}; + for (var i = 0, il = source.length; i < il; ++i) { + if (typeof source[i] !== 'undefined') { + + obj[i] = source[i]; + } + } + + return obj; +}; + + +exports.merge = function (target, source) { + + if (!source) { + return target; + } + + if (typeof source !== 'object') { + if (Array.isArray(target)) { + target.push(source); + } + else { + target[source] = true; + } + + return target; + } + + if (typeof target !== 'object') { + target = [target].concat(source); + return target; + } + + if (Array.isArray(target) && + !Array.isArray(source)) { + + target = exports.arrayToObject(target); + } + + var keys = Object.keys(source); + for (var k = 0, kl = keys.length; k < kl; ++k) { + var key = keys[k]; + var value = source[key]; + + if (!target[key]) { + target[key] = value; + } + else { + target[key] = exports.merge(target[key], value); + } + } + + return target; +}; + + +exports.decode = function (str) { + + try { + return decodeURIComponent(str.replace(/\+/g, ' ')); + } catch (e) { + return str; + } +}; + + +exports.compact = function (obj, refs) { + + if (typeof obj !== 'object' || + obj === null) { + + return obj; + } + + refs = refs || []; + var lookup = refs.indexOf(obj); + if (lookup !== -1) { + return refs[lookup]; + } + + refs.push(obj); + + if (Array.isArray(obj)) { + var compacted = []; + + for (var i = 0, il = obj.length; i < il; ++i) { + if (typeof obj[i] !== 'undefined') { + compacted.push(obj[i]); + } + } + + return compacted; + } + + var keys = Object.keys(obj); + for (i = 0, il = keys.length; i < il; ++i) { + var key = keys[i]; + obj[key] = exports.compact(obj[key], refs); + } + + return obj; +}; + + +exports.isRegExp = function (obj) { + return Object.prototype.toString.call(obj) === '[object RegExp]'; +}; + + +exports.isBuffer = function (obj) { + + if (obj === null || + typeof obj === 'undefined') { + + return false; + } + + return !!(obj.constructor && + obj.constructor.isBuffer && + obj.constructor.isBuffer(obj)); +}; + +},{}],9:[function(require,module,exports){ "use strict"; /** @@ -403,40 +819,7 @@ module.exports = invariant; function Cancellation() {} module.exports = Cancellation; -},{}],5:[function(require,module,exports){ -"use strict"; - -var warning = require("react/lib/warning"); -var invariant = require("react/lib/invariant"); - -function checkPropTypes(componentName, propTypes, props) { - for (var propName in propTypes) { - if (propTypes.hasOwnProperty(propName)) { - var error = propTypes[propName](props, propName, componentName); - - if (error instanceof Error) warning(false, error.message); - } - } -} - -var Configuration = { - - statics: { - - validateProps: function validateProps(props) { - checkPropTypes(this.displayName, this.propTypes, props); - } - - }, - - render: function render() { - invariant(false, "%s elements are for router configuration only and should not be rendered", this.constructor.displayName); - } - -}; - -module.exports = Configuration; -},{"react/lib/invariant":182,"react/lib/warning":202}],6:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ "use strict"; var invariant = require("react/lib/invariant"); @@ -467,10 +850,10 @@ var History = { }; module.exports = History; -},{"react/lib/ExecutionEnvironment":64,"react/lib/invariant":182}],7:[function(require,module,exports){ +},{"react/lib/ExecutionEnvironment":60,"react/lib/invariant":189}],11:[function(require,module,exports){ "use strict"; -var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); }; +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; @@ -520,7 +903,7 @@ var Match = (function () { this.routes = routes; } - _prototypeProperties(Match, { + _createClass(Match, null, { findMatch: { /** @@ -537,9 +920,7 @@ var Match = (function () { for (var i = 0, len = routes.length; match == null && i < len; ++i) match = deepSearch(routes[i], pathname, query); return match; - }, - writable: true, - configurable: true + } } }); @@ -547,11 +928,20 @@ var Match = (function () { })(); module.exports = Match; -},{"./PathUtils":10}],8:[function(require,module,exports){ +},{"./PathUtils":13}],12:[function(require,module,exports){ "use strict"; +var warning = require("react/lib/warning"); var PropTypes = require("./PropTypes"); +function deprecatedMethod(routerMethodName, fn) { + return function () { + warning(false, "Router.Navigation is deprecated. Please use this.context.router." + routerMethodName + "() instead"); + + return fn.apply(this, arguments); + }; +} + /** * A mixin for components that modify the URL. * @@ -559,11 +949,11 @@ var PropTypes = require("./PropTypes"); * * var MyLink = React.createClass({ * mixins: [ Router.Navigation ], - * handleClick: function (event) { + * handleClick(event) { * event.preventDefault(); * this.transitionTo('aRoute', { the: 'params' }, { the: 'query' }); * }, - * render: function () { + * render() { * return ( * Click me! * ); @@ -573,87 +963,52 @@ var PropTypes = require("./PropTypes"); var Navigation = { contextTypes: { - makePath: PropTypes.func.isRequired, - makeHref: PropTypes.func.isRequired, - transitionTo: PropTypes.func.isRequired, - replaceWith: PropTypes.func.isRequired, - goBack: PropTypes.func.isRequired + router: PropTypes.router.isRequired }, /** * Returns an absolute URL path created from the given route * name, URL parameters, and query values. */ - makePath: function makePath(to, params, query) { - return this.context.makePath(to, params, query); - }, + makePath: deprecatedMethod("makePath", function (to, params, query) { + return this.context.router.makePath(to, params, query); + }), /** * Returns a string that may safely be used as the href of a * link to the route with the given name. */ - makeHref: function makeHref(to, params, query) { - return this.context.makeHref(to, params, query); - }, + makeHref: deprecatedMethod("makeHref", function (to, params, query) { + return this.context.router.makeHref(to, params, query); + }), /** * Transitions to the URL specified in the arguments by pushing * a new URL onto the history stack. */ - transitionTo: function transitionTo(to, params, query) { - this.context.transitionTo(to, params, query); - }, + transitionTo: deprecatedMethod("transitionTo", function (to, params, query) { + this.context.router.transitionTo(to, params, query); + }), /** * Transitions to the URL specified in the arguments by replacing * the current URL in the history stack. */ - replaceWith: function replaceWith(to, params, query) { - this.context.replaceWith(to, params, query); - }, + replaceWith: deprecatedMethod("replaceWith", function (to, params, query) { + this.context.router.replaceWith(to, params, query); + }), /** * Transitions to the previous URL. */ - goBack: function goBack() { - return this.context.goBack(); - } + goBack: deprecatedMethod("goBack", function () { + return this.context.router.goBack(); + }) }; module.exports = Navigation; -},{"./PropTypes":11}],9:[function(require,module,exports){ -"use strict"; - -var PropTypes = require("./PropTypes"); - -/** - * Provides the router with context for Router.Navigation. - */ -var NavigationContext = { - - childContextTypes: { - makePath: PropTypes.func.isRequired, - makeHref: PropTypes.func.isRequired, - transitionTo: PropTypes.func.isRequired, - replaceWith: PropTypes.func.isRequired, - goBack: PropTypes.func.isRequired - }, - - getChildContext: function getChildContext() { - return { - makePath: this.constructor.makePath.bind(this.constructor), - makeHref: this.constructor.makeHref.bind(this.constructor), - transitionTo: this.constructor.transitionTo.bind(this.constructor), - replaceWith: this.constructor.replaceWith.bind(this.constructor), - goBack: this.constructor.goBack.bind(this.constructor) - }; - } - -}; - -module.exports = NavigationContext; -},{"./PropTypes":11}],10:[function(require,module,exports){ +},{"./PropTypes":14,"react/lib/warning":210}],13:[function(require,module,exports){ "use strict"; var invariant = require("react/lib/invariant"); @@ -797,7 +1152,7 @@ var PathUtils = { if (existingQuery) query = query ? merge(existingQuery, query) : existingQuery; - var queryString = qs.stringify(query, { indices: false }); + var queryString = qs.stringify(query, { arrayFormat: "brackets" }); if (queryString) { return PathUtils.withoutQuery(path) + "?" + queryString; @@ -807,27 +1162,39 @@ var PathUtils = { }; module.exports = PathUtils; -},{"qs":38,"qs/lib/utils":42,"react/lib/invariant":182}],11:[function(require,module,exports){ +},{"qs":4,"qs/lib/utils":8,"react/lib/invariant":189}],14:[function(require,module,exports){ "use strict"; var assign = require("react/lib/Object.assign"); var ReactPropTypes = require("react").PropTypes; +var Route = require("./Route"); -var PropTypes = assign({ +var PropTypes = assign({}, ReactPropTypes, { /** - * Requires that the value of a prop be falsy. + * Indicates that a prop should be falsy. */ falsy: function falsy(props, propName, componentName) { if (props[propName]) { return new Error("<" + componentName + "> may not have a \"" + propName + "\" prop"); } - } + }, -}, ReactPropTypes); + /** + * Indicates that a prop should be a Route object. + */ + route: ReactPropTypes.instanceOf(Route), + + /** + * Indicates that a prop should be a Router object. + */ + //router: ReactPropTypes.instanceOf(Router) // TODO + router: ReactPropTypes.func + +}); module.exports = PropTypes; -},{"react":"react","react/lib/Object.assign":70}],12:[function(require,module,exports){ +},{"./Route":16,"react":"react","react/lib/Object.assign":67}],15:[function(require,module,exports){ "use strict"; /** @@ -840,10 +1207,10 @@ function Redirect(to, params, query) { } module.exports = Redirect; -},{}],13:[function(require,module,exports){ +},{}],16:[function(require,module,exports){ "use strict"; -var _prototypeProperties = function (child, staticProps, instanceProps) { if (staticProps) Object.defineProperties(child, staticProps); if (instanceProps) Object.defineProperties(child.prototype, instanceProps); }; +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; @@ -869,7 +1236,33 @@ var Route = (function () { this.handler = handler; } - _prototypeProperties(Route, { + _createClass(Route, { + appendChild: { + + /** + * Appends the given route to this route's child routes. + */ + + value: function appendChild(route) { + invariant(route instanceof Route, "route.appendChild must use a valid Route"); + + if (!this.childRoutes) this.childRoutes = []; + + this.childRoutes.push(route); + } + }, + toString: { + value: function toString() { + var string = ""; + + return string; + } + } + }, { createRoute: { /** @@ -928,7 +1321,7 @@ var Route = (function () { if (path && !(options.isDefault || options.isNotFound)) { if (PathUtils.isAbsolute(path)) { if (parentRoute) { - invariant(parentRoute.paramNames.length === 0, "You cannot nest path \"%s\" inside \"%s\"; the parent requires URL parameters", path, parentRoute.path); + invariant(path === parentRoute.path || parentRoute.paramNames.length === 0, "You cannot nest path \"%s\" inside \"%s\"; the parent requires URL parameters", path, parentRoute.path); } } else if (parentRoute) { // Relative paths extend their parent. @@ -968,9 +1361,7 @@ var Route = (function () { } return route; - }, - writable: true, - configurable: true + } }, createDefaultRoute: { @@ -981,9 +1372,7 @@ var Route = (function () { value: function createDefaultRoute(options) { return Route.createRoute(assign({}, options, { isDefault: true })); - }, - writable: true, - configurable: true + } }, createNotFoundRoute: { @@ -994,9 +1383,7 @@ var Route = (function () { value: function createNotFoundRoute(options) { return Route.createRoute(assign({}, options, { isNotFound: true })); - }, - writable: true, - configurable: true + } }, createRedirect: { @@ -1020,39 +1407,7 @@ var Route = (function () { transition.redirect(options.to, options.params || params, options.query || query); } })); - }, - writable: true, - configurable: true - } - }, { - appendChild: { - - /** - * Appends the given route to this route's child routes. - */ - - value: function appendChild(route) { - invariant(route instanceof Route, "route.appendChild must use a valid Route"); - - if (!this.childRoutes) this.childRoutes = []; - - this.childRoutes.push(route); - }, - writable: true, - configurable: true - }, - toString: { - value: function toString() { - var string = ""; - - return string; - }, - writable: true, - configurable: true + } } }); @@ -1060,62 +1415,7 @@ var Route = (function () { })(); module.exports = Route; -},{"./PathUtils":10,"react/lib/Object.assign":70,"react/lib/invariant":182,"react/lib/warning":202}],14:[function(require,module,exports){ -"use strict"; - -var React = require("react"); -var assign = require("react/lib/Object.assign"); -var PropTypes = require("./PropTypes"); - -var REF_NAME = "__routeHandler__"; - -var RouteHandlerMixin = { - - contextTypes: { - getRouteAtDepth: PropTypes.func.isRequired, - setRouteComponentAtDepth: PropTypes.func.isRequired, - routeHandlers: PropTypes.array.isRequired - }, - - childContextTypes: { - routeHandlers: PropTypes.array.isRequired - }, - - getChildContext: function getChildContext() { - return { - routeHandlers: this.context.routeHandlers.concat([this]) - }; - }, - - componentDidMount: function componentDidMount() { - this._updateRouteComponent(this.refs[REF_NAME]); - }, - - componentDidUpdate: function componentDidUpdate() { - this._updateRouteComponent(this.refs[REF_NAME]); - }, - - componentWillUnmount: function componentWillUnmount() { - this._updateRouteComponent(null); - }, - - _updateRouteComponent: function _updateRouteComponent(component) { - this.context.setRouteComponentAtDepth(this.getRouteDepth(), component); - }, - - getRouteDepth: function getRouteDepth() { - return this.context.routeHandlers.length; - }, - - createChildRouteHandler: function createChildRouteHandler(props) { - var route = this.context.getRouteAtDepth(this.getRouteDepth()); - return route ? React.createElement(route.handler, assign({}, props || this.props, { ref: REF_NAME })) : null; - } - -}; - -module.exports = RouteHandlerMixin; -},{"./PropTypes":11,"react":"react","react/lib/Object.assign":70}],15:[function(require,module,exports){ +},{"./PathUtils":13,"react/lib/Object.assign":67,"react/lib/invariant":189,"react/lib/warning":210}],17:[function(require,module,exports){ "use strict"; var invariant = require("react/lib/invariant"); @@ -1191,11 +1491,20 @@ var ScrollHistory = { }; module.exports = ScrollHistory; -},{"./getWindowScrollPosition":30,"react/lib/ExecutionEnvironment":64,"react/lib/invariant":182}],16:[function(require,module,exports){ +},{"./getWindowScrollPosition":32,"react/lib/ExecutionEnvironment":60,"react/lib/invariant":189}],18:[function(require,module,exports){ "use strict"; +var warning = require("react/lib/warning"); var PropTypes = require("./PropTypes"); +function deprecatedMethod(routerMethodName, fn) { + return function () { + warning(false, "Router.State is deprecated. Please use this.context.router." + routerMethodName + "() instead"); + + return fn.apply(this, arguments); + }; +} + /** * A mixin for components that need to know the path, routes, URL * params and query that are currently active. @@ -1204,7 +1513,7 @@ var PropTypes = require("./PropTypes"); * * var AboutLink = React.createClass({ * mixins: [ Router.State ], - * render: function () { + * render() { * var className = this.props.className; * * if (this.isActive('about')) @@ -1217,158 +1526,56 @@ var PropTypes = require("./PropTypes"); var State = { contextTypes: { - getCurrentPath: PropTypes.func.isRequired, - getCurrentRoutes: PropTypes.func.isRequired, - getCurrentPathname: PropTypes.func.isRequired, - getCurrentParams: PropTypes.func.isRequired, - getCurrentQuery: PropTypes.func.isRequired, - isActive: PropTypes.func.isRequired + router: PropTypes.router.isRequired }, /** * Returns the current URL path. */ - getPath: function getPath() { - return this.context.getCurrentPath(); - }, - - /** - * Returns an array of the routes that are currently active. - */ - getRoutes: function getRoutes() { - return this.context.getCurrentRoutes(); - }, + getPath: deprecatedMethod("getCurrentPath", function () { + return this.context.router.getCurrentPath(); + }), /** * Returns the current URL path without the query string. */ - getPathname: function getPathname() { - return this.context.getCurrentPathname(); - }, + getPathname: deprecatedMethod("getCurrentPathname", function () { + return this.context.router.getCurrentPathname(); + }), /** * Returns an object of the URL params that are currently active. */ - getParams: function getParams() { - return this.context.getCurrentParams(); - }, + getParams: deprecatedMethod("getCurrentParams", function () { + return this.context.router.getCurrentParams(); + }), /** * Returns an object of the query params that are currently active. */ - getQuery: function getQuery() { - return this.context.getCurrentQuery(); - }, + getQuery: deprecatedMethod("getCurrentQuery", function () { + return this.context.router.getCurrentQuery(); + }), + + /** + * Returns an array of the routes that are currently active. + */ + getRoutes: deprecatedMethod("getCurrentRoutes", function () { + return this.context.router.getCurrentRoutes(); + }), /** * A helper method to determine if a given route, params, and query * are active. */ - isActive: function isActive(to, params, query) { - return this.context.isActive(to, params, query); - } + isActive: deprecatedMethod("isActive", function (to, params, query) { + return this.context.router.isActive(to, params, query); + }) }; module.exports = State; -},{"./PropTypes":11}],17:[function(require,module,exports){ -"use strict"; - -var assign = require("react/lib/Object.assign"); -var PropTypes = require("./PropTypes"); -var PathUtils = require("./PathUtils"); - -function routeIsActive(activeRoutes, routeName) { - return activeRoutes.some(function (route) { - return route.name === routeName; - }); -} - -function paramsAreActive(activeParams, params) { - for (var property in params) if (String(activeParams[property]) !== String(params[property])) { - return false; - }return true; -} - -function queryIsActive(activeQuery, query) { - for (var property in query) if (String(activeQuery[property]) !== String(query[property])) { - return false; - }return true; -} - -/** - * Provides the router with context for Router.State. - */ -var StateContext = { - - /** - * Returns the current URL path + query string. - */ - getCurrentPath: function getCurrentPath() { - return this.state.path; - }, - - /** - * Returns a read-only array of the currently active routes. - */ - getCurrentRoutes: function getCurrentRoutes() { - return this.state.routes.slice(0); - }, - - /** - * Returns the current URL path without the query string. - */ - getCurrentPathname: function getCurrentPathname() { - return this.state.pathname; - }, - - /** - * Returns a read-only object of the currently active URL parameters. - */ - getCurrentParams: function getCurrentParams() { - return assign({}, this.state.params); - }, - - /** - * Returns a read-only object of the currently active query parameters. - */ - getCurrentQuery: function getCurrentQuery() { - return assign({}, this.state.query); - }, - - /** - * Returns true if the given route, params, and query are active. - */ - isActive: function isActive(to, params, query) { - if (PathUtils.isAbsolute(to)) { - return to === this.state.path; - }return routeIsActive(this.state.routes, to) && paramsAreActive(this.state.params, params) && (query == null || queryIsActive(this.state.query, query)); - }, - - childContextTypes: { - getCurrentPath: PropTypes.func.isRequired, - getCurrentRoutes: PropTypes.func.isRequired, - getCurrentPathname: PropTypes.func.isRequired, - getCurrentParams: PropTypes.func.isRequired, - getCurrentQuery: PropTypes.func.isRequired, - isActive: PropTypes.func.isRequired - }, - - getChildContext: function getChildContext() { - return { - getCurrentPath: this.getCurrentPath, - getCurrentRoutes: this.getCurrentRoutes, - getCurrentPathname: this.getCurrentPathname, - getCurrentParams: this.getCurrentParams, - getCurrentQuery: this.getCurrentQuery, - isActive: this.isActive - }; - } - -}; - -module.exports = StateContext; -},{"./PathUtils":10,"./PropTypes":11,"react/lib/Object.assign":70}],18:[function(require,module,exports){ +},{"./PropTypes":14,"react/lib/warning":210}],19:[function(require,module,exports){ "use strict"; /* jshint -W058 */ @@ -1444,7 +1651,7 @@ Transition.to = function (transition, routes, params, query, callback) { }; module.exports = Transition; -},{"./Cancellation":4,"./Redirect":12}],19:[function(require,module,exports){ +},{"./Cancellation":9,"./Redirect":15}],20:[function(require,module,exports){ "use strict"; /** @@ -1470,7 +1677,7 @@ var LocationActions = { }; module.exports = LocationActions; -},{}],20:[function(require,module,exports){ +},{}],21:[function(require,module,exports){ "use strict"; var LocationActions = require("../actions/LocationActions"); @@ -1500,7 +1707,7 @@ var ImitateBrowserBehavior = { }; module.exports = ImitateBrowserBehavior; -},{"../actions/LocationActions":19}],21:[function(require,module,exports){ +},{"../actions/LocationActions":20}],22:[function(require,module,exports){ "use strict"; /** @@ -1516,12 +1723,56 @@ var ScrollToTopBehavior = { }; module.exports = ScrollToTopBehavior; -},{}],22:[function(require,module,exports){ +},{}],23:[function(require,module,exports){ "use strict"; +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + +/** + * This component is necessary to get around a context warning + * present in React 0.13.0. It sovles this by providing a separation + * between the "owner" and "parent" contexts. + */ + var React = require("react"); -var Configuration = require("../Configuration"); + +var ContextWrapper = (function (_React$Component) { + function ContextWrapper() { + _classCallCheck(this, ContextWrapper); + + if (_React$Component != null) { + _React$Component.apply(this, arguments); + } + } + + _inherits(ContextWrapper, _React$Component); + + _createClass(ContextWrapper, { + render: { + value: function render() { + return this.props.children; + } + } + }); + + return ContextWrapper; +})(React.Component); + +module.exports = ContextWrapper; +},{"react":"react"}],24:[function(require,module,exports){ +"use strict"; + +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + var PropTypes = require("../PropTypes"); +var RouteHandler = require("./RouteHandler"); +var Route = require("./Route"); /** * A component is a special kind of that @@ -1529,32 +1780,49 @@ var PropTypes = require("../PropTypes"); * Only one such route may be used at any given level in the * route hierarchy. */ -var DefaultRoute = React.createClass({ - displayName: "DefaultRoute", +var DefaultRoute = (function (_Route) { + function DefaultRoute() { + _classCallCheck(this, DefaultRoute); - mixins: [Configuration], - - propTypes: { - name: PropTypes.string, - path: PropTypes.falsy, - children: PropTypes.falsy, - handler: PropTypes.func.isRequired + if (_Route != null) { + _Route.apply(this, arguments); + } } -}); + _inherits(DefaultRoute, _Route); + + return DefaultRoute; +})(Route); + +// TODO: Include these in the above class definition +// once we can use ES7 property initializers. +// https://github.com/babel/babel/issues/619 + +DefaultRoute.propTypes = { + name: PropTypes.string, + path: PropTypes.falsy, + children: PropTypes.falsy, + handler: PropTypes.func.isRequired +}; + +DefaultRoute.defaultProps = { + handler: RouteHandler +}; module.exports = DefaultRoute; -},{"../Configuration":5,"../PropTypes":11,"react":"react"}],23:[function(require,module,exports){ +},{"../PropTypes":14,"./Route":28,"./RouteHandler":29}],25:[function(require,module,exports){ "use strict"; +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + var React = require("react"); -var classSet = require("react/lib/cx"); var assign = require("react/lib/Object.assign"); -var Navigation = require("../Navigation"); -var State = require("../State"); var PropTypes = require("../PropTypes"); -var Route = require("../Route"); function isLeftClickEvent(event) { return event.button === 0; @@ -1582,88 +1850,116 @@ function isModifiedEvent(event) { * * */ -var Link = React.createClass({ - displayName: "Link", +var Link = (function (_React$Component) { + function Link() { + _classCallCheck(this, Link); - mixins: [Navigation, State], - - propTypes: { - activeClassName: PropTypes.string.isRequired, - to: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Route)]), - params: PropTypes.object, - query: PropTypes.object, - activeStyle: PropTypes.object, - onClick: PropTypes.func - }, - - getDefaultProps: function getDefaultProps() { - return { - activeClassName: "active" - }; - }, - - handleClick: function handleClick(event) { - var allowTransition = true; - var clickResult; - - if (this.props.onClick) clickResult = this.props.onClick(event); - - if (isModifiedEvent(event) || !isLeftClickEvent(event)) { - return; - }if (clickResult === false || event.defaultPrevented === true) allowTransition = false; - - event.preventDefault(); - - if (allowTransition) this.transitionTo(this.props.to, this.props.params, this.props.query); - }, - - /** - * Returns the value of the "href" attribute to use on the DOM element. - */ - getHref: function getHref() { - return this.makeHref(this.props.to, this.props.params, this.props.query); - }, - - /** - * Returns the value of the "class" attribute to use on the DOM element, which contains - * the value of the activeClassName property when this is active. - */ - getClassName: function getClassName() { - var classNames = {}; - - if (this.props.className) classNames[this.props.className] = true; - - if (this.getActiveState()) classNames[this.props.activeClassName] = true; - - return classSet(classNames); - }, - - getActiveState: function getActiveState() { - return this.isActive(this.props.to, this.props.params, this.props.query); - }, - - render: function render() { - var props = assign({}, this.props, { - href: this.getHref(), - className: this.getClassName(), - onClick: this.handleClick - }); - - if (props.activeStyle && this.getActiveState()) props.style = props.activeStyle; - - return React.DOM.a(props, this.props.children); + if (_React$Component != null) { + _React$Component.apply(this, arguments); + } } -}); + _inherits(Link, _React$Component); + + _createClass(Link, { + handleClick: { + value: function handleClick(event) { + var allowTransition = true; + var clickResult; + + if (this.props.onClick) clickResult = this.props.onClick(event); + + if (isModifiedEvent(event) || !isLeftClickEvent(event)) { + return; + }if (clickResult === false || event.defaultPrevented === true) allowTransition = false; + + event.preventDefault(); + + if (allowTransition) this.context.router.transitionTo(this.props.to, this.props.params, this.props.query); + } + }, + getHref: { + + /** + * Returns the value of the "href" attribute to use on the DOM element. + */ + + value: function getHref() { + return this.context.router.makeHref(this.props.to, this.props.params, this.props.query); + } + }, + getClassName: { + + /** + * Returns the value of the "class" attribute to use on the DOM element, which contains + * the value of the activeClassName property when this is active. + */ + + value: function getClassName() { + var className = this.props.className; + + if (this.getActiveState()) className += " " + this.props.activeClassName; + + return className; + } + }, + getActiveState: { + value: function getActiveState() { + return this.context.router.isActive(this.props.to, this.props.params, this.props.query); + } + }, + render: { + value: function render() { + var props = assign({}, this.props, { + href: this.getHref(), + className: this.getClassName(), + onClick: this.handleClick.bind(this) + }); + + if (props.activeStyle && this.getActiveState()) props.style = props.activeStyle; + + return React.DOM.a(props, this.props.children); + } + } + }); + + return Link; +})(React.Component); + +// TODO: Include these in the above class definition +// once we can use ES7 property initializers. +// https://github.com/babel/babel/issues/619 + +Link.contextTypes = { + router: PropTypes.router.isRequired +}; + +Link.propTypes = { + activeClassName: PropTypes.string.isRequired, + to: PropTypes.oneOfType([PropTypes.string, PropTypes.route]).isRequired, + params: PropTypes.object, + query: PropTypes.object, + activeStyle: PropTypes.object, + onClick: PropTypes.func +}; + +Link.defaultProps = { + activeClassName: "active", + className: "" +}; module.exports = Link; -},{"../Navigation":8,"../PropTypes":11,"../Route":13,"../State":16,"react":"react","react/lib/Object.assign":70,"react/lib/cx":160}],24:[function(require,module,exports){ +},{"../PropTypes":14,"react":"react","react/lib/Object.assign":67}],26:[function(require,module,exports){ "use strict"; -var React = require("react"); -var Configuration = require("../Configuration"); +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + var PropTypes = require("../PropTypes"); +var RouteHandler = require("./RouteHandler"); +var Route = require("./Route"); /** * A is a special kind of that @@ -1672,56 +1968,95 @@ var PropTypes = require("../PropTypes"); * Only one such route may be used at any given level in the * route hierarchy. */ -var NotFoundRoute = React.createClass({ - displayName: "NotFoundRoute", +var NotFoundRoute = (function (_Route) { + function NotFoundRoute() { + _classCallCheck(this, NotFoundRoute); - mixins: [Configuration], - - propTypes: { - name: PropTypes.string, - path: PropTypes.falsy, - children: PropTypes.falsy, - handler: PropTypes.func.isRequired + if (_Route != null) { + _Route.apply(this, arguments); + } } -}); + _inherits(NotFoundRoute, _Route); + + return NotFoundRoute; +})(Route); + +// TODO: Include these in the above class definition +// once we can use ES7 property initializers. +// https://github.com/babel/babel/issues/619 + +NotFoundRoute.propTypes = { + name: PropTypes.string, + path: PropTypes.falsy, + children: PropTypes.falsy, + handler: PropTypes.func.isRequired +}; + +NotFoundRoute.defaultProps = { + handler: RouteHandler +}; module.exports = NotFoundRoute; -},{"../Configuration":5,"../PropTypes":11,"react":"react"}],25:[function(require,module,exports){ +},{"../PropTypes":14,"./Route":28,"./RouteHandler":29}],27:[function(require,module,exports){ "use strict"; -var React = require("react"); -var Configuration = require("../Configuration"); +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + var PropTypes = require("../PropTypes"); +var Route = require("./Route"); /** * A component is a special kind of that always * redirects to another route when it matches. */ -var Redirect = React.createClass({ - displayName: "Redirect", +var Redirect = (function (_Route) { + function Redirect() { + _classCallCheck(this, Redirect); - mixins: [Configuration], - - propTypes: { - path: PropTypes.string, - from: PropTypes.string, // Alias for path. - to: PropTypes.string, - handler: PropTypes.falsy + if (_Route != null) { + _Route.apply(this, arguments); + } } -}); + _inherits(Redirect, _Route); + + return Redirect; +})(Route); + +// TODO: Include these in the above class definition +// once we can use ES7 property initializers. +// https://github.com/babel/babel/issues/619 + +Redirect.propTypes = { + path: PropTypes.string, + from: PropTypes.string, // Alias for path. + to: PropTypes.string, + handler: PropTypes.falsy +}; + +// Redirects should not have a default handler +Redirect.defaultProps = {}; module.exports = Redirect; -},{"../Configuration":5,"../PropTypes":11,"react":"react"}],26:[function(require,module,exports){ +},{"../PropTypes":14,"./Route":28}],28:[function(require,module,exports){ "use strict"; +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + var React = require("react"); -var Configuration = require("../Configuration"); +var invariant = require("react/lib/invariant"); var PropTypes = require("../PropTypes"); var RouteHandler = require("./RouteHandler"); + /** * components specify components that are rendered to the page when the * URL matches a given pattern. @@ -1762,52 +2097,147 @@ var RouteHandler = require("./RouteHandler"); * * If no handler is provided for the route, it will render a matched child route. */ -var Route = React.createClass({ - displayName: "Route", +var Route = (function (_React$Component) { + function Route() { + _classCallCheck(this, Route); - mixins: [Configuration], - - propTypes: { - name: PropTypes.string, - path: PropTypes.string, - handler: PropTypes.func, - ignoreScrollBehavior: PropTypes.bool - }, - - getDefaultProps: function getDefaultProps() { - return { - handler: RouteHandler - }; + if (_React$Component != null) { + _React$Component.apply(this, arguments); + } } -}); + _inherits(Route, _React$Component); + + _createClass(Route, { + render: { + value: function render() { + invariant(false, "%s elements are for router configuration only and should not be rendered", this.constructor.name); + } + } + }); + + return Route; +})(React.Component); + +// TODO: Include these in the above class definition +// once we can use ES7 property initializers. +// https://github.com/babel/babel/issues/619 + +Route.propTypes = { + name: PropTypes.string, + path: PropTypes.string, + handler: PropTypes.func, + ignoreScrollBehavior: PropTypes.bool +}; + +Route.defaultProps = { + handler: RouteHandler +}; module.exports = Route; -},{"../Configuration":5,"../PropTypes":11,"./RouteHandler":27,"react":"react"}],27:[function(require,module,exports){ +},{"../PropTypes":14,"./RouteHandler":29,"react":"react","react/lib/invariant":189}],29:[function(require,module,exports){ "use strict"; +var _createClass = (function () { function defineProperties(target, props) { for (var key in props) { var prop = props[key]; prop.configurable = true; if (prop.value) prop.writable = true; } Object.defineProperties(target, props); } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + +var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; + var React = require("react"); -var RouteHandlerMixin = require("../RouteHandlerMixin"); +var ContextWrapper = require("./ContextWrapper"); +var assign = require("react/lib/Object.assign"); +var PropTypes = require("../PropTypes"); + +var REF_NAME = "__routeHandler__"; /** * A component renders the active child route handler * when routes are nested. */ -var RouteHandler = React.createClass({ - displayName: "RouteHandler", +var RouteHandler = (function (_React$Component) { + function RouteHandler() { + _classCallCheck(this, RouteHandler); - mixins: [RouteHandlerMixin], - - render: function render() { - return this.createChildRouteHandler(); + if (_React$Component != null) { + _React$Component.apply(this, arguments); + } } -}); + _inherits(RouteHandler, _React$Component); + + _createClass(RouteHandler, { + getChildContext: { + value: function getChildContext() { + return { + routeDepth: this.context.routeDepth + 1 + }; + } + }, + componentDidMount: { + value: function componentDidMount() { + this._updateRouteComponent(this.refs[REF_NAME]); + } + }, + componentDidUpdate: { + value: function componentDidUpdate() { + this._updateRouteComponent(this.refs[REF_NAME]); + } + }, + componentWillUnmount: { + value: function componentWillUnmount() { + this._updateRouteComponent(null); + } + }, + _updateRouteComponent: { + value: function _updateRouteComponent(component) { + this.context.router.setRouteComponentAtDepth(this.getRouteDepth(), component); + } + }, + getRouteDepth: { + value: function getRouteDepth() { + return this.context.routeDepth; + } + }, + createChildRouteHandler: { + value: function createChildRouteHandler(props) { + var route = this.context.router.getRouteAtDepth(this.getRouteDepth()); + return route ? React.createElement(route.handler, assign({}, props || this.props, { ref: REF_NAME })) : null; + } + }, + render: { + value: function render() { + var handler = this.createChildRouteHandler(); + // diff --git a/setup.py b/setup.py index bffce8055..9509ce7a9 100644 --- a/setup.py +++ b/setup.py @@ -83,7 +83,8 @@ setup( "coveralls>=0.4.1", "pathod>=%s, <%s" % ( version.MINORVERSION, version.NEXT_MINORVERSION - ) + ), + "countershape" ], 'contentviews': [ "pyamf>=0.6.1", From b2f87b9424f825874732c160de109d4385ae59e5 Mon Sep 17 00:00:00 2001 From: Thomas Kriechbaumer Date: Thu, 21 May 2015 13:15:55 +0200 Subject: [PATCH 157/170] improve autoenv script * properly quote DIR variable (it might contain spaces) * use builtin string magic instead of `dirname` --- .env | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.env b/.env index 7f847e29f..97f38452b 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ -DIR=`dirname $0` -if [ -z "$VIRTUAL_ENV" ] && [ -f $DIR/../venv.mitmproxy/bin/activate ]; then +DIR="${0%/*}" +if [ -z "$VIRTUAL_ENV" ] && [ -f "$DIR/../venv.mitmproxy/bin/activate" ]; then echo "Activating mitmproxy virtualenv..." - source $DIR/../venv.mitmproxy/bin/activate + source "$DIR/../venv.mitmproxy/bin/activate" fi From f816246f4eae78a5fb0626f753e5210fcbe9e82f Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 22 May 2015 11:21:00 +1200 Subject: [PATCH 158/170] doc: fix nav in website mode --- doc-src/_websitelayout.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc-src/_websitelayout.html b/doc-src/_websitelayout.html index 92bf7bc71..5a7c01bb5 100644 --- a/doc-src/_websitelayout.html +++ b/doc-src/_websitelayout.html @@ -16,9 +16,9 @@ From ba070bf9474fc6db70a6693b1603503682476776 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Fri, 22 May 2015 17:13:58 +1200 Subject: [PATCH 159/170] docs: bootstrap theme + logo --- doc-src/01-bootstrap.min.css | 5 - doc-src/01-vendor.css | 6707 ++++++++++++++++++++++++++++++++++ doc-src/_layout.html | 7 +- doc-src/mitmproxy-long.png | Bin 0 -> 123829 bytes 4 files changed, 6713 insertions(+), 6 deletions(-) delete mode 100644 doc-src/01-bootstrap.min.css create mode 100644 doc-src/01-vendor.css create mode 100644 doc-src/mitmproxy-long.png diff --git a/doc-src/01-bootstrap.min.css b/doc-src/01-bootstrap.min.css deleted file mode 100644 index cd1c616ad..000000000 --- a/doc-src/01-bootstrap.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Bootstrap v3.3.4 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}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}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!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:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.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"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-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}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}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}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;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}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.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-md-1,.col-md-10,.col-md-11,.col-md-12,.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-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.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-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;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>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-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,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px \9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.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}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.form-group-sm .form-control{height:30px;line-height:30px}select[multiple].form-group-sm .form-control,textarea.form-group-sm .form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:5px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.form-group-lg .form-control{height:46px;line-height:46px}select[multiple].form-group-lg .form-control,textarea.form-group-lg .form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:10px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.active,.btn-default.focus,.btn-default:active,.btn-default:focus,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.active,.btn-primary.focus,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.active,.btn-success.focus,.btn-success:active,.btn-success:focus,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.active,.btn-info.focus,.btn-info:active,.btn-info:focus,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.active,.btn-warning.focus,.btn-warning:active,.btn-warning:focus,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.active,.btn-danger.focus,.btn-danger:active,.btn-danger:focus,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{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;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.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:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{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-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.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{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.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{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-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-top-left-radius:0;border-bottom-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:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.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,.125);box-shadow:inset 0 3px 5px rgba(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,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.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-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;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:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,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}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,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 .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn: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:6px 12px;font-size:14px;font-weight:400;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:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{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>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.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:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.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.42857143;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:focus,.nav-tabs>li.active>a:hover{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:focus,.nav-tabs.nav-justified>.active>a:hover{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:focus,.nav-tabs.nav-justified>.active>a:hover{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:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.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:focus,.nav-tabs-justified>.active>a:hover{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:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px)and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{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-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{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;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .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;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.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;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{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}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.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;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@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-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.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:#777}.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:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-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:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-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-top-left-radius:3px;border-bottom-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 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:focus,.pager li>a:hover{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:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.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:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 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,.1);box-shadow:inset 0 1px 2px rgba(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:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.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-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.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,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>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>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.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:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.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,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(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:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.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}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:400;line-height:1.4;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.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:#000;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-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.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;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{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.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;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.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,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.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,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row: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}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px)and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px)and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px)and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px)and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file diff --git a/doc-src/01-vendor.css b/doc-src/01-vendor.css new file mode 100644 index 000000000..2f65c8a32 --- /dev/null +++ b/doc-src/01-vendor.css @@ -0,0 +1,6707 @@ +@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700"); +.navbar-inverse .badge { + background-color: #fff; + color: #2780e3; +} +body { + -webkit-font-smoothing: antialiased; +} +.text-primary, +.text-primary:hover { + color: #2780e3; +} +.text-success, +.text-success:hover { + color: #3fb618; +} +.text-danger, +.text-danger:hover { + color: #ff0039; +} +.text-warning, +.text-warning:hover { + color: #ff7518; +} +.text-info, +.text-info:hover { + color: #9954bb; +} +table a:not(.btn), +.table a:not(.btn) { + text-decoration: underline; +} +table .dropdown-menu a, +.table .dropdown-menu a { + text-decoration: none; +} +table .success, +.table .success, +table .warning, +.table .warning, +table .danger, +.table .danger, +table .info, +.table .info { + color: #fff; +} +table .success a, +.table .success a, +table .warning a, +.table .warning a, +table .danger a, +.table .danger a, +table .info a, +.table .info a { + color: #fff; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .form-control-feedback { + color: #ff7518; +} +.has-warning .form-control, +.has-warning .form-control:focus, +.has-warning .input-group-addon { + border: 1px solid #ff7518; +} +.has-error .help-block, +.has-error .control-label, +.has-error .form-control-feedback { + color: #ff0039; +} +.has-error .form-control, +.has-error .form-control:focus, +.has-error .input-group-addon { + border: 1px solid #ff0039; +} +.has-success .help-block, +.has-success .control-label, +.has-success .form-control-feedback { + color: #3fb618; +} +.has-success .form-control, +.has-success .form-control:focus, +.has-success .input-group-addon { + border: 1px solid #3fb618; +} +.nav-pills > li > a { + border-radius: 0; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + background-image: none; +} +.close { + text-decoration: none; + text-shadow: none; + opacity: 0.4; +} +.close:hover, +.close:focus { + opacity: 1; +} +.alert { + border: none; +} +.alert .alert-link { + text-decoration: underline; + color: #fff; +} +.label { + border-radius: 0; +} +.progress { + height: 8px; + -webkit-box-shadow: none; + box-shadow: none; +} +.progress .progress-bar { + font-size: 8px; + line-height: 8px; +} +.panel-heading, +.panel-footer { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.panel-default .close { + color: #333333; +} +a.list-group-item-success.active { + background-color: #3fb618; +} +a.list-group-item-success.active:hover, +a.list-group-item-success.active:focus { + background-color: #379f15; +} +a.list-group-item-warning.active { + background-color: #ff7518; +} +a.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus { + background-color: #fe6600; +} +a.list-group-item-danger.active { + background-color: #ff0039; +} +a.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus { + background-color: #e60033; +} +.modal .close { + color: #333333; +} +.popover { + color: #333333; +} +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ +html { + font-family: sans-serif; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; + vertical-align: baseline; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +a { + background-color: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +mark { + background: #ff0; + color: #000; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + color: inherit; + font: inherit; + margin: 0; +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + padding: 0; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-appearance: textfield; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +legend { + border: 0; + padding: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +td, +th { + padding: 0; +} +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ +@media print { + *, + *:before, + *:after { + background: transparent !important; + color: #000 !important; + box-shadow: none !important; + text-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="#"]:after, + a[href^="javascript:"]: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; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + select { + background: #fff !important; + } + .navbar { + display: none; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table td, + .table th { + background-color: #fff !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +@font-face { + font-family: 'Glyphicons Halflings'; + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon-asterisk:before { + content: "\2a"; +} +.glyphicon-plus:before { + content: "\2b"; +} +.glyphicon-euro:before, +.glyphicon-eur: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"; +} +.glyphicon-cd:before { + content: "\e201"; +} +.glyphicon-save-file:before { + content: "\e202"; +} +.glyphicon-open-file:before { + content: "\e203"; +} +.glyphicon-level-up:before { + content: "\e204"; +} +.glyphicon-copy:before { + content: "\e205"; +} +.glyphicon-paste:before { + content: "\e206"; +} +.glyphicon-alert:before { + content: "\e209"; +} +.glyphicon-equalizer:before { + content: "\e210"; +} +.glyphicon-king:before { + content: "\e211"; +} +.glyphicon-queen:before { + content: "\e212"; +} +.glyphicon-pawn:before { + content: "\e213"; +} +.glyphicon-bishop:before { + content: "\e214"; +} +.glyphicon-knight:before { + content: "\e215"; +} +.glyphicon-baby-formula:before { + content: "\e216"; +} +.glyphicon-tent:before { + content: "\26fa"; +} +.glyphicon-blackboard:before { + content: "\e218"; +} +.glyphicon-bed:before { + content: "\e219"; +} +.glyphicon-apple:before { + content: "\f8ff"; +} +.glyphicon-erase:before { + content: "\e221"; +} +.glyphicon-hourglass:before { + content: "\231b"; +} +.glyphicon-lamp:before { + content: "\e223"; +} +.glyphicon-duplicate:before { + content: "\e224"; +} +.glyphicon-piggy-bank:before { + content: "\e225"; +} +.glyphicon-scissors:before { + content: "\e226"; +} +.glyphicon-bitcoin:before { + content: "\e227"; +} +.glyphicon-btc:before { + content: "\e227"; +} +.glyphicon-xbt:before { + content: "\e227"; +} +.glyphicon-yen:before { + content: "\00a5"; +} +.glyphicon-jpy:before { + content: "\00a5"; +} +.glyphicon-ruble:before { + content: "\20bd"; +} +.glyphicon-rub:before { + content: "\20bd"; +} +.glyphicon-scale:before { + content: "\e230"; +} +.glyphicon-ice-lolly:before { + content: "\e231"; +} +.glyphicon-ice-lolly-tasted:before { + content: "\e232"; +} +.glyphicon-education:before { + content: "\e233"; +} +.glyphicon-option-horizontal:before { + content: "\e234"; +} +.glyphicon-option-vertical:before { + content: "\e235"; +} +.glyphicon-menu-hamburger:before { + content: "\e236"; +} +.glyphicon-modal-window:before { + content: "\e237"; +} +.glyphicon-oil:before { + content: "\e238"; +} +.glyphicon-grain:before { + content: "\e239"; +} +.glyphicon-sunglasses:before { + content: "\e240"; +} +.glyphicon-text-size:before { + content: "\e241"; +} +.glyphicon-text-color:before { + content: "\e242"; +} +.glyphicon-text-background:before { + content: "\e243"; +} +.glyphicon-object-align-top:before { + content: "\e244"; +} +.glyphicon-object-align-bottom:before { + content: "\e245"; +} +.glyphicon-object-align-horizontal:before { + content: "\e246"; +} +.glyphicon-object-align-left:before { + content: "\e247"; +} +.glyphicon-object-align-vertical:before { + content: "\e248"; +} +.glyphicon-object-align-right:before { + content: "\e249"; +} +.glyphicon-triangle-right:before { + content: "\e250"; +} +.glyphicon-triangle-left:before { + content: "\e251"; +} +.glyphicon-triangle-bottom:before { + content: "\e252"; +} +.glyphicon-triangle-top:before { + content: "\e253"; +} +.glyphicon-console:before { + content: "\e254"; +} +.glyphicon-superscript:before { + content: "\e255"; +} +.glyphicon-subscript:before { + content: "\e256"; +} +.glyphicon-menu-left:before { + content: "\e257"; +} +.glyphicon-menu-right:before { + content: "\e258"; +} +.glyphicon-menu-down:before { + content: "\e259"; +} +.glyphicon-menu-up:before { + content: "\e260"; +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 10px; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "Source Sans Pro", Calibri, Candara, Arial, sans-serif; + font-size: 15px; + line-height: 1.42857143; + color: #333333; + background-color: #ffffff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #2780e3; + text-decoration: none; +} +a:hover, +a:focus { + color: #165ba8; + text-decoration: underline; +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +figure { + margin: 0; +} +img { + vertical-align: middle; +} +.img-responsive, +.thumbnail > img, +.thumbnail a > img, +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 0; +} +.img-thumbnail { + padding: 4px; + line-height: 1.42857143; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 0; + -webkit-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + display: inline-block; + max-width: 100%; + height: auto; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 21px; + margin-bottom: 21px; + border: 0; + border-top: 1px solid #e6e6e6; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} +[role="button"] { + cursor: pointer; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: "Source Sans Pro", Calibri, Candara, Arial, sans-serif; + font-weight: 300; + line-height: 1.1; + color: inherit; +} +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: #999999; +} +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 21px; + margin-bottom: 10.5px; +} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small { + font-size: 65%; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10.5px; + margin-bottom: 10.5px; +} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 39px; +} +h2, +.h2 { + font-size: 32px; +} +h3, +.h3 { + font-size: 26px; +} +h4, +.h4 { + font-size: 19px; +} +h5, +.h5 { + font-size: 15px; +} +h6, +.h6 { + font-size: 13px; +} +p { + margin: 0 0 10.5px; +} +.lead { + margin-bottom: 21px; + font-size: 17px; + font-weight: 300; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 22.5px; + } +} +small, +.small { + font-size: 86%; +} +mark, +.mark { + background-color: #ff7518; + padding: .2em; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.text-nowrap { + white-space: nowrap; +} +.text-lowercase { + text-transform: lowercase; +} +.text-uppercase { + text-transform: uppercase; +} +.text-capitalize { + text-transform: capitalize; +} +.text-muted { + color: #999999; +} +.text-primary { + color: #2780e3; +} +a.text-primary:hover { + color: #1967be; +} +.text-success { + color: #ffffff; +} +a.text-success:hover { + color: #e6e6e6; +} +.text-info { + color: #ffffff; +} +a.text-info:hover { + color: #e6e6e6; +} +.text-warning { + color: #ffffff; +} +a.text-warning:hover { + color: #e6e6e6; +} +.text-danger { + color: #ffffff; +} +a.text-danger:hover { + color: #e6e6e6; +} +.bg-primary { + color: #fff; + background-color: #2780e3; +} +a.bg-primary:hover { + background-color: #1967be; +} +.bg-success { + background-color: #3fb618; +} +a.bg-success:hover { + background-color: #2f8912; +} +.bg-info { + background-color: #9954bb; +} +a.bg-info:hover { + background-color: #7e3f9d; +} +.bg-warning { + background-color: #ff7518; +} +a.bg-warning:hover { + background-color: #e45c00; +} +.bg-danger { + background-color: #ff0039; +} +a.bg-danger:hover { + background-color: #cc002e; +} +.page-header { + padding-bottom: 9.5px; + margin: 42px 0 21px; + border-bottom: 1px solid #e6e6e6; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10.5px; +} +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; + margin-left: -5px; +} +.list-inline > li { + display: inline-block; + padding-left: 5px; + padding-right: 5px; +} +dl { + margin-top: 0; + margin-bottom: 21px; +} +dt, +dd { + line-height: 1.42857143; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 10.5px 21px; + margin: 0 0 21px; + font-size: 18.75px; + border-left: 5px solid #e6e6e6; +} +blockquote p:last-child, +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +blockquote footer, +blockquote small, +blockquote .small { + display: block; + font-size: 80%; + line-height: 1.42857143; + color: #999999; +} +blockquote footer:before, +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #e6e6e6; + border-left: 0; + text-align: right; +} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +address { + margin-bottom: 21px; + font-style: normal; + line-height: 1.42857143; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 0; +} +kbd { + padding: 2px 4px; + font-size: 90%; + color: #ffffff; + background-color: #333333; + border-radius: 0; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25); +} +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: bold; + box-shadow: none; +} +pre { + display: block; + padding: 10px; + margin: 0 0 10.5px; + font-size: 14px; + line-height: 1.42857143; + word-break: break-all; + word-wrap: break-word; + color: #333333; + background-color: #f5f5f5; + border: 1px solid #cccccc; + border-radius: 0; +} +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 { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +.row { + margin-left: -15px; + margin-right: -15px; +} +.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-left: 15px; + padding-right: 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, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666667%; +} +.col-xs-10 { + width: 83.33333333%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666667%; +} +.col-xs-7 { + width: 58.33333333%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666667%; +} +.col-xs-4 { + width: 33.33333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.66666667%; +} +.col-xs-1 { + width: 8.33333333%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666667%; +} +.col-xs-pull-10 { + right: 83.33333333%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666667%; +} +.col-xs-pull-7 { + right: 58.33333333%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666667%; +} +.col-xs-pull-4 { + right: 33.33333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.66666667%; +} +.col-xs-pull-1 { + right: 8.33333333%; +} +.col-xs-pull-0 { + right: auto; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666667%; +} +.col-xs-push-10 { + left: 83.33333333%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666667%; +} +.col-xs-push-7 { + left: 58.33333333%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666667%; +} +.col-xs-push-4 { + left: 33.33333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.66666667%; +} +.col-xs-push-1 { + left: 8.33333333%; +} +.col-xs-push-0 { + left: auto; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666667%; +} +.col-xs-offset-10 { + margin-left: 83.33333333%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666667%; +} +.col-xs-offset-7 { + margin-left: 58.33333333%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.66666667%; +} +.col-xs-offset-1 { + margin-left: 8.33333333%; +} +.col-xs-offset-0 { + margin-left: 0%; +} +@media (min-width: 768px) { + .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, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666667%; + } + .col-sm-10 { + width: 83.33333333%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666667%; + } + .col-sm-7 { + width: 58.33333333%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666667%; + } + .col-sm-4 { + width: 33.33333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.66666667%; + } + .col-sm-1 { + width: 8.33333333%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666667%; + } + .col-sm-pull-10 { + right: 83.33333333%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666667%; + } + .col-sm-pull-7 { + right: 58.33333333%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666667%; + } + .col-sm-pull-4 { + right: 33.33333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.66666667%; + } + .col-sm-pull-1 { + right: 8.33333333%; + } + .col-sm-pull-0 { + right: auto; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666667%; + } + .col-sm-push-10 { + left: 83.33333333%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666667%; + } + .col-sm-push-7 { + left: 58.33333333%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666667%; + } + .col-sm-push-4 { + left: 33.33333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.66666667%; + } + .col-sm-push-1 { + left: 8.33333333%; + } + .col-sm-push-0 { + left: auto; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666667%; + } + .col-sm-offset-10 { + margin-left: 83.33333333%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666667%; + } + .col-sm-offset-7 { + margin-left: 58.33333333%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.66666667%; + } + .col-sm-offset-1 { + margin-left: 8.33333333%; + } + .col-sm-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 992px) { + .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, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666667%; + } + .col-md-10 { + width: 83.33333333%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666667%; + } + .col-md-7 { + width: 58.33333333%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666667%; + } + .col-md-4 { + width: 33.33333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.66666667%; + } + .col-md-1 { + width: 8.33333333%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666667%; + } + .col-md-pull-10 { + right: 83.33333333%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666667%; + } + .col-md-pull-7 { + right: 58.33333333%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666667%; + } + .col-md-pull-4 { + right: 33.33333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.66666667%; + } + .col-md-pull-1 { + right: 8.33333333%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666667%; + } + .col-md-push-10 { + left: 83.33333333%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666667%; + } + .col-md-push-7 { + left: 58.33333333%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666667%; + } + .col-md-push-4 { + left: 33.33333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.66666667%; + } + .col-md-push-1 { + left: 8.33333333%; + } + .col-md-push-0 { + left: auto; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666667%; + } + .col-md-offset-10 { + margin-left: 83.33333333%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666667%; + } + .col-md-offset-7 { + margin-left: 58.33333333%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.66666667%; + } + .col-md-offset-1 { + margin-left: 8.33333333%; + } + .col-md-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 1200px) { + .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, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666667%; + } + .col-lg-10 { + width: 83.33333333%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666667%; + } + .col-lg-7 { + width: 58.33333333%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666667%; + } + .col-lg-4 { + width: 33.33333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.66666667%; + } + .col-lg-1 { + width: 8.33333333%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666667%; + } + .col-lg-pull-10 { + right: 83.33333333%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666667%; + } + .col-lg-pull-7 { + right: 58.33333333%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666667%; + } + .col-lg-pull-4 { + right: 33.33333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.66666667%; + } + .col-lg-pull-1 { + right: 8.33333333%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666667%; + } + .col-lg-push-10 { + left: 83.33333333%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666667%; + } + .col-lg-push-7 { + left: 58.33333333%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666667%; + } + .col-lg-push-4 { + left: 33.33333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.66666667%; + } + .col-lg-push-1 { + left: 8.33333333%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666667%; + } + .col-lg-offset-10 { + margin-left: 83.33333333%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666667%; + } + .col-lg-offset-7 { + margin-left: 58.33333333%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.66666667%; + } + .col-lg-offset-1 { + margin-left: 8.33333333%; + } + .col-lg-offset-0 { + margin-left: 0%; + } +} +table { + background-color: transparent; +} +caption { + padding-top: 8px; + padding-bottom: 8px; + color: #999999; + text-align: left; +} +th { + text-align: left; +} +.table { + width: 100%; + max-width: 100%; + margin-bottom: 21px; +} +.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.42857143; + vertical-align: top; + border-top: 1px solid #dddddd; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #dddddd; +} +.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 #dddddd; +} +.table .table { + background-color: #ffffff; +} +.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 #dddddd; +} +.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 #dddddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover { + background-color: #f5f5f5; +} +table col[class*="col-"] { + position: static; + float: none; + display: table-column; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + float: none; + display: table-cell; +} +.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-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr:hover > .active, +.table-hover > tbody > tr.active:hover > th { + background-color: #e8e8e8; +} +.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: #3fb618; +} +.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:hover > .success, +.table-hover > tbody > tr.success:hover > th { + background-color: #379f15; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #9954bb; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr:hover > .info, +.table-hover > tbody > tr.info:hover > th { + background-color: #8d46b0; +} +.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: #ff7518; +} +.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:hover > .warning, +.table-hover > tbody > tr.warning:hover > th { + background-color: #fe6600; +} +.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: #ff0039; +} +.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:hover > .danger, +.table-hover > tbody > tr.danger:hover > th { + background-color: #e60033; +} +.table-responsive { + overflow-x: auto; + min-height: 0.01%; +} +@media screen and (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15.75px; + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #dddddd; + } + .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; + min-width: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 21px; + font-size: 22.5px; + line-height: inherit; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +label { + display: inline-block; + max-width: 100%; + 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; +} +input[type="range"] { + display: block; + width: 100%; +} +select[multiple], +select[size] { + height: auto; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +output { + display: block; + padding-top: 11px; + font-size: 15px; + line-height: 1.42857143; + color: #333333; +} +.form-control { + display: block; + width: 100%; + height: 43px; + padding: 10px 18px; + font-size: 15px; + line-height: 1.42857143; + color: #333333; + background-color: #ffffff; + background-image: none; + border: 1px solid #cccccc; + border-radius: 0; + -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; + -o-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,.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); +} +.form-control::-moz-placeholder { + color: #999999; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #999999; +} +.form-control::-webkit-input-placeholder { + color: #999999; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + background-color: #e6e6e6; + opacity: 1; +} +.form-control[disabled], +fieldset[disabled] .form-control { + cursor: not-allowed; +} +textarea.form-control { + height: auto; +} +input[type="search"] { + -webkit-appearance: none; +} +@media screen and (-webkit-min-device-pixel-ratio: 0) { + input[type="date"], + input[type="time"], + input[type="datetime-local"], + input[type="month"] { + line-height: 43px; + } + input[type="date"].input-sm, + input[type="time"].input-sm, + input[type="datetime-local"].input-sm, + input[type="month"].input-sm, + .input-group-sm input[type="date"], + .input-group-sm input[type="time"], + .input-group-sm input[type="datetime-local"], + .input-group-sm input[type="month"] { + line-height: 31px; + } + input[type="date"].input-lg, + input[type="time"].input-lg, + input[type="datetime-local"].input-lg, + input[type="month"].input-lg, + .input-group-lg input[type="date"], + .input-group-lg input[type="time"], + .input-group-lg input[type="datetime-local"], + .input-group-lg input[type="month"] { + line-height: 64px; + } +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + min-height: 21px; + padding-left: 20px; + 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"] { + position: absolute; + margin-left: -20px; + margin-top: 4px \9; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"].disabled, +input[type="checkbox"].disabled, +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"] { + cursor: not-allowed; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox label { + cursor: not-allowed; +} +.form-control-static { + padding-top: 11px; + padding-bottom: 11px; + margin-bottom: 0; + min-height: 36px; +} +.form-control-static.input-lg, +.form-control-static.input-sm { + padding-left: 0; + padding-right: 0; +} +.input-sm { + height: 31px; + padding: 5px 10px; + font-size: 13px; + line-height: 1.5; + border-radius: 0; +} +select.input-sm { + height: 31px; + line-height: 31px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.form-group-sm .form-control { + height: 31px; + padding: 5px 10px; + font-size: 13px; + line-height: 1.5; + border-radius: 0; +} +select.form-group-sm .form-control { + height: 31px; + line-height: 31px; +} +textarea.form-group-sm .form-control, +select[multiple].form-group-sm .form-control { + height: auto; +} +.form-group-sm .form-control-static { + height: 31px; + padding: 5px 10px; + font-size: 13px; + line-height: 1.5; + min-height: 34px; +} +.input-lg { + height: 64px; + padding: 18px 30px; + font-size: 19px; + line-height: 1.3333333; + border-radius: 0; +} +select.input-lg { + height: 64px; + line-height: 64px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.form-group-lg .form-control { + height: 64px; + padding: 18px 30px; + font-size: 19px; + line-height: 1.3333333; + border-radius: 0; +} +select.form-group-lg .form-control { + height: 64px; + line-height: 64px; +} +textarea.form-group-lg .form-control, +select[multiple].form-group-lg .form-control { + height: auto; +} +.form-group-lg .form-control-static { + height: 64px; + padding: 18px 30px; + font-size: 19px; + line-height: 1.3333333; + min-height: 40px; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 53.75px; +} +.form-control-feedback { + position: absolute; + top: 0; + right: 0; + z-index: 2; + display: block; + width: 43px; + height: 43px; + line-height: 43px; + text-align: center; + pointer-events: none; +} +.input-lg + .form-control-feedback { + width: 64px; + height: 64px; + line-height: 64px; +} +.input-sm + .form-control-feedback { + width: 31px; + height: 31px; + line-height: 31px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success.radio label, +.has-success.checkbox label, +.has-success.radio-inline label, +.has-success.checkbox-inline label { + color: #ffffff; +} +.has-success .form-control { + border-color: #ffffff; + -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: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; +} +.has-success .input-group-addon { + color: #ffffff; + border-color: #ffffff; + background-color: #3fb618; +} +.has-success .form-control-feedback { + color: #ffffff; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning.radio label, +.has-warning.checkbox label, +.has-warning.radio-inline label, +.has-warning.checkbox-inline label { + color: #ffffff; +} +.has-warning .form-control { + border-color: #ffffff; + -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: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; +} +.has-warning .input-group-addon { + color: #ffffff; + border-color: #ffffff; + background-color: #ff7518; +} +.has-warning .form-control-feedback { + color: #ffffff; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error.radio label, +.has-error.checkbox label, +.has-error.radio-inline label, +.has-error.checkbox-inline label { + color: #ffffff; +} +.has-error .form-control { + border-color: #ffffff; + -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: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; +} +.has-error .input-group-addon { + color: #ffffff; + border-color: #ffffff; + background-color: #ff0039; +} +.has-error .form-control-feedback { + color: #ffffff; +} +.has-feedback label ~ .form-control-feedback { + top: 26px; +} +.has-feedback label.sr-only ~ .form-control-feedback { + top: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-static { + display: inline-block; + } + .form-inline .input-group { + display: inline-table; + vertical-align: middle; + } + .form-inline .input-group .input-group-addon, + .form-inline .input-group .input-group-btn, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: 0; + margin-bottom: 0; + padding-top: 11px; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 32px; +} +.form-horizontal .form-group { + margin-left: -15px; + margin-right: -15px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + margin-bottom: 0; + padding-top: 11px; + } +} +.form-horizontal .has-feedback .form-control-feedback { + right: 15px; +} +@media (min-width: 768px) { + .form-horizontal .form-group-lg .control-label { + padding-top: 24.9999994px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 6px; + } +} +.btn { + display: inline-block; + margin-bottom: 0; + font-weight: normal; + text-align: center; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + padding: 10px 18px; + font-size: 15px; + line-height: 1.42857143; + border-radius: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.btn:focus, +.btn:active:focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn.active.focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus, +.btn.focus { + color: #ffffff; + text-decoration: none; +} +.btn:active, +.btn.active { + outline: 0; + background-image: none; + -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 { + cursor: not-allowed; + pointer-events: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-default { + color: #ffffff; + background-color: #222222; + border-color: #222222; +} +.btn-default:hover, +.btn-default:focus, +.btn-default.focus, +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #ffffff; + background-color: #090909; + border-color: #040404; +} +.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.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: #222222; + border-color: #222222; +} +.btn-default .badge { + color: #222222; + background-color: #ffffff; +} +.btn-primary { + color: #ffffff; + background-color: #2780e3; + border-color: #2780e3; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary.focus, +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #1967be; + border-color: #1862b5; +} +.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.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: #2780e3; + border-color: #2780e3; +} +.btn-primary .badge { + color: #2780e3; + background-color: #ffffff; +} +.btn-success { + color: #ffffff; + background-color: #3fb618; + border-color: #3fb618; +} +.btn-success:hover, +.btn-success:focus, +.btn-success.focus, +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #2f8912; + border-color: #2c8011; +} +.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.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: #3fb618; + border-color: #3fb618; +} +.btn-success .badge { + color: #3fb618; + background-color: #ffffff; +} +.btn-info { + color: #ffffff; + background-color: #9954bb; + border-color: #9954bb; +} +.btn-info:hover, +.btn-info:focus, +.btn-info.focus, +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #7e3f9d; + border-color: #783c96; +} +.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.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: #9954bb; + border-color: #9954bb; +} +.btn-info .badge { + color: #9954bb; + background-color: #ffffff; +} +.btn-warning { + color: #ffffff; + background-color: #ff7518; + border-color: #ff7518; +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning.focus, +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #e45c00; + border-color: #da5800; +} +.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.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: #ff7518; + border-color: #ff7518; +} +.btn-warning .badge { + color: #ff7518; + background-color: #ffffff; +} +.btn-danger { + color: #ffffff; + background-color: #ff0039; + border-color: #ff0039; +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger.focus, +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #cc002e; + border-color: #c2002b; +} +.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.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: #ff0039; + border-color: #ff0039; +} +.btn-danger .badge { + color: #ff0039; + background-color: #ffffff; +} +.btn-link { + color: #2780e3; + font-weight: normal; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.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: #165ba8; + 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: #999999; + text-decoration: none; +} +.btn-lg, +.btn-group-lg > .btn { + padding: 18px 30px; + font-size: 19px; + line-height: 1.3333333; + border-radius: 0; +} +.btn-sm, +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 13px; + line-height: 1.5; + border-radius: 0; +} +.btn-xs, +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 13px; + line-height: 1.5; + border-radius: 0; +} +.btn-block { + display: block; + width: 100%; +} +.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 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +tr.collapse.in { + display: table-row; +} +tbody.collapse.in { + display: table-row-group; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition-property: height, visibility; + transition-property: height, visibility; + -webkit-transition-duration: 0.35s; + transition-duration: 0.35s; + -webkit-transition-timing-function: ease; + transition-timing-function: ease; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px dashed; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropup, +.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; + list-style: none; + font-size: 15px; + text-align: left; + background-color: #ffffff; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0; + -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: 9.5px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.42857143; + color: #333333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + text-decoration: none; + color: #ffffff; + background-color: #2780e3; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + outline: 0; + background-color: #2780e3; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: not-allowed; +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + left: auto; + right: 0; +} +.dropdown-menu-left { + left: 0; + right: auto; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 13px; + line-height: 1.42857143; + color: #999999; + white-space: nowrap; +} +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid; + content: ""; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + left: auto; + right: 0; + } + .navbar-right .dropdown-menu-left { + left: 0; + right: auto; + } +} +.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 + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar { + margin-left: -5px; +} +.btn-toolbar .btn-group, +.btn-toolbar .input-group { + float: left; +} +.btn-toolbar > .btn, +.btn-toolbar > .btn-group, +.btn-toolbar > .input-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-bottom-right-radius: 0; + border-top-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:not(:last-child) > .btn:last-child, +.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.btn-group > .btn-group:last-child:not(:first-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 > .btn + .dropdown-toggle { + padding-left: 8px; + padding-right: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-left: 12px; + padding-right: 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, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.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: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-bottom-left-radius: 0; + border-top-right-radius: 0; + 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:not(:last-child) > .btn:last-child, +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + float: none; + display: table-cell; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +.btn-group-justified > .btn-group .dropdown-menu { + left: auto; +} +[data-toggle="buttons"] > .btn input[type="radio"], +[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], +[data-toggle="buttons"] > .btn input[type="checkbox"], +[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-left: 0; + padding-right: 0; +} +.input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 64px; + padding: 18px 30px; + font-size: 19px; + line-height: 1.3333333; + border-radius: 0; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 64px; + line-height: 64px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon, +select[multiple].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: 31px; + padding: 5px 10px; + font-size: 13px; + line-height: 1.5; + border-radius: 0; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 31px; + line-height: 31px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].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: 10px 18px; + font-size: 15px; + font-weight: normal; + line-height: 1; + color: #333333; + text-align: center; + background-color: #e6e6e6; + border: 1px solid #cccccc; + border-radius: 0; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 13px; + border-radius: 0; +} +.input-group-addon.input-lg { + padding: 18px 30px; + font-size: 19px; + border-radius: 0; +} +.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 > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-top-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 > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + font-size: 0; + white-space: nowrap; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -1px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + z-index: 2; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-right: -1px; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + margin-left: -1px; +} +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.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: #e6e6e6; +} +.nav > li.disabled > a { + color: #999999; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999999; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #e6e6e6; + border-color: #2780e3; +} +.nav .nav-divider { + height: 1px; + margin: 9.5px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #dddddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 0 0 0 0; +} +.nav-tabs > li > a:hover { + border-color: #e6e6e6 #e6e6e6 #dddddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555555; + background-color: #ffffff; + border: 1px solid #dddddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.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: 0; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 0 0 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: #ffffff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 0; +} +.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: #ffffff; + background-color: #2780e3; +} +.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 { + text-align: center; + margin-bottom: 5px; +} +.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: 0; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #dddddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #dddddd; + border-radius: 0 0 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #ffffff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.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: 21px; + border: 1px solid transparent; +} +@media (min-width: 768px) { + .navbar { + border-radius: 0; + } +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + overflow-x: visible; + padding-right: 15px; + padding-left: 15px; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} +.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: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-left: 0; + padding-right: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-device-width: 480px) and (orientation: landscape) { + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + max-height: 200px; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .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: 14.5px 15px; + font-size: 19px; + line-height: 21px; + height: 50px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +.navbar-brand > img { + display: block; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + margin-right: 15px; + padding: 9px 10px; + margin-top: 8px; + margin-bottom: 8px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 0; +} +.navbar-toggle:focus { + outline: 0; +} +.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.25px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 21px; +} +@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: 21px; + } + .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: 14.5px; + padding-bottom: 14.5px; + } +} +.navbar-form { + margin-left: -15px; + margin-right: -15px; + padding: 10px 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); + margin-top: 3.5px; + margin-bottom: 3.5px; +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .form-control-static { + display: inline-block; + } + .navbar-form .input-group { + display: inline-table; + vertical-align: middle; + } + .navbar-form .input-group .input-group-addon, + .navbar-form .input-group .input-group-btn, + .navbar-form .input-group .form-control { + width: auto; + } + .navbar-form .input-group > .form-control { + width: 100%; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } + .navbar-form .form-group:last-child { + margin-bottom: 0; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 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 { + margin-bottom: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-btn { + margin-top: 3.5px; + margin-bottom: 3.5px; +} +.navbar-btn.btn-sm { + margin-top: 9.5px; + margin-bottom: 9.5px; +} +.navbar-btn.btn-xs { + margin-top: 14px; + margin-bottom: 14px; +} +.navbar-text { + margin-top: 14.5px; + margin-bottom: 14.5px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-left: 15px; + margin-right: 15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + margin-right: -15px; + } + .navbar-right ~ .navbar-right { + margin-right: 0; + } +} +.navbar-default { + background-color: #222222; + border-color: #121212; +} +.navbar-default .navbar-brand { + color: #ffffff; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #ffffff; + background-color: none; +} +.navbar-default .navbar-text { + color: #ffffff; +} +.navbar-default .navbar-nav > li > a { + color: #ffffff; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #ffffff; + background-color: #090909; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #090909; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #cccccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: transparent; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #090909; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #ffffff; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #121212; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: #090909; + color: #ffffff; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #ffffff; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: #090909; + } + .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: #ffffff; + background-color: #090909; + } + .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: #cccccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #ffffff; +} +.navbar-default .navbar-link:hover { + color: #ffffff; +} +.navbar-default .btn-link { + color: #ffffff; +} +.navbar-default .btn-link:hover, +.navbar-default .btn-link:focus { + color: #ffffff; +} +.navbar-default .btn-link[disabled]:hover, +fieldset[disabled] .navbar-default .btn-link:hover, +.navbar-default .btn-link[disabled]:focus, +fieldset[disabled] .navbar-default .btn-link:focus { + color: #cccccc; +} +.navbar-inverse { + background-color: #2780e3; + border-color: #1967be; +} +.navbar-inverse .navbar-brand { + color: #ffffff; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #ffffff; + background-color: none; +} +.navbar-inverse .navbar-text { + color: #ffffff; +} +.navbar-inverse .navbar-nav > li > a { + color: #ffffff; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #ffffff; + background-color: #1967be; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #ffffff; + background-color: #1967be; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #ffffff; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: transparent; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #1967be; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #ffffff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #1a6ecc; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + background-color: #1967be; + color: #ffffff; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #1967be; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #1967be; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #ffffff; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #ffffff; + background-color: #1967be; + } + .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: #ffffff; + background-color: #1967be; + } + .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: #ffffff; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #ffffff; +} +.navbar-inverse .navbar-link:hover { + color: #ffffff; +} +.navbar-inverse .btn-link { + color: #ffffff; +} +.navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link:focus { + color: #ffffff; +} +.navbar-inverse .btn-link[disabled]:hover, +fieldset[disabled] .navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link[disabled]:focus, +fieldset[disabled] .navbar-inverse .btn-link:focus { + color: #ffffff; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 21px; + list-style: none; + background-color: #f5f5f5; + border-radius: 0; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + content: "/\00a0"; + padding: 0 5px; + color: #cccccc; +} +.breadcrumb > .active { + color: #999999; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 21px 0; + border-radius: 0; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 10px 18px; + line-height: 1.42857143; + text-decoration: none; + color: #2780e3; + background-color: #ffffff; + border: 1px solid #dddddd; + margin-left: -1px; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + color: #165ba8; + background-color: #e6e6e6; + border-color: #dddddd; +} +.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: #999999; + background-color: #f5f5f5; + border-color: #dddddd; + cursor: default; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999999; + background-color: #ffffff; + border-color: #dddddd; + cursor: not-allowed; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 18px 30px; + font-size: 19px; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 13px; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.pager { + padding-left: 0; + margin: 21px 0; + list-style: none; + text-align: center; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 0; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #e6e6e6; +} +.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: #999999; + background-color: #ffffff; + cursor: not-allowed; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +a.label:hover, +a.label:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #222222; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #090909; +} +.label-primary { + background-color: #2780e3; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #1967be; +} +.label-success { + background-color: #3fb618; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #2f8912; +} +.label-info { + background-color: #9954bb; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #7e3f9d; +} +.label-warning { + background-color: #ff7518; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #e45c00; +} +.label-danger { + background-color: #ff0039; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #cc002e; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 13px; + font-weight: bold; + color: #ffffff; + line-height: 1; + vertical-align: baseline; + white-space: nowrap; + text-align: center; + background-color: #2780e3; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +.btn-xs .badge, +.btn-group-xs > .btn .badge { + top: 0; + padding: 1px 5px; +} +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} +.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #2780e3; + background-color: #ffffff; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding: 30px 15px; + margin-bottom: 30px; + color: inherit; + background-color: #e6e6e6; +} +.jumbotron h1, +.jumbotron .h1 { + color: inherit; +} +.jumbotron p { + margin-bottom: 15px; + font-size: 23px; + font-weight: 200; +} +.jumbotron > hr { + border-top-color: #cccccc; +} +.container .jumbotron, +.container-fluid .jumbotron { + border-radius: 0; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding: 48px 0; + } + .container .jumbotron, + .container-fluid .jumbotron { + padding-left: 60px; + padding-right: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 67.5px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 21px; + line-height: 1.42857143; + background-color: #ffffff; + border: 1px solid #dddddd; + border-radius: 0; + -webkit-transition: border 0.2s ease-in-out; + -o-transition: border 0.2s ease-in-out; + transition: border 0.2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + margin-left: auto; + margin-right: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #2780e3; +} +.thumbnail .caption { + padding: 9px; + color: #333333; +} +.alert { + padding: 15px; + margin-bottom: 21px; + border: 1px solid transparent; + border-radius: 0; +} +.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, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + background-color: #3fb618; + border-color: #4e9f15; + color: #ffffff; +} +.alert-success hr { + border-top-color: #438912; +} +.alert-success .alert-link { + color: #e6e6e6; +} +.alert-info { + background-color: #9954bb; + border-color: #7643a8; + color: #ffffff; +} +.alert-info hr { + border-top-color: #693c96; +} +.alert-info .alert-link { + color: #e6e6e6; +} +.alert-warning { + background-color: #ff7518; + border-color: #ff4309; + color: #ffffff; +} +.alert-warning hr { + border-top-color: #ee3800; +} +.alert-warning .alert-link { + color: #e6e6e6; +} +.alert-danger { + background-color: #ff0039; + border-color: #f0005e; + color: #ffffff; +} +.alert-danger hr { + border-top-color: #d60054; +} +.alert-danger .alert-link { + color: #e6e6e6; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + overflow: hidden; + height: 21px; + margin-bottom: 21px; + background-color: #cccccc; + border-radius: 0; + -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: 13px; + line-height: 21px; + color: #ffffff; + text-align: center; + background-color: #2780e3; + -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 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .progress-bar, +.progress-bar-striped { + 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: -o-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, +.progress-bar.active { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #3fb618; +} +.progress-striped .progress-bar-success { + 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: -o-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: #9954bb; +} +.progress-striped .progress-bar-info { + 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: -o-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: #ff7518; +} +.progress-striped .progress-bar-warning { + 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: -o-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: #ff0039; +} +.progress-striped .progress-bar-danger { + 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: -o-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 { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media, +.media-body { + zoom: 1; + overflow: hidden; +} +.media-body { + width: 10000px; +} +.media-object { + display: block; +} +.media-right, +.media > .pull-right { + padding-left: 10px; +} +.media-left, +.media > .pull-left { + padding-right: 10px; +} +.media-left, +.media-right, +.media-body { + display: table-cell; + vertical-align: top; +} +.media-middle { + vertical-align: middle; +} +.media-bottom { + vertical-align: bottom; +} +.media-heading { + margin-top: 0; + margin-bottom: 5px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + margin-bottom: 20px; + padding-left: 0; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #ffffff; + border: 1px solid #dddddd; +} +.list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +a.list-group-item { + color: #555555; +} +a.list-group-item .list-group-item-heading { + color: #333333; +} +a.list-group-item:hover, +a.list-group-item:focus { + text-decoration: none; + color: #555555; + background-color: #f5f5f5; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + background-color: #e6e6e6; + color: #999999; + cursor: not-allowed; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #999999; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #ffffff; + background-color: #2780e3; + border-color: #dddddd; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #dceafa; +} +.list-group-item-success { + color: #ffffff; + background-color: #3fb618; +} +a.list-group-item-success { + color: #ffffff; +} +a.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +a.list-group-item-success:focus { + color: #ffffff; + background-color: #379f15; +} +a.list-group-item-success.active, +a.list-group-item-success.active:hover, +a.list-group-item-success.active:focus { + color: #fff; + background-color: #ffffff; + border-color: #ffffff; +} +.list-group-item-info { + color: #ffffff; + background-color: #9954bb; +} +a.list-group-item-info { + color: #ffffff; +} +a.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +a.list-group-item-info:focus { + color: #ffffff; + background-color: #8d46b0; +} +a.list-group-item-info.active, +a.list-group-item-info.active:hover, +a.list-group-item-info.active:focus { + color: #fff; + background-color: #ffffff; + border-color: #ffffff; +} +.list-group-item-warning { + color: #ffffff; + background-color: #ff7518; +} +a.list-group-item-warning { + color: #ffffff; +} +a.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +a.list-group-item-warning:focus { + color: #ffffff; + background-color: #fe6600; +} +a.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus { + color: #fff; + background-color: #ffffff; + border-color: #ffffff; +} +.list-group-item-danger { + color: #ffffff; + background-color: #ff0039; +} +a.list-group-item-danger { + color: #ffffff; +} +a.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +a.list-group-item-danger:focus { + color: #ffffff; + background-color: #e60033; +} +a.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus { + color: #fff; + background-color: #ffffff; + border-color: #ffffff; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 21px; + background-color: #ffffff; + border: 1px solid transparent; + border-radius: 0; + -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-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: -1; + border-top-left-radius: -1; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 17px; + color: inherit; +} +.panel-title > a, +.panel-title > small, +.panel-title > .small, +.panel-title > small > a, +.panel-title > .small > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #dddddd; + border-bottom-right-radius: -1; + border-bottom-left-radius: -1; +} +.panel > .list-group, +.panel > .panel-collapse > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item, +.panel > .panel-collapse > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child, +.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-right-radius: -1; + border-top-left-radius: -1; +} +.panel > .list-group:last-child .list-group-item:last-child, +.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: -1; + border-bottom-left-radius: -1; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-left: 15px; + padding-right: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-right-radius: -1; + border-top-left-radius: -1; +} +.panel > .table:first-child > thead:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: -1; + border-top-right-radius: -1; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: -1; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: -1; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: -1; + border-bottom-left-radius: -1; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-left-radius: -1; + border-bottom-right-radius: -1; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: -1; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: -1; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive, +.panel > .table + .panel-body, +.panel > .table-responsive + .panel-body { + border-top: 1px solid #dddddd; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.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:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.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, +.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 { + border-bottom: 0; +} +.panel > .table-responsive { + border: 0; + margin-bottom: 0; +} +.panel-group { + margin-bottom: 21px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 0; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + border-top: 1px solid #dddddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #dddddd; +} +.panel-default { + border-color: #dddddd; +} +.panel-default > .panel-heading { + color: #333333; + background-color: #f5f5f5; + border-color: #dddddd; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #dddddd; +} +.panel-default > .panel-heading .badge { + color: #f5f5f5; + background-color: #333333; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #dddddd; +} +.panel-primary { + border-color: #2780e3; +} +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #2780e3; + border-color: #2780e3; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #2780e3; +} +.panel-primary > .panel-heading .badge { + color: #2780e3; + background-color: #ffffff; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #2780e3; +} +.panel-success { + border-color: #4e9f15; +} +.panel-success > .panel-heading { + color: #ffffff; + background-color: #3fb618; + border-color: #4e9f15; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #4e9f15; +} +.panel-success > .panel-heading .badge { + color: #3fb618; + background-color: #ffffff; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #4e9f15; +} +.panel-info { + border-color: #7643a8; +} +.panel-info > .panel-heading { + color: #ffffff; + background-color: #9954bb; + border-color: #7643a8; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #7643a8; +} +.panel-info > .panel-heading .badge { + color: #9954bb; + background-color: #ffffff; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #7643a8; +} +.panel-warning { + border-color: #ff4309; +} +.panel-warning > .panel-heading { + color: #ffffff; + background-color: #ff7518; + border-color: #ff4309; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ff4309; +} +.panel-warning > .panel-heading .badge { + color: #ff7518; + background-color: #ffffff; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ff4309; +} +.panel-danger { + border-color: #f0005e; +} +.panel-danger > .panel-heading { + color: #ffffff; + background-color: #ff0039; + border-color: #f0005e; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #f0005e; +} +.panel-danger > .panel-heading .badge { + color: #ff0039; + background-color: #ffffff; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #f0005e; +} +.embed-responsive { + position: relative; + display: block; + height: 0; + padding: 0; + overflow: hidden; +} +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + left: 0; + bottom: 0; + height: 100%; + width: 100%; + border: 0; +} +.embed-responsive-16by9 { + padding-bottom: 56.25%; +} +.embed-responsive-4by3 { + padding-bottom: 75%; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 0; + -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: 0; +} +.well-sm { + padding: 9px; + border-radius: 0; +} +.close { + float: right; + font-size: 22.5px; + font-weight: bold; + line-height: 1; + color: #ffffff; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover, +.close:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.modal-open { + overflow: hidden; +} +.modal { + display: none; + overflow: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + -o-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -o-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #ffffff; + border: 1px solid #999999; + border: 1px solid transparent; + border-radius: 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; + outline: 0; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} +.modal-header { + padding: 15px; + border-bottom: 1px solid #e5e5e5; + min-height: 16.42857143px; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.42857143; +} +.modal-body { + position: relative; + padding: 20px; +} +.modal-footer { + padding: 20px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer .btn + .btn { + margin-left: 5px; + margin-bottom: 0; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .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); + } + .modal-sm { + width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg { + width: 900px; + } +} +.tooltip { + position: absolute; + z-index: 1070; + display: block; + font-family: "Source Sans Pro", Calibri, Candara, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); +} +.tooltip.in { + opacity: 0.9; + filter: alpha(opacity=90); +} +.tooltip.top { + margin-top: -3px; + padding: 5px 0; +} +.tooltip.right { + margin-left: 3px; + padding: 0 5px; +} +.tooltip.bottom { + margin-top: 3px; + padding: 5px 0; +} +.tooltip.left { + margin-left: -3px; + padding: 0 5px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + border-radius: 0; +} +.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-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.top-left .tooltip-arrow { + bottom: 0; + right: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.top-right .tooltip-arrow { + bottom: 0; + left: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + right: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + left: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: none; + max-width: 276px; + padding: 1px; + font-family: "Source Sans Pro", Calibri, Candara, Arial, sans-serif; + font-size: 15px; + font-weight: normal; + line-height: 1.42857143; + text-align: left; + background-color: #ffffff; + background-clip: padding-box; + border: 1px solid #cccccc; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 0; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + white-space: normal; +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + margin: 0; + padding: 8px 14px; + font-size: 15px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: -1 -1 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 { + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #999999; + border-top-color: rgba(0, 0, 0, 0.25); + bottom: -11px; +} +.popover.top > .arrow:after { + content: " "; + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #ffffff; +} +.popover.right > .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-left-width: 0; + border-right-color: #999999; + border-right-color: rgba(0, 0, 0, 0.25); +} +.popover.right > .arrow:after { + content: " "; + left: 1px; + bottom: -10px; + border-left-width: 0; + border-right-color: #ffffff; +} +.popover.bottom > .arrow { + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999999; + border-bottom-color: rgba(0, 0, 0, 0.25); + top: -11px; +} +.popover.bottom > .arrow:after { + content: " "; + top: 1px; + margin-left: -10px; + border-top-width: 0; + border-bottom-color: #ffffff; +} +.popover.left > .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999999; + border-left-color: rgba(0, 0, 0, 0.25); +} +.popover.left > .arrow:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: #ffffff; + bottom: -10px; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + overflow: hidden; + width: 100%; +} +.carousel-inner > .item { + display: none; + position: relative; + -webkit-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + line-height: 1; +} +@media all and (transform-3d), (-webkit-transform-3d) { + .carousel-inner > .item { + -webkit-transition: -webkit-transform 0.6s ease-in-out; + -moz-transition: -moz-transform 0.6s ease-in-out; + -o-transition: -o-transform 0.6s ease-in-out; + transition: transform 0.6s ease-in-out; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-perspective: 1000; + -moz-perspective: 1000; + perspective: 1000; + } + .carousel-inner > .item.next, + .carousel-inner > .item.active.right { + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + left: 0; + } + .carousel-inner > .item.prev, + .carousel-inner > .item.active.left { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + left: 0; + } + .carousel-inner > .item.next.left, + .carousel-inner > .item.prev.right, + .carousel-inner > .item.active { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + left: 0; + } +} +.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; + left: 0; + bottom: 0; + width: 15%; + opacity: 0.5; + filter: alpha(opacity=50); + font-size: 20px; + color: #ffffff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); + background-image: -o-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 { + left: auto; + right: 0; + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); + background-image: -o-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 { + outline: 0; + color: #ffffff; + text-decoration: none; + opacity: 0.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%; + margin-left: -10px; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; + margin-right: -10px; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + line-height: 1; + 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%; + margin-left: -30%; + padding-left: 0; + list-style: none; + text-align: center; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + border: 1px solid #ffffff; + border-radius: 10px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); +} +.carousel-indicators .active { + margin: 0; + width: 12px; + height: 12px; + background-color: #ffffff; +} +.carousel-caption { + position: absolute; + left: 15%; + right: 15%; + bottom: 20px; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #ffffff; + 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 .glyphicon-chevron-left, + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + font-size: 30px; + } + .carousel-control .glyphicon-chevron-left, + .carousel-control .icon-prev { + margin-left: -15px; + } + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-next { + margin-right: -15px; + } + .carousel-caption { + left: 20%; + right: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-footer:before, +.modal-footer:after { + content: " "; + display: table; +} +.clearfix:after, +.dl-horizontal dd:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-footer:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: 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; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + display: none !important; +} +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .visible-xs-block { + display: block !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline { + display: inline !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline-block { + display: inline-block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-block { + display: block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline { + display: inline !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline-block { + display: inline-block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-block { + display: block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline { + display: inline !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline-block { + display: inline-block !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg-block { + display: block !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline { + display: inline !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline-block { + display: inline-block !important; + } +} +@media (max-width: 767px) { + .hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg { + display: none !important; + } +} +.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +.visible-print-block { + display: none !important; +} +@media print { + .visible-print-block { + display: block !important; + } +} +.visible-print-inline { + display: none !important; +} +@media print { + .visible-print-inline { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; +} +@media print { + .visible-print-inline-block { + display: inline-block !important; + } +} +@media print { + .hidden-print { + display: none !important; + } +} + +/*# sourceMappingURL=01-vendor.css.map */ \ No newline at end of file diff --git a/doc-src/_layout.html b/doc-src/_layout.html index 871e3ad74..0a12e25e6 100644 --- a/doc-src/_layout.html +++ b/doc-src/_layout.html @@ -12,7 +12,12 @@ - mitmproxy $!VERSION!$ docs + + + + + diff --git a/doc-src/mitmproxy-long.png b/doc-src/mitmproxy-long.png new file mode 100644 index 0000000000000000000000000000000000000000..f9397d1e55c2e96a2bc849f3402ffbfdd6146e72 GIT binary patch literal 123829 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

fAhup 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

  • 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 literal 0 HcmV?d00001 From b91999507e662cbcce6c7968647d8cbac54fbcb5 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 23 May 2015 12:36:52 +1200 Subject: [PATCH 160/170] Move websitelayout to website. --- doc-src/_websitelayout.html | 56 ------------------------------------- doc-src/index.py | 3 +- 2 files changed, 1 insertion(+), 58 deletions(-) delete mode 100644 doc-src/_websitelayout.html diff --git a/doc-src/_websitelayout.html b/doc-src/_websitelayout.html deleted file mode 100644 index 5a7c01bb5..000000000 --- a/doc-src/_websitelayout.html +++ /dev/null @@ -1,56 +0,0 @@ - - -
    -
    -
    - $!navbar!$ -
    -
    - - $!body!$ -
    -
    -
    - -
    -
    -
    -

    Copyright 2014 Aldo Cortesi

    -
    -
    - diff --git a/doc-src/index.py b/doc-src/index.py index 52b9c31a4..b049e3ce1 100644 --- a/doc-src/index.py +++ b/doc-src/index.py @@ -15,10 +15,9 @@ ns.VERSION = version.VERSION if ns.options.website: ns.idxpath = "doc/index.html" - this.layout = countershape.Layout("_websitelayout.html") else: ns.idxpath = "index.html" - this.layout = countershape.Layout("_layout.html") +this.layout = countershape.Layout("_layout.html") ns.title = countershape.template.Template(None, "

    @!this.title!@

    ") this.titlePrefix = "%s - " % version.NAMEVERSION From 0a812656617be313c6648918f9b4c52a2ddb59c4 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 24 May 2015 13:16:49 +1200 Subject: [PATCH 161/170] docs: adjust for countershape changes --- doc-src/_layout.html | 90 ++++++++++++++++++++++++-------------------- doc-src/index.py | 7 ++-- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/doc-src/_layout.html b/doc-src/_layout.html index 0a12e25e6..221da4669 100644 --- a/doc-src/_layout.html +++ b/doc-src/_layout.html @@ -1,46 +1,54 @@ - -
  • " p = state.application.getPage(page) - return pre + '%s
  • '%(model.UrlTo(page), p.title) + return pre + '%s'%(countershape.widgets.UrlTo(page), p.title) ns.nav = nav ns.navbar = countershape.template.File(None, "_nav.html") From 2135bcec61cf346555f8fd1e24bbb9267d002502 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sun, 24 May 2015 14:09:51 +1200 Subject: [PATCH 162/170] docs: styles now live in www.mitproxy.org repo, make images responsive --- doc-src/01-vendor.css | 1 - doc-src/02-app.css | 43 +++++++++++++++++++++++++ doc-src/02-docstyle.css | 36 --------------------- doc-src/_layout.html | 6 ++-- doc-src/dev/architecture.html | 4 +-- doc-src/howmitmproxy.html | 8 ++--- doc-src/mitmproxy.html | 28 ++++++++-------- doc-src/modes.html | 20 ++++++------ doc-src/tutorials/gamecenter.html | 6 ++-- doc-src/tutorials/transparent-dhcp.html | 8 ++--- 10 files changed, 83 insertions(+), 77 deletions(-) create mode 100644 doc-src/02-app.css delete mode 100644 doc-src/02-docstyle.css diff --git a/doc-src/01-vendor.css b/doc-src/01-vendor.css index 2f65c8a32..9c97647aa 100644 --- a/doc-src/01-vendor.css +++ b/doc-src/01-vendor.css @@ -1,4 +1,3 @@ -@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,700"); .navbar-inverse .badge { background-color: #fff; color: #2780e3; diff --git a/doc-src/02-app.css b/doc-src/02-app.css new file mode 100644 index 000000000..c7bd41ffc --- /dev/null +++ b/doc-src/02-app.css @@ -0,0 +1,43 @@ +.masthead { + text-align: center; + border-bottom: 0; +} +.frontpage .talks div { + margin-bottom: 10px; +} +.nav-sidebar { + background-color: #f0f0f0; + margin-bottom: 20px; +} +.nav-sidebar li { + line-height: 1.1; +} +.nav-sidebar li > a, +.nav-sidebar .nav-header { + padding-left: 20px; +} +.nav-sidebar .nav-header { + margin-top: 1em; + font-size: 1.2em; + font-weight: bold; +} +.nav-sidebar .active > a, +.nav-sidebar .active > a:hover, +.nav-sidebar .active > a:focus { + color: #fff; + background-color: #428bca; +} +.tablenum { + font-weight: bold; +} +.nowrap { + white-space: nowrap; +} +.page-header { + margin: 0px 0 22px; +} +.page-header h1 { + margin-top: 0px; +} + +/*# sourceMappingURL=02-app.css.map */ \ No newline at end of file diff --git a/doc-src/02-docstyle.css b/doc-src/02-docstyle.css deleted file mode 100644 index 59528bb38..000000000 --- a/doc-src/02-docstyle.css +++ /dev/null @@ -1,36 +0,0 @@ - - -/* Sidebar navigation */ -.nav-sidebar { - margin-right: -21px; /* 20px padding + 1px border */ - margin-bottom: 20px; - margin-left: -20px; -} -.nav-sidebar > li > a { - padding-right: 20px; - padding-left: 20px; -} -.nav-sidebar > .active > a, -.nav-sidebar > .active > a:hover, -.nav-sidebar > .active > a:focus { - color: #fff; - background-color: #428bca; -} - - - -.tablenum { - font-weight: bold; -} - -.nowrap { - white-space: nowrap; -} - -h1 { - line-height: 1.1; -} - -.page-header { - margin: 0px 0 22px; -} diff --git a/doc-src/_layout.html b/doc-src/_layout.html index 221da4669..e8b019344 100644 --- a/doc-src/_layout.html +++ b/doc-src/_layout.html @@ -5,7 +5,7 @@ $!header!$ -

    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®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