PKY6BwvEEsarge-0.1.1/index.html Welcome to sarge’s documentation! — Sarge 0.1.1 documentation
Comments powered by Disqus

Project Versions

Next topic

Overview

This Page

PKZ6BfB?++sarge-0.1.1/searchindex.jsSearch.setIndex({objects:{"":{Capture:[2,0,1,""],Pipeline:[2,0,1,""],run:[2,2,1,""],get_stderr:[2,2,1,""],shell_format:[2,2,1,""],get_both:[2,2,1,""],Popen:[2,0,1,""],shell_quote:[2,2,1,""],default_capture_timeout:[2,3,1,""],Command:[2,0,1,""],capture_stdout:[2,2,1,""],capture_both:[2,2,1,""],get_stdout:[2,2,1,""],capture_stderr:[2,2,1,""]},Capture:{read:[2,1,1,""],readline:[2,1,1,""],readlines:[2,1,1,""],expect:[2,1,1,""]},Pipeline:{commands:[2,3,1,""],returncode:[2,3,1,""],run:[2,1,1,""],returncodes:[2,3,1,""],close:[2,1,1,""],wait:[2,1,1,""]},Command:{terminate:[2,1,1,""],poll:[2,1,1,""],run:[2,1,1,""],kill:[2,1,1,""],wait:[2,1,1,""]}},terms:{all:[4,1,2,3],code:[0,1,2,3,4],chain:[0,3],illustr:3,consum:3,snip:1,sleep:4,abil:4,gnuwin32:4,follow:[4,1,2,3],typeerror:3,depend:3,sensit:4,specif:[0,3,4],send:3,stack_trac:1,program:[4,3],swap:[0,1,2,4],under:[0,1,3,4],sens:3,sent:3,sourc:[4,1,2,3],everi:[4,1,3],string:[1,2,3],fals:[4,1,2,3],reader:1,util:3,print:[4,1,3],mechan:2,parti:3,failur:2,veri:4,subprocess:[0,1,2,3,4],exact:3,relev:[4,3],condition:[0,3],recip:1,magic:1,level:[4,3],necessit:3,cmd:4,list:[4,1,2,3],iter:[0,3],unquot:2,session:3,shlex:[4,1],stderr:[0,1,2,3,4],sajip:4,initialis:2,pleas:[0,3],prevent:[4,3],fortun:4,"l\u00e1szl\u00f3":1,direct:[0,3],crop:3,consequ:3,second:[4,1,2],pass:[0,2,3,4],submit:1,compat:[0,4],aim:0,what:[0,1,3,4],abc:3,sub:[1,2,3],section:1,abl:[1,3],invok:[1,2,3],uniform:4,current:[4,1,2],version:[0,2,4],capture_stdout:[4,2,3],"new":[4,1,3],"public":[1,2],libintl3:4,redirect:[0,2,3],full:3,deriv:1,vinai:[4,1,3],honour:4,gener:[2,3],here:[4,1,2,3],behaviour:[1,3],shouldn:[1,3],let:[4,3],ubuntu:4,standard:[4,1,2],sinc:1,valu:[1,2,3],wait:[4,1,2,3],box:4,convert:[1,2,3],convers:3,volumin:[4,2],popen:[4,1,2,3],queue:[1,3],amount:[0,1],behav:3,synchronis:3,permit:1,earli:4,implement:[4,1],"20mb":1,envoi:4,string_or_pattern:2,sheila:3,control:[1,3],semant:3,via:3,repositori:4,danger:3,search:[4,2,3],modul:[4,1,2,3],user_input:3,put:[4,2],unix:[2,3],api:[0,1,2,3,4],instal:[0,3,4],txt:2,post:[4,2,3],unit:[1,2],kei:3,from:[0,1,2,3,4],describ:[1,2],would:[1,2,3],commun:[4,1,3],sake:2,coghlan:1,two:[4,2,3],next:[0,1,2,3,4],implic:[0,1],almost:3,call:[4,1,2,3],usr:3,recommend:4,taken:1,simpler:1,type:[2,3],until:[1,2,3],more:[4,3],sort:3,sudo:3,afford:1,convert_field:1,anywai:1,enhanc:1,warn:3,flag:[2,3],default_capture_timeout:[1,2],indic:[1,2,3],particular:2,unpack:3,behalf:4,must:[2,3],placehold:[0,1,2,3,4],none:[1,2,3],word:1,sometim:[1,3],get_stdout:[4,2,3],setup:3,work:[0,1,2,3,4],dev:[2,3],cat:[4,1,2,3],descriptor:2,can:[4,1,2,3],learn:4,capture_both:[2,3],unread:3,def:3,problemat:3,overrid:[1,2],devnul:[4,3],oneiric64:4,tap:1,encapsul:4,stream:[0,1,2,3,4],scan:1,process:[0,1,2,3,4],lock:[4,3],registr:4,share:4,backslash:1,accept:[4,3],topic:3,minimum:4,explor:3,tarbal:3,occur:[4,1,3],delai:[4,3],alwai:[1,3],"0xa11d50":3,cours:[4,1,2,3],end:[1,2,3],newlin:[2,3],thing:[4,1,3],rather:3,anoth:[2,3],ordinari:3,get:[4,1,3],write:3,how:[0,1,2,3],anyon:0,sever:1,env:3,instead:[1,2,3],simpl:[4,1,2,3],updat:4,map:2,express:[2,3],resourc:3,overridden:1,after:[4,3],coreutil:4,mac:4,mai:[4,2,3],multipl:4,data:[0,1,2,3,4],welcom:0,stabil:[0,4],circumst:3,"short":[4,3],attempt:4,practic:[2,3],third:3,tutori:[0,3,4],counter:[1,2],greet:3,element:[2,3],issu:[0,1,2,3,4],inform:[4,3],maintain:2,environ:[0,3],allow:[4,1,2],shellformatt:1,order:[4,3],feed:[1,2],tty:3,help:[4,1,2,3],over:[0,3],"0xa96c50":3,becaus:[4,3],pascal:4,own:[4,2],through:[1,2,3],flexibl:4,mainli:2,paramet:[2,3],style:4,fix:4,jim:3,unicode_liter:3,better:1,platform:[0,2,3,4],offic:4,bin:[1,3],mail:[2,3],main:[0,3,4],might:[4,1,2,3],easier:[0,3,4],them:[1,2,3],good:4,"return":[4,1,2,3],pure:3,thei:3,handl:[0,1,3,4],safe:[0,1,2,3,4],initi:4,"break":[4,3],mention:3,"0x1057110":3,yourself:2,grammar:1,name:[4,3],anyth:3,didn:3,separ:[4,2,3],token:1,timeout:[0,1,2,3],each:[1,2,3],debug:[0,1],found:[2,3],unicod:[0,2,3,4],readxxx:1,tracer:1,mean:[4,1,2,3],subset:4,replac:1,chunk:1,hard:[2,3],continu:2,realli:3,ensur:[4,2,3],expect:[4,1,2,3],operand:[2,3],happen:[1,2],commiss:4,fmt:2,special:[1,2,3],out:[4,3],variabl:[4,1,2,3],"try":3,shown:2,safeti:2,space:4,facil:[4,1,2],content:[2,3],internet:3,hardwar:4,got:3,cwd:3,multilin:[2,3],hang:[1,3],"0x20f3dd0":3,fred:3,reason:3,base:1,zombi:3,dire:3,releas:4,org:[4,3],"byte":[0,1,2,3],bash:[4,3],care:3,wai:[4,1,2,3],thread:[0,1,2,3,4],befor:[1,3],forc:[4,1],could:[1,2,3],synchron:[0,2,3],keep:[4,1],turn:1,perhap:3,place:[2,3],isn:3,circuit:3,think:1,first:[4,2],oper:4,softwar:4,rang:[4,1],directli:3,onc:3,arrai:2,number:[2,3],echo:[4,2,3],alreadi:1,done:[4,3],construct:[4,1,2,3],wasn:3,sizehint:2,open:2,hood:[0,1,3],size:[1,2],differ:3,lister:3,pexpect:3,convent:2,script:3,top:3,system:[1,3],least:3,attack:[4,3],sergeant:4,similarli:3,termin:[0,1,2,3,4],conveni:[4,2,3],"0xb8dd50":3,headi:3,too:3,shell:[0,1,2,3,4],consol:3,option:[0,1,3],get_both:[4,2,3],copi:4,specifi:[4,1,2,3],tee:[4,2],shell_command:1,part:[1,2,3],pars:[0,1,2,4],allegedli:4,off:1,than:[4,1,2,3],wide:4,liter:[2,3],grep:3,keyword:[1,2,3],instanc:[1,2,3],provid:[1,2,3],tree:1,zero:[2,3],charact:[1,3],project:[0,1,4],matter:2,posix:[0,2,3,4],str:[2,3],lover:4,posit:[1,2,3],"_______":4,other:[0,1,2,3,4],fork:[0,3],sai:2,test_sarg:[4,1],py3:3,mind:4,ani:[4,1,2,3],packag:[4,3],taster:4,expir:2,have:[4,1,2,3],"__main__":3,need:[0,1,2,3,4],properli:[2,3],"null":2,caus:[1,2,3],form:[4,2],"_get_handl":1,latter:3,note:[0,2,3,4],also:[4,1,2,3],without:[4,1,2,3],"0x247ed50":3,take:[1,3],which:[0,1,2,3,4],tupl:2,combin:3,analogu:2,brace:2,prepar:3,singl:2,even:[1,3],begin:1,sure:3,unless:[1,2],distribut:[1,3],though:[1,2,3],buffer:[0,1,2,3,4],licens:1,reach:4,lexic:1,regular:[2,3],cygwin:4,alpha:4,"class":[0,1,2,3,4],bytesio:2,get_stderr:[4,2,3],simplic:2,don:[4,1,2,3],later:3,cover:4,doe:[4,2,3],pipe:[4,1,2,3],bracket:1,wildcard:3,pattern:[0,2,3,4],enclos:1,unchang:2,amus:4,fact:2,somewhat:[4,2],show:[1,3],text:[4,2,3],esoter:[4,2],random:1,serialis:4,syntax:[0,2,4],bring:3,concurr:3,permiss:3,find:[4,1,2,3],nagi:1,involv:[4,3],absolut:4,onli:[2,3],explicitli:[1,2],locat:3,just:[0,1,3,4],async:[4,1,2,3],configur:3,enough:4,trace_thread:1,should:[4,2,3],experiment:4,rich:4,local:2,meant:3,dup2:2,nasti:3,likewis:3,stop:[1,2],repr:3,nativ:3,cannot:3,ssh:3,foobarbaz:4,report:[4,3],requir:[4,2,3],perus:3,child:[0,1,2,3],bar:[4,2,3],shy:3,possibl:[4,3],baz:[4,2,3],method:[4,1,2,3],stop_thread:2,"default":[1,2,3],common:[0,3],contain:[4,1,2],where:[4,1,2,3],view:[2,3],set:[1,2,3],"float":2,noth:3,see:[4,1,2,3],num:1,result:[4,2,3],arg:[2,3],bytestr:[2,3],close:[4,1,2,3],analog:[1,3],statu:[0,4],still:3,give:3,correctli:4,vari:3,someth:3,dll:4,written:2,between:3,progress:0,awai:3,approach:[0,1,3],across:1,attribut:[0,1,2,3],altern:1,parent:3,numer:4,ask:2,were:[2,3],libiconv2:4,len:1,shell_format:[4,2,3],readlin:[4,1,2,3],addit:[1,3],both:2,protect:3,last:[4,2,3],howev:[4,1,2,3],constructor:[1,2,3],etc:3,eta:4,present:4,context:[0,3],logic:[4,1,3],improv:4,whole:2,among:4,point:[1,2,3],overview:[0,4],inspir:1,returncod:[4,2,3],"0x175ed10":4,fashion:1,linux:[4,3],respect:[1,3],poll:[4,2],assum:3,duplic:1,shlext:1,creat:[0,1,2,3],coupl:1,devic:3,sarg:[0,1,2,3,4],been:[4,1,2,3],much:[4,2,3],"0x2765b10":3,outbut:3,immedi:[4,2,3],feedback:4,life:[0,4],defunct:3,argument:[4,1,2,3],understand:[2,3],togeth:3,demand:3,systemroot:3,worri:3,former:3,wrapper:[0,2],"case":[1,2,3],ident:4,look:[0,1,2,3,4],plain:3,properti:3,formatt:[1,2],defin:[1,2,3],"while":[4,2,3],gritti:4,abov:[4,2,3],error:2,invoc:[4,3],manner:3,spawn:[4,2,3],propag:4,layer:3,advantag:3,stdout:[0,1,2,3,4],readi:3,side:2,non:4,issue6721:3,kwarg:2,limit:3,descript:1,ascii:3,disappear:3,complet:[4,1,2,3],develop:4,descent:1,perform:4,suggest:4,make:[0,1,2,3,4],cross:[2,3],same:[4,1,2,3],check:1,python:[0,1,3,4],complex:3,shell_shlex:[4,1],split:[4,3],buffer_s:[2,3],document:[0,4],difficult:4,exhaust:2,finish:2,http:[4,3],blais:4,wherea:[2,3],effect:[1,2,3],hand:3,moment:1,rais:4,temporari:2,user:[0,3],mani:3,extern:[0,3,4],chang:[0,1,4],stdin:[2,3],appropri:3,kept:3,scenario:[4,1],firstli:1,well:3,inherit:3,exampl:[4,1,2,3],command:[0,1,2,3,4],thi:[0,1,2,3,4],programm:4,reward:4,left:3,explan:[4,2],interpret:3,default_expect_timeout:2,identifi:1,paus:1,execut:[0,2,3,4],prompt:3,"____________________________________":4,kill:[4,2,3],touch:4,unbuff:3,yet:[4,2],web:3,now:[4,3],easi:3,mix:3,recurs:1,had:3,except:[4,3],exposit:3,larg:[0,1,3],exercis:4,schedul:3,els:3,har:[4,1,3],bnf:1,match:[2,3],opt:3,applic:[0,2,4],around:[4,3],format:[0,1,2,3,4],read:[4,1,2,3],reitz:4,know:[4,2],world:3,bit:3,password:3,reap:3,shell_quot:[4,1,2,3],measur:1,like:[4,1,2,3],success:[2,3],integ:2,mit:1,kenneth:4,"boolean":3,necessari:[4,1],either:[2,3],leav:[4,3],output:[0,1,2,3,4],manag:[0,1,3],underli:[4,2],right:3,often:4,captur:[0,1,2,3,4],interact:[0,2,3,4],textiowrapp:3,pipelin:[0,1,2,3,4],born:4,intern:[4,1,3],flush:3,guarante:3,surpris:3,librari:[4,1,2,3],capture_stderr:[2,3],virtualenv:3,basic:[0,1],cooper:3,lead:[4,2,3],avoid:[4,1,3],subclass:[1,2],tracker:[4,1,3],exit:[1,3],inject:[4,2,3],recognis:2,condit:[4,2,3],foo:[4,2,3],reproduc:3,refer:[0,1,2,3,4],machin:3,core:1,object:[4,1,2,3],run:[4,1,2,3],nitti:4,power:4,acronym:4,lose:2,usag:[0,1,2,3,4],who:0,step:[0,1,2,3,4],crlf:[2,3],although:[4,3],boundari:[1,2,3],"__name__":3,major:3,stage:4,unsaf:3,comparison:3,about:[0,1,3,4],actual:2,"0x24b3190":3,memori:[1,2,3],nbar:3,stand:4,act:3,discard:3,luck:3,produc:3,block:[0,1,2,3],fulfil:2,"__future__":3,activest:1,within:[2,3],encod:[2,3],due:2,resili:4,empti:[1,3],strip:3,wrap:[4,2,3],"import":[4,1,3],cowthink:4,your:[4,1,3],merg:3,span:3,log:[0,1,2,4],suffici:1,area:[4,3],aren:4,support:[4,2],"long":2,why:[0,4],avail:[2,3],start:[4,3],window:[4,2,3],interfac:4,includ:[1,2,3],lot:[1,3],suit:[4,3],"function":[0,1,2,3,4],creation:[4,1],unexpect:3,offer:[4,3],altogeth:3,some:[4,1,3],bite:3,back:[1,3],line:[4,2,3],"true":[4,1,2,3],bug:3,longer:[4,2],suppli:3,made:[4,1],utf:[2,3],input:[0,2,3],consist:[1,2],understood:[0,2],whether:2,access:[4,3],bucket:3,asynchron:[0,2,3,4],unusu:3,those:[4,1,2],indefinit:[1,2,3],site:3,otherwis:[1,2,3],problem:[4,3],deadlock:[4,1],connect:2,featur:[0,4],constant:[1,2],evalu:3,"int":2,certain:3,parser:[1,2],doesn:[2,3],repres:2,file:[4,1,2,3],pip:3,simplest:3,fill:[4,2,3],again:3,quot:[0,1,2,3,4],want:[4,1,2,3],dispos:3,when:[0,1,2,3,4],detail:[4,3],nick:1,codec:[2,3],bool:2,futur:[0,1],rememb:3,test:[0,1,3,4],you:[4,1,2,3],"0x7f3320e94310":3,tmp:3,junk:3,intend:4,ftp:3,sequenc:3,decod:3,rise:3,intent:2,consid:[4,2,3],doubl:2,bitbucket:4,receiv:3,haven:3,directori:[0,3,4],pseudo:3,potenti:[1,3],time:[4,1,3],far:3,escap:1,hello:3,stick:3},objtypes:{"0":"py:class","1":"py:method","2":"py:function","3":"py:attribute"},titles:["Welcome to sarge’s documentation!","Under the hood","API Reference","Tutorial","Overview"],objnames:{"0":["py","class","Python class"],"1":["py","method","Python method"],"2":["py","function","Python function"],"3":["py","attribute","Python attribute"]},filenames:["index","internals","reference","tutorial","overview"]})PKZ6B33sarge-0.1.1/genindex.html Index — Sarge 0.1.1 documentation

Project Versions

PKZ6B \XTTsarge-0.1.1/reference.html API Reference — Sarge 0.1.1 documentation

API Reference

This is the place where the functions and classes in sarge's public API are described.

Attributes

default_capture_timeout

This is the default timeout which will be used by Capture instances when you don’t specify one in the Capture constructor. This is currently set to 0.02 seconds.

Functions

run(command, input=None, async=False, **kwargs)

This function is a convenience wrapper which constructs a Pipeline instance from the passed parameters, and then invokes run() and close() on that instance.

Parameters:
  • command (str) – The command(s) to run.
  • input (Text, bytes or a file-like object containing bytes (not text).) – Input data to be passed to the command(s). If text is passed, it’s converted to bytes using the default encoding. The bytes are converted to a file-like object (a BytesIO instance). If a value such as a file-like object, integer file descriptor or special value like subprocess.PIPE is passed, it is passed through unchanged to subprocess.Popen.
  • kwargs – Any keyword parameters which you might want to pass to the wrapped Pipeline instance.
Returns:

The created Pipeline instance.

capture_stdout(command, input=None, async=False, **kwargs)

This function is a convenience wrapper which does the same as run() while capturing the stdout of the subprocess(es). This captured output is available through the stdout attribute of the return value from this function.

Parameters:
  • command – As for run().
  • input – As for run().
  • kwargs – As for run().
Returns:

As for run().

get_stdout(command, input=None, async=False, **kwargs)

This function is a convenience wrapper which does the same as capture_stdout() but also returns the text captured. Use this when you know the output is not voluminous, so it doesn’t matter that it’s buffered in memory.

Parameters:
  • command – As for run().
  • input – As for run().
  • kwargs – As for run().
Returns:

The captured text.

New in version 0.1.1.

capture_stderr(command, input=None, async=False, **kwargs)

This function is a convenience wrapper which does the same as run() while capturing the stderr of the subprocess(es). This captured output is available through the stderr attribute of the return value from this function.

Parameters:
  • command – As for run().
  • input – As for run().
  • kwargs – As for run().
Returns:

As for run().

get_stderr(command, input=None, async=False, **kwargs)

This function is a convenience wrapper which does the same as capture_stderr() but also returns the text captured. Use this when you know the output is not voluminous, so it doesn’t matter that it’s buffered in memory.

Parameters:
  • command – As for run().
  • input – As for run().
  • kwargs – As for run().
Returns:

The captured text.

New in version 0.1.1.

capture_both(command, input=None, async=False, **kwargs)

This function is a convenience wrapper which does the same as run() while capturing the stdout and the stderr of the subprocess(es). This captured output is available through the stdout and stderr attributes of the return value from this function.

Parameters:
  • command – As for run().
  • input – As for run().
  • kwargs – As for run().
Returns:

As for run().

get_both(command, input=None, async=False, **kwargs)

This function is a convenience wrapper which does the same as capture_both() but also returns the text captured. Use this when you know the output is not voluminous, so it doesn’t matter that it’s buffered in memory.

Parameters:
  • command – As for run().
  • input – As for run().
  • kwargs – As for run().
Returns:

The captured text as a 2-element tuple, with the stdout text in the first element and the stderr text in the second.

New in version 0.1.1.

shell_quote(s)

Quote text so that it is safe for Posix command shells.

For example, “.py” would be converted to “’.py’”. If the text is considered safe it is returned unquoted.

Parameters:s (str, or unicode on 2.x) – The value to quote
Returns:A safe version of the input, from the point of view of Posix command shells
Return type:The passed-in type
shell_format(fmt, *args, **kwargs)

Format a shell command with format placeholders and variables to fill those placeholders.

Note: you must specify positional parameters explicitly, i.e. as {0}, {1} instead of {}, {}. Requiring the formatter to maintain its own counter can lead to thread safety issues unless a thread local is used to maintain the counter. It’s not that hard to specify the values explicitly yourself :-)

Parameters:
  • fmt (str, or unicode on 2.x) – The shell command as a format string. Note that you will need to double up braces you want in the result, i.e. { -> {{ and } -> }}, due to the way str.format() works.
  • args – Positional arguments for use with fmt.
  • kwargs – Keyword arguments for use with fmt.
Returns:

The formatted shell command, which should be safe for use in shells from the point of view of shell injection.

Return type:

The type of fmt.

Classes

class Command(args, **kwargs)

This represents a single command to be spawned as a subprocess.

Parameters:
  • args (str if shell=True, or an array of str) – The command to run.
  • kwargs – Any keyword parameters you might pass to Popen, other than stdin (for which, you need to see the input argument of run()).
run(input=None, async=False)

Run the command.

Parameters:
  • input (Text, bytes or a file-like object containing bytes.) – Input data to be passed to the command. If text is passed, it’s converted to bytes using the default encoding. The bytes are converted to a file-like object (a BytesIO instance). The contents of the file-like object are written to the stdin stream of the sub-process.
  • async (bool) – If True, the command is run asynchronously – that is to say, wait() is not called on the underlying Popen instance.
wait()

Wait for the command’s underlying sub-process to complete.

terminate()

Terminate the command’s underlying sub-process by calling subprocess.Popen.terminate() on it.

New in version 0.1.1.

kill()

Kill the command’s underlying sub-process by calling subprocess.Popen.kill() on it.

New in version 0.1.1.

poll()

Poll the command’s underlying sub-process by calling subprocess.Popen.poll() on it. Returns the result of that call.

New in version 0.1.1.

class Pipeline(source, posix=True, **kwargs)

This represents a set of commands which need to be run as a unit.

Parameters:
  • source (str) – The source text with the command(s) to run.
  • posix (bool) – Whether the source will be parsed using Posix conventions.
  • kwargs – Any keyword parameters you would pass to subprocess.Popen, other than stdin (for which, you need to use the input parameter of the run() method instead). You can pass Capture instances for stdout and stderr keyword arguments, which will cause those streams to be captured to those instances.
run(input=None, async=False)

Run the pipeline.

Parameters:
  • input – The same as for the Command.run() method.
  • async – The same as for the Command.run() method. Note that parts of the pipeline may specify synchronous or asynchronous running – this flag refers to the pipeline as a whole.
wait()

Wait for all command sub-processes to finish.

close()

Wait for all command sub-processes to finish, and close all opened streams.

returncodes

A list of the return codes of all sub-processes which were actually run.

returncode

The return code of the last sub-process which was actually run.

commands

The Command instances which were actually created.

class Capture(timeout=None, buffer_size=0)

A class which allows an output stream from a sub-process to be captured.

Parameters:
  • timeout (float) – The default timeout, in seconds. Note that you can override this in particular calls to read input. If None is specified, the value of the module attribute default_capture_timeout is used instead.
  • buffer_size (int) – The buffer size to use when reading from the underlying streams. If not specified or specified as zero, a 4K buffer is used. For interactive applications, use a value of 1.
read(size=-1, block=True, timeout=None)

Like the read method of any file-like object.

Parameters:
  • size (int) – The number of bytes to read. If not specified, the intent is to read the stream until it is exhausted.
  • block (bool) – Whether to block waiting for input to be available,
  • timeout (float) – How long to wait for input. If None, use the default timeout that this instance was initialised with. If the result is None, wait indefinitely.
readline(size=-1, block=True, timeout=None)

Like the readline method of any file-like object.

Parameters:
  • size – As for the read() method.
  • block – As for the read() method.
  • timeout – As for the read() method.
readlines(sizehint=-1, block=True, timeout=None)

Like the readlines method of any file-like object.

Parameters:
  • sizehint – As for the read() method’s size.
  • block – As for the read() method.
  • timeout – As for the read() method.
expect(string_or_pattern, timeout=None)

This looks for a pattern in the captured output stream. If found, it returns immediately; otherwise, it will block until the timeout expires, waiting for a match as bytes from the captured stream continue to be read.

Parameters:
  • string_or_pattern – A string or pattern representing a regular expression to match. Note that this needs to be a bytestring pattern if you pass a pattern in; if you pass in text, it is converted to bytes using the utf-8 codec and then to a pattern used for matching (using search). If you pass in a pattern, you may want to ensure that its flags include re/MULTILINE so that you can make use of ^ and $ in matching line boundaries. Note that on Windows, you may need to use \r?$ to match ends of lines, as $ matches Unix newlines (LF) and not Windows newlines (CRLF).
  • timeout – If not specified, the module’s default_expect_timeout is used.
Returns:

A regular expression match instance, if a match was found within the specified timeout, or None if no match was found.

close(stop_threads=False):

Close the capture object. By default, this waits for the threads which read the captured streams to terminate (which may not happen unless the child process is killed, and the streams read to exhaustion). To ensure that the threads are stopped immediately, specify True for the stop_threads parameter, which will asks the threads to terminate immediately. This may lead to losing data from the captured streams which has not yet been read.

class Popen

This is a subclass of subprocess.Popen which is provided mainly to allow a process’ stdout to be mapped to its stderr. The standard library version allows you to specify stderr=STDOUT to indicate that the standard error stream of the sub-process be the same as its standard output stream. However. there’s no facility in the standard library to do stdout=STDERR – but it is provided in this subclass.

In fact, the two streams can be swapped by doing stdout=STDERR, stderr=STDOUT in a call. The STDERR value is defined in sarge as an integer constant which is understood by sarge (much as STDOUT is an integer constant which is understood by subprocess).

Shell syntax understood by sarge

Shell commands are parsed by sarge using a simple parser.

Command syntax

The sarge parser looks for commands which are separated by ; and &:

echo foo; echo bar & echo baz

which means to run echo foo, wait for its completion, and then run echo bar and then echo baz without waiting for echo bar to complete.

The commands which are separated by & and ; are conditional commands, of the form:

a && b

or:

c || d

Here, command b is executed only if a returns success (i.e. a return code of 0), whereas d is only executed if c returns failure, i.e. a return code other than 0. Of course, in practice all of a, b, c and d could have arguments, not shown above for simplicity’s sake.

Each operand on either side of && or || could also consist of a pipeline – a set of commands connected such that the output streams of one feed into the input stream of another. For example:

echo foo | cat

or:

command-a |& command-b

where the use of | indicates that the standard output of echo foo is piped to the input of cat, whereas the standard error of command-a is piped to the input of command-b.

Redirections

The sarge parser also understands redirections such as are shown in the following examples:

command arg-1 arg-2 > stdout.txt
command arg-1 arg-2 2> stderr.txt
command arg-1 arg-2 2>&1
command arg-1 arg-2 >&2

In general, file descriptors other than 1 and 2 are not allowed, as the functionality needed to provided them (dup2) is not properly supported on Windows. However, an esoteric special case is recognised:

echo foo | tee stdout.log 3>&1 1>&2 2>&3 | tee stderr.log > /dev/null

This redirection construct will put foo in both stdout.log and stderr.log. The effect of this construct is to swap the standard output and standard error streams, using file descriptor 3 as a temporary as in the code analogue for swapping variables a and b using temporary variable c:

c = a
a = b
b = c

This is recognised by sarge and used to swap the two streams, though it doesn’t literally use file descriptor 3, instead using a cross-platform mechanism to fulfill the requirement.

You can see this post for a longer explanation of this somewhat esoteric usage of redirection.

Next steps

You might find it helpful to look at the mailing list.

Comments powered by Disqus

Project Versions

Table Of Contents

Previous topic

Under the hood

This Page

PKZ6B!!sarge-0.1.1/search.html Search — Sarge 0.1.1 documentation

Search

Please activate JavaScript to enable the search functionality.

From here you can search these documents. Enter your search words into the box below and click "search". Note that the search function will automatically search for all of the words. Pages containing fewer words won't appear in the result list.

Project Versions

PKY6BRQGlGlsarge-0.1.1/internals.html Under the hood — Sarge 0.1.1 documentation

Under the hood

This is the section where some description of how sarge works internally will be provided, as and when time permits.

How capturing works

This section describes how Capture is implemented.

Basic approach

A Capture consists of a queue, some output streams from sub-processes, and some threads to read from those streams into the queue. One thread is created for each stream, and the thread exits when its stream has been completely read. When you read from a Capture instance using methods like read(), readline() and readlines(), you are effectively reading from the queue.

Blocking and timeouts

Each of the read(), readline() and readlines() methods has optional block and timeout keyword arguments. These default to True and None respectively, which means block indefinitely until there’s some data – the standard behaviour for file-like objects. However, these can be overridden internally in a couple of ways:

  • The Capture constructor takes an optional timeout keyword argument. This defaults to None, but if specified, that’s the timeout used by the readXXX methods unless you specify values in the method calls. If None is specified in the constructor, the module attribute default_capture_timeout is used, which is currently set to 0.02 seconds. If you need to change this default, you can do so before any Capture instances are created (or just provide an alternative default in every Capture creation).
  • If all streams feeding into the capture have been completely read, then block is always set to False.

Implications when handling large amounts of data

There shouldn’t be any special implications of handling large amounts of data, other than buffering, buffer sizes and memory usage (which you would have to think about anyway). Here’s an example of piping a 20MB file into a capture across several process boundaries:

$ ls -l random.bin
-rw-rw-r-- 1 vinay vinay 20971520 2012-01-17 17:57 random.bin
$ python
[snip]
>>> from sarge import run, Capture
>>> p = run('cat random.bin|cat|cat|cat|cat|cat', stdout=Capture(), async=True)
>>> for i in range(8):
...     data = p.stdout.read(2621440)
...     print('Read chunk %d: %d bytes' % (i, len(data)))
...
Read chunk 0: 2621440 bytes
Read chunk 1: 2621440 bytes
Read chunk 2: 2621440 bytes
Read chunk 3: 2621440 bytes
Read chunk 4: 2621440 bytes
Read chunk 5: 2621440 bytes
Read chunk 6: 2621440 bytes
Read chunk 7: 2621440 bytes
>>> p.stdout.read()
''

Swapping output streams

A new constant, STDERR, is defined by sarge. If you specify stdout=STDERR, this means that you want the child process stdout to be the same as its stderr. This is analogous to the core functionality in subprocess.Popen where you can specify stderr=STDOUT to have the child process stderr be the same as its stdout. The use of this constant also allows you to swap the child’s stdout and stderr, which can be useful in some cases.

This functionality works through a class sarge.Popen which subclasses subprocess.Popen and overrides the internal _get_handles method to work the necessary magic – which is to duplicate, close and swap handles as needed.

How shell quoting works

The shell_quote() function works as follows. Firstly, an empty string is converted to ''. Next, a check is made to see if the string has already been quoted (i.e. it begins and ends with the ' character), and if so, it is returned enclosed in " and with any contained characters escaped with a backslash. Otherwise, it’s bracketed with the ' character and every internal instance of ' is replaced with '"'"'.

How shell command formatting works

This is inspired by Nick Coghlan’s shell_command project. An internal ShellFormatter class is derived from string.Formatter and overrides the string.Formatter.convert_field() method to provide quoting for placeholder values. This formatter is simpler than Nick’s in that it forces you to explicitly provide the indices of positional arguments: You have to use e.g. 'cp {0} {1} instead of cp {} {}. This avoids the need to keep an internal counter in the formatter, which would make its implementation be not thread-safe without additional work.

How command parsing works

Internally sarge uses a simple recursive descent parser to parse commands. A simple BNF grammar for the parser would be:

<list> ::= <pipeline> ((";" | "&") <pipeline>)*
<pipeline> ::= <logical> (("&&" | "||") <logical>)*
<logical> ::= (<command> (("|" | "|&") <command>)*) | "(" <list> ")"
<command> ::= <command-part>+
<command-part> ::= WORD ((<NUM>)? (">" | ">>") (<WORD> | ("&" <NUM>)))*

where WORD and NUM are terminal tokens with the meanings you would expect.

The parser constructs a parse tree, which is used internally by the Pipeline class to manage the running of the pipeline.

The standard library’s shlex module contains a class which is used for lexical scanning. Since the shlex.shlex class is not able to provide the needed functionality, sarge includes a module, shlext, which defines a subclass, shell_shlex, which provides the necessary functionality. This is not part of the public API of sarge, though it has been submitted as an enhancement on the Python issue tracker.

Thread debugging

Sometimes, you can get deadlocks even though you think you’ve taken sufficient measures to avoid them. To help identify where deadlocks are occurring, the sarge source distribution includes a module, stack_tracer, which is based on MIT-licensed code by László Nagy in an ActiveState recipe. To see how it’s invoked, you can look at the sarge test harness test_sarge.py – this is set to invoke the tracer if the TRACE_THREADS variable is set (which it is, by default). If the unit tests hang on your system, then the threads-X.Y.log file will show where the deadlock is (just look and see what all the threads are waiting for).

Future changes

At the moment, if a Capture is used, it will read from its sub-process output streams into a queue, which can then be read by your code. If you don’t read from the Capture in a timely fashion, a lot of data could potentially be buffered in memory – the same thing that happens when you use subprocess.Popen.communicate(). There might be added some means of “turning the tap off”, i.e. pausing the reader threads so that the capturing threads stop reading from the sub-process streams. This will, of course, cause those sub-processes to block on their I/O, so at some point the tap would need to be turned back on. However, such a facility would afford better sub-process control in some scenarios.

Next steps

You might find it helpful to look at the API Reference.

Comments powered by Disqus
PKZ6BZsarge-0.1.1/.buildinfo# Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. config: d9a83a8776bb71a7b77baa7b6d264013 tags: fbb0d17656682115ca4d033fb2f83ba1 PKZ6Bb  sarge-0.1.1/objects.inv# Sphinx inventory version 2 # Project: Sarge # Version: 0.1 # The remainder of this file is compressed using zlib. xڕT;O0+@bj$nbTc ߓ`jKU-9q(+a<ɹlvTj{2h2]I%N UӁUjÖs` c쾜IWKAy`2hHT8˵?ʙuD;F=Q6XK$4`?C;eqBC)3ɇf FsL`fB+4_Q_\Q @c Z[ ZEM$bQSѢRc܄+,(_5_uPx TUcsꅅJ3)nz1љ(cœȩMy` J}Z?ƥC–M0))4*1[t ZeӮ {V}}*Һv6&w^PKZ6Bd6A77sarge-0.1.1/tutorial.html Tutorial — Sarge 0.1.1 documentation

Tutorial

This is the place to start your practical exploration of sarge.

Installation and testing

sarge is a pure-Python library. You should be able to install it using:

pip install sarge

for installing sarge into a virtualenv or other directory where you have write permissions. On Posix platforms, you may need to invoke using sudo if you need to install sarge in a protected location such as your system Python’s site-packages directory.

A full test suite is included with sarge. To run it, you’ll need to unpack a source tarball and run python setup.py test in the top-level directory of the unpack location. You can of course also run python setup.py install to install from the source tarball (perhaps invoking with sudo if you need to install to a protected location).

Common usage patterns

In the simplest cases, sarge doesn’t provide any major advantage over subprocess:

>>> from sarge import run
>>> run('echo "Hello, world!"')
Hello, world!
<sarge.Pipeline object at 0x1057110>

The echo command got run, as expected, and printed its output on the console. In addition, a Pipeline object got returned. Don’t worry too much about what this is for now – it’s more useful when more complex combinations of commands are run.

By comparison, the analogous case with subprocess would be:

>>> from subprocess import call
>>> call('echo "Hello, world!"'.split())
"Hello, world!"
0

We had to call split() on the command (or we could have passed shell=True), and as well as running the command, the call() method returned the exit code of the subprocess. To get the same effect with sarge you have to do:

>>> from sarge import run
>>> run('echo "Hello, world!"').returncode
Hello, world!
0

If that’s as simple as you want to get, then of course you don’t need sarge. Let’s look at more demanding uses next.

Chaining commands

It’s easy to chain commands together with sarge. For example:

>>> run('echo "Hello,"; echo "world!"')
Hello,
world!
<sarge.Pipeline object at 0x247ed50>

whereas this would have been more involved if you were just using subprocess:

>>> call('echo "Hello,"'.split()); call('echo "world!"'.split())
"Hello,"
0
"world!"
0

You get two return codes, one for each command. The same information is available from sarge, in one place – the Pipeline instance that’s returned from a run() call:

>>> run('echo "Hello,"; echo "world!"').returncodes
Hello,
world!
[0, 0]

The returncodes property of a Pipeline instance returns a list of the return codes of all the commands that were run, whereas the returncode property just returns the last element of this list. The Pipeline class defines a number of useful properties - see the reference for full details.

Handling user input safely

By default, sarge does not run commands via the shell. This means that wildcard characters in user input do not have potentially dangerous consequences:

>>> run('ls *.py')
ls: cannot access *.py: No such file or directory
<sarge.Pipeline object at 0x20f3dd0>

This behaviour helps to avoid shell injection attacks.

There might be circumstances where you need to use shell=True, in which case you should consider formatting your commands with placeholders and quoting any variable parts that you get from external sources (such as user input). Which brings us on to ...

Formatting commands with placeholders for safe usage

If you need to merge commands with external inputs (e.g. user inputs) and you want to prevent shell injection attacks, you can use the shell_format() function. This takes a format string, positional and keyword arguments and uses the new formatting (str.format()) to produce the result:

>>> from sarge import shell_format
>>> shell_format('ls {0}', '*.py')
"ls '*.py'"

Note how the potentially unsafe input has been quoted. With a safe input, no quoting is done:

>>> shell_format('ls {0}', 'test.py')
'ls test.py'

If you really want to prevent quoting, even for potentially unsafe inputs, just use the s conversion:

>>> shell_format('ls {0!s}', '*.py')
'ls *.py'

There is also a shell_quote() function which quotes potentially unsafe input:

>>> from sarge import shell_quote
>>> shell_quote('abc')
'abc'
>>> shell_quote('ab?')
"'ab?'"
>>> shell_quote('"ab?"')
'\'"ab?"\''
>>> shell_quote("'ab?'")
'"\'ab?\'"'

This function is used internally by shell_format(), so you shouldn’t need to call it directly except in unusual cases.

Passing input data to commands

You can pass input to a command pipeline using the input keyword parameter to run():

>>> from sarge import run
>>> p = run('cat|cat', input='foo')
foo>>>

You can pass a string, bytes or a file-like object of bytes. If it’s a string or bytes, what you pass in is converted to a file-like object of bytes, which is sent to the child process’ stdin stream in a separate thread.

You can also pass in special values like subprocess.PIPE – these are passed to the subprocess layer as-is.

Chaining commands conditionally

You can use && and || to chain commands conditionally using short-circuit Boolean semantics. For example:

>>> from sarge import run
>>> run('false && echo foo')
<sarge.Pipeline object at 0xb8dd50>

Here, echo foo wasn’t called, because the false command evaluates to False in the shell sense (by returning an exit code other than zero). Conversely:

>>> run('false || echo foo')
foo
<sarge.Pipeline object at 0xa11d50>

Here, foo is output because we used the || condition; because the left- hand operand evaluates to False, the right-hand operand is evaluated (i.e. run, in this context). Similarly, using the true command:

>>> run('true && echo foo')
foo
<sarge.Pipeline object at 0xb8dd50>
>>> run('true || echo foo')
<sarge.Pipeline object at 0xa11d50>

Creating command pipelines

It’s just as easy to construct command pipelines:

>>> run('echo foo | cat')
foo
<sarge.Pipeline object at 0xb8dd50>
>>> run('echo foo; echo bar | cat')
foo
bar
<sarge.Pipeline object at 0xa96c50>

Using redirection

You can also use redirection to files as you might expect. For example:

>>> run('echo foo | cat > /tmp/junk')
<sarge.Pipeline object at 0x24b3190>
^D (to exit Python)
$ cat /tmp/junk
foo

You can use >, >>, 2>, 2>> which all work as on Posix systems. However, you can’t use < or <<.

To send things to the bit-bucket in a cross-platform way, you can do something like:

>>> run('echo foo | cat > %s' % os.devnull)
<sarge.Pipeline object at 0x2765b10>

Capturing stdout and stderr from commands

To capture output for commands, just pass a Capture instance for the relevant stream:

>>> from sarge import run, Capture
>>> p = run('echo foo; echo bar | cat', stdout=Capture())
>>> p.stdout.text
u'foo\nbar\n'

The Capture instance acts like a stream you can read from: it has read(), readline() and readlines() methods which you can call just like on any file-like object, except that they offer additional options through block and timeout keyword parameters.

As in the above example, you can use the bytes or text property of a Capture instance to read all the bytes or text captured. The latter just decodes the former using UTF-8 (the default encoding isn’t used, because on Python 2.x, the default encoding isn’t UTF-8 – it’s ASCII).

There are some convenience functions – capture_stdout(), capture_stderr() and capture_both() – which work just like run() but capture the relevant streams to Capture instances, which can be accessed using the appropriate attribute on the Pipeline instance returned from the functions.

There are more convenience functions, get_stdout(), get_stderr() and get_both(), which work just like capture_stdout(), capture_stderr() and capture_both() respectively, but return the captured text. For example:

>>> from sarge import get_stdout
>>> get_stdout('echo foo; echo bar')
u'foo\nbar\n'

New in version 0.1.1: The get_stdout(), get_stderr() and get_both() functions were added.

A Capture instance can capture output from one or more sub-process streams, and will create a thread for each such stream so that it can read all sub-process output without causing the sub-processes to block on their output I/O. However, if you use a Capture, you should be prepared either to consume what it’s read from the sub-processes, or else be prepared for it all to be buffered in memory (which may be problematic if the sub-processes generate a lot of output).

Iterating over captures

You can iterate over Capture instances. By default you will get successive lines from the captured data, as bytes; if you want text, you can wrap with io.TextIOWrapper. Here’s an example using Python 3.2:

>>> from sarge import capture_stdout
>>> p = capture_stdout('echo foo; echo bar')
>>> for line in p.stdout: print(repr(line))
...
b'foo\n'
b'bar\n'
>>> p = capture_stdout('echo bar; echo baz')
>>> from io import TextIOWrapper
>>> for line in TextIOWrapper(p.stdout): print(repr(line))
...
'bar\n'
'baz\n'

This works the same way in Python 2.x. Using Python 2.7:

>>> from sarge import capture_stdout
>>> p = capture_stdout('echo foo; echo bar')
>>> for line in p.stdout: print(repr(line))
...
'foo\n'
'bar\n'
>>> p = capture_stdout('echo bar; echo baz')
>>> from io import TextIOWrapper
>>> for line in TextIOWrapper(p.stdout): print(repr(line))
...
u'bar\n'
u'baz\n'

Interacting with child processes

Sometimes you need to interact with a child process in an interactive manner. To illustrate how to do this, consider the following simple program, named receiver, which will be used as the child process:

#!/usr/bin/env python
import sys

def main(args=None):
    while True:
        user_input = sys.stdin.readline().strip()
        if not user_input:
            break
        s = 'Hi, %s!\n' % user_input
        sys.stdout.write(s)
        sys.stdout.flush() # need this when run as a subprocess

if __name__ == '__main__':
    sys.exit(main())

This just reads lines from the input and echoes them back as a greeting. If we run it interactively:

$ ./receiver
Fred
Hi, Fred!
Jim
Hi, Jim!
Sheila
Hi, Sheila!

The program exits on seeing an empty line.

We can now show how to interact with this program from a parent process:

>>> from sarge import Command, Capture
>>> from subprocess import PIPE
>>> p = Command('/.receiver', stdout=Capture(buffer_size=1))
>>> p.run(input=PIPE, async=True)
Command('./receiver')
>>> p.stdin.write('Fred\n')
>>> p.stdout.readline()
'Hi, Fred!\n'
>>> p.stdin.write('Jim\n')
>>> p.stdout.readline()
'Hi, Jim!\n'
>>> p.stdin.write('Sheila\n')
>>> p.stdout.readline()
'Hi, Sheila!\n'
>>> p.stdin.write('\n')
>>> p.stdout.readline()
''
>>> p.returncode
>>> p.wait()
0

The p.returncode didn’t print anything, indicating that the return code was None. This means that although the child process has exited, it’s still a zombie because we haven’t “reaped” it by making a call to wait(). Once that’s done, the zombie disappears and we get the return code.

Buffering issues

From the point of view of buffering, note that two elements are needed for the above example to work:

  • We specify buffer_size=1 in the Capture constructor. Without this, data would only be read into the Capture’s queue after an I/O completes – which would depend on how many bytes the Capture reads at a time. You can also pass a buffer_size=-1 to indicate that you want to use line- buffering, i.e. read a line at a time from the child process. (This may only work as expected if the child process flushes its outbut buffers after every line.)
  • We make a flush call in the receiver script, to ensure that the pipe is flushed to the capture queue. You could avoid the flush call in the above example if you used python -u receiver as the command (which runs the script unbuffered).

This example illustrates that in order for this sort of interaction to work, you need cooperation from the child process. If the child process has large output buffers and doesn’t flush them, you could be kept waiting for input until the buffers fill up or a flush occurs.

If a third party package you’re trying to interact with gives you buffering problems, you may or may not have luck (on Posix, at least) using the unbuffer utility from the expect-dev package (do a Web search to find it). This invokes a program directing its output to a pseudo-tty device which gives line buffering behaviour. This doesn’t always work, though :-(

Looking for specific patterns in child process output

You can look for specific patterns in the output of a child process, by using the expect() method of the Capture class. This takes a string, bytestring or regular expression pattern object and a timeout, and either returns a regular expression match object (if a match was found in the specified timeout) or None (if no match was found in the specified timeout). If you pass in a bytestring, it will be converted to a regular expression pattern. If you pass in text, it will be encoded to bytes using the utf-8 codec and then to a regular expression pattern. This pattern will be used to look for a match (using search). If you pass in a regular expression pattern, make sure it is meant for bytes rather than text (to avoid TypeError on Python 3.x). You may also find it useful to specify re.MULTILINE in the pattern flags, so that you can match using ^ and $ at line boundaries. Note that on Windows, you may need to use \r?$ to match ends of lines, as $ matches Unix newlines (LF) and not Windows newlines (CRLF).

New in version 0.1.1: The expect method was added.

To illustrate usage of Capture.expect(), consider the program lister.py (which is provided as part of the source distribution, as it’s used in the tests). This prints line 1, line 2 etc. indefinitely with a configurable delay, flushing its output stream after each line. We can capture the output from a run of lister.py, ensuring that we use line-buffering in the parent process:

>>> from sarge import Capture, run
>>> c = Capture(buffer_size=-1)     # line-buffering
>>> p = run('python lister.py -d 0.01', async=True, stdout=c)
>>> m = c.expect('^line 1$')
>>> m.span()
(0, 6)
>>> m = c.expect('^line 5$')
>>> m.span()
(28, 34)
>>> m = c.expect('^line 1.*$')
>>> m.span()
(63, 70)
>>> c.close(True)           # close immediately, discard any unread input
>>> p.commands[0].kill()    # kill the subprocess
>>> c.bytes[63:70]
'line 10'
>>> m = c.expect(r'^line 1\d\d$')
>>> m.span()
(783, 791)
>>> c.bytes[783:791]
'line 100'

Direct terminal usage

Some programs don’t work through their stdin/stdout/stderr streams, instead opting to work directly with their controlling terminal. In such cases, you can’t work with these programs using sarge; you need to use a pseudo-terminal approach, such as is provided by (for example) pexpect. Sarge works within the limits of the subprocess module, which means sticking to stdin, stdout and stderr as ordinary streams or pipes (but not pseudo-terminals).

Examples of programs which work directly through their controlling terminal are ftp and ssh - the password prompts for these programs are generally always printed to the controlling terminal rather than stdout or stderr.

Environments

In the subprocess.Popen constructor, the env keyword argument, if supplied, is expected to be the complete environment passed to the child process. This can lead to problems on Windows, where if you don’t pass the SYSTEMROOT environment variable, things can break. With sarge, it’s assumed that anything you pass in env is added to the contents of os.environ. This is almost always what you want – after all, in a Posix shell, the environment is generally inherited with certain additions for a specific command invocation.

Note

On Python 2.x on Windows, environment keys and values must be of type str - Unicode values will cause a TypeError. Be careful of this if you use from __future__ import unicode_literals. For example, the test harness for sarge uses Unicode literals on 2.x, necessitating the use of different logic for 2.x and 3.x:

if PY3:
    env = {'FOO': 'BAR'}
else:
    # Python 2.x wants native strings, at least on Windows
    env = { b'FOO': b'BAR' }

Working directory and other options

You can set the working directory for a Command or Pipeline using the cwd keyword argument to the constructor, which is passed through to the subprocess when it’s created. Likewise, you can use the other keyword arguments which are accepted by the subprocess.Popen constructor.

Avoid using the stdin keyword argument – instead, use the input keyword argument to the Command.run() and Pipeline.run() methods, or the run(), capture_stdout(), capture_stderr(), and capture_both() functions. The input keyword makes it easier for you to pass literal text or byte data.

Unicode and bytes

All data between your process and sub-processes is communicated as bytes. Any text passed as input to run() or a run() method will be converted to bytes using UTF-8 (the default encoding isn’t used, because on Python 2.x, the default encoding isn’t UTF-8 – it’s ASCII).

As sarge requires Python 2.6 or later, you can use from __future__ import unicode_literals and byte literals like b'foo' so that your code looks and behaves the same under Python 2.x and Python 3.x. (See the note on using native string keys and values in Environments.)

As mentioned above, Capture instances return bytes, but you can wrap with io.TextIOWrapper if you want text.

Use as context managers

The Capture and Pipeline classes can be used as context managers:

>>> with Capture() as out:
...     with Pipeline('cat; echo bar | cat', stdout=out) as p:
...         p.run(input='foo\n')
...
<sarge.Pipeline object at 0x7f3320e94310>
>>> out.read().split()
['foo', 'bar']

Synchronous and asynchronous execution of commands

By default. commands passed to run() run synchronously, i.e. all commands run to completion before the call returns. However, you can pass async=True to run, in which case the call returns a Pipeline instance before all the commands in it have run. You will need to call wait() or close() on this instance when you are ready to synchronise with it; this is needed so that the sub processes can be properly disposed of (otherwise, you will leave zombie processes hanging around, which show up, for example, as <defunct> on Linux systems when you run ps -ef). Here’s an example:

>>> p = run('echo foo|cat|cat|cat|cat', async=True)
>>> foo

Here, foo is printed to the terminal by the last cat command, but all the sub-processes are zombies. (The run function returned immediately, so the interpreter got to issue the >>>` prompt *before* the ``foo output was printed.)

In another terminal, you can see the zombies:

$ ps -ef | grep defunct | grep -v grep
vinay     4219  4217  0 19:27 pts/0    00:00:00 [echo] <defunct>
vinay     4220  4217  0 19:27 pts/0    00:00:00 [cat] <defunct>
vinay     4221  4217  0 19:27 pts/0    00:00:00 [cat] <defunct>
vinay     4222  4217  0 19:27 pts/0    00:00:00 [cat] <defunct>
vinay     4223  4217  0 19:27 pts/0    00:00:00 [cat] <defunct>

Now back in the interactive Python session, we call close() on the pipeline:

>>> p.close()

and now, in the other terminal, look for defunct processes again:

$ ps -ef | grep defunct | grep -v grep
$

No zombies found :-)

About threading and forking on Posix

If you run commands asynchronously by using & in a command pipeline, then a thread is spawned to run each such command asynchronously. Remember that thread scheduling behaviour can be unexpected – things may not always run in the order you expect. For example, the command line:

echo foo & echo bar & echo baz

should run all of the echo commands concurrently as far as possible, but you can’t be sure of the exact sequence in which these commands complete – it may vary from machine to machine and even from one run to the next. This has nothing to do with sarge – there are no guarantees with just plain Bash, either.

On Posix, subprocess uses os.fork() to create the child process, and you may see dire warnings on the Internet about mixing threads, processes and fork(). It is a heady mix, to be sure: you need to understand what’s going on in order to avoid nasty surprises. If you run into any such, it may be hard to get help because others can’t reproduce the problems. However, that’s no reason to shy away from providing the functionality altogether. Such issues do not occur on Windows, for example: because Windows doesn’t have a fork() system call, child processes are created in a different way which doesn’t give rise to the issues which sometimes crop up in a Posix environment.

For an exposition of the sort of things which might bite you if you are using locks, threading and fork() on Posix, see this post.

Other resources on this topic:

Please report any problems you find in this area (or any other) either via the mailing list or the issue tracker.

Next steps

You might find it helpful to look at information about how sarge works internally – Under the hood – or peruse the API Reference.

Comments powered by Disqus
PKY6BAAsarge-0.1.1/overview.html Overview — Sarge 0.1.1 documentation

Overview

Start here for all things sarge.

What is Sarge for?

If you want to interact with external programs from your Python applications, Sarge is a library which is intended to make your life easier than using the subprocess module in Python’s standard library.

Sarge is, of course, short for sergeant – and like any good non-commissioned officer, sarge works to issue commands on your behalf and to inform you about the results of running those commands.

The acronym lovers among you might be amused to learn that sarge can also stand for “Subprocess Allegedly Rewards Good Encapsulation” :-)

Here’s a taster (example suggested by Kenneth Reitz’s Envoy documentation):

>>> from sarge import capture_stdout
>>> p = capture_stdout('fortune|cowthink')
>>> p.returncode
0
>>> p.commands
[Command('fortune'), Command('cowthink')]
>>> p.returncodes
[0, 0]
>>> print(p.stdout.text)
 ____________________________________
( The last thing one knows in        )
( constructing a work is what to put )
( first.                             )
(                                    )
( -- Blaise Pascal                   )
 ------------------------------------
        o   ^__^
         o  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

The capture_stdout() function is a convenient form of an underlying function, run(). You can also use conditionals:

>>> from sarge import run
>>> p = run('false && echo foo')
>>> p.commands
[Command('false')]
>>> p.returncodes
[1]
>>> p.returncode
1
>>> p = run('false || echo foo')
foo
>>> p.commands
[Command('false'), Command('echo foo')]
>>> p.returncodes
[1, 0]
>>> p.returncode
0

The conditional logic is being done by sarge and not the shell – which means you can use the identical code on Windows. Here’s an example of some more involved use of pipes, which also works identically on Posix and Windows:

>>> cmd = 'echo foo | tee stdout.log 3>&1 1>&2 2>&3 | tee stderr.log > %s' % os.devnull
>>> p = run(cmd)
>>> p.commands
[Command('echo foo'), Command('tee stdout.log'), Command('tee stderr.log')]
>>> p.returncodes
[0, 0, 0]
>>>
vinay@eta-oneiric64:~/projects/sarge$ cat stdout.log
foo
vinay@eta-oneiric64:~/projects/sarge$ cat stderr.log
foo

In the above example, the first tee invocation swaps its stderr and stdout – see this post for a longer explanation of this somewhat esoteric usage.

Why not just use subprocess?

The subprocess module in the standard library contains some very powerful functionality. It encapsulates the nitty-gritty details of subprocess creation and communication on Posix and Windows platforms, and presents the application programmer with a uniform interface to the OS-level facilities. However, subprocess does not do much more than this, and is difficult to use in some scenarios. For example:

  • You want to use command pipelines, but using subprocess out of the box often leads to deadlocks because pipe buffers get filled up.
  • You want to use bash-style pipe syntax on Windows, but Windows shells don’t support some of the syntax you want to use, like &&, ||, |& and so on.
  • You want to process output from commands in a flexible way, and communicate() is not flexible enough for your needs – for example, you need to process output a line at a time.
  • You want to avoid shell injection problems by having the ability to quote your command arguments safely.
  • subprocess allows you to let stderr be the same as stdout, but not the other way around – and you need to do that.

Main features

Sarge offers the following features:

  • A simple run command which allows a rich subset of Bash-style shell command syntax, but parsed and run by sarge so that you can run on Windows without cygwin.

  • The ability to format shell commands with placeholders, such that variables are quoted to prevent shell injection attacks:

    >>> from sarge import shell_format
    >>> shell_format('ls {0}', '*.py')
    "ls '*.py'"
    >>> shell_format('cat {0}', 'a file name with spaces')
    "cat 'a file name with spaces'"
    
  • The ability to capture output streams without requiring you to program your own threads. You just use a Capture object and then you can read from it as and when you want:

    >>> from sarge import Capture, run
    >>> with Capture() as out:
    ...     run('echo foobarbaz', stdout=out)
    ...
    <sarge.Pipeline object at 0x175ed10>
    >>> out.read(3)
    'foo'
    >>> out.read(3)
    'bar'
    >>> out.read(3)
    'baz'
    >>> out.read(3)
    '\n'
    >>> out.read(3)
    ''
    

    A Capture object can capture the output from multiple commands:

    >>> from sarge import run, Capture
    >>> p = run('echo foo; echo bar; echo baz', stdout=Capture())
    >>> p.stdout.readline()
    'foo\n'
    >>> p.stdout.readline()
    'bar\n'
    >>> p.stdout.readline()
    'baz\n'
    >>> p.stdout.readline()
    ''
    

    Delays in commands are honoured in asynchronous calls:

    >>> from sarge import run, Capture
    >>> cmd = 'echo foo & (sleep 2; echo bar) & (sleep 1; echo baz)'
    >>> p = run(cmd, stdout=Capture(), async=True) # returns immediately
    >>> p.close() # wait for completion
    >>> p.stdout.readline()
    'foo\n'
    >>> p.stdout.readline()
    'baz\n'
    >>> p.stdout.readline()
    'bar\n'
    >>>
    

Here, the sleep commands ensure that the asynchronous echo calls occur in the order foo (no delay), baz (after a delay of one second) and bar (after a delay of two seconds); the capturing works as expected.

Python version and platform compatibility

Sarge is intended to be used on any Python version >= 2.6 and is tested on Python versions 2.6, 2.7, 3.1, 3.2 and 3.3 on Linux, Windows, and Mac OS X (not all versions are tested on all platforms, but are expected to work correctly).

Project status

The project has reached alpha status in its development: there is a test suite and it has been exercised on Windows, Ubuntu and Mac OS X. However, because of the timing sensitivity of the functionality, testing needs to be performed on as wide a range of hardware and platforms as possible.

The source repository for the project is on BitBucket:

https://bitbucket.org/vinay.sajip/sarge/

You can leave feedback by raising a new issue on the issue tracker (BitBucket registration not necessary, but recommended).

Note

For testing under Windows, you need to install the GnuWin32 coreutils package, and copy the relevant executables (currently libiconv2.dll, libintl3.dll, cat.exe, echo.exe, tee.exe, false.exe, true.exe, sleep.exe and touch.exe) to the directory from which you run the test harness (test_sarge.py).

API stability

Although every attempt will be made to keep API changes to the absolute minimum, it should be borne in mind that the software is in its very early stages. For example, the asynchronous feature (where commands are run in separate threads when you specify & in a command pipeline) can be considered experimental, and there may be changes in this area. However, you aren’t forced to use this feature, and sarge should be useful without it.

Change log

0.1.2

Released: Not yet.

0.1.1

Released: 2013-06-04

  • expect method added to Capture class, to allow searching for specific patterns in subprocess output streams.
  • added terminate, kill and poll methods to Command class to operate on the wrapped subprocess.
  • Command.run now propagates exceptions which occur while spawning subprocesses.
  • Fixed issue #4: shell_shlex does not split on @.
  • Fixed issue #3: run et al now accept commands as lists, just as subprocess.Popen does.
  • Fixed issue #2: shell_quote implementation improved.
  • Improved shell_shlex resilience by handling Unicode on 2.x (where shlex breaks if passed Unicode).
  • Added get_stdout, get_stderr and get_both for when subprocess output is not expected to be voluminous.
  • Added an internal lock to serialise access to shared data.
  • Tests added to cover added functionality and reported issues.
  • Numerous documentation updates.

0.1

Released: 2012-02-10

  • Initial release.

Next steps

You might find it helpful to look at the Tutorial, or the API Reference.

Comments powered by Disqus

Project Versions

Table Of Contents

Previous topic

Welcome to sarge’s documentation!

Next topic

Tutorial

This Page

PKXRBkuFpp$sarge-0.1.1/_static/down-pressed.pngPNG  IHDRasRGBbKGDC pHYs B(xtIME -vF#IDAT8!OAJ, ++@I vbÿ@W7F HN#48646TMvv޼7Dsax1U q;< E-f)j%po4xF78G>)- EYm4%7YTk-Qa"NWAo-yeq,) Ypt\hqmszG]Nar߶s^l vh\2%0EeRvIENDB`PKXRB4sarge-0.1.1/_static/jquery.js/*! * jQuery JavaScript Library v1.4.2 * http://jquery.com/ * * Copyright 2010, John Resig * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * Includes Sizzle.js * http://sizzlejs.com/ * Copyright 2010, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * * Date: Sat Feb 13 22:33:48 2010 -0500 */ (function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& (d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== "find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a"; var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, "_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== "="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); (function(){var g=s.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= {},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== "string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== 1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, ""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", ""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, "border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== "string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? "&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== 1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== "json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== "number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
"; a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": "pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); PKXRBhkksarge-0.1.1/_static/down.pngPNG  IHDRasRGBbKGDC pHYs B(xtIME"U{IDAT8ҡNCAJ, ++@4>/U^,~T&3M^^^PM6ٹs*RJa)eG*W<"F Fg78G>q OIp:sAj5GنyD^+yU:p_%G@D|aOs(yM,"msx:.b@D|`Vٟ۲иeKſ/G!IENDB`PKXRB' 5w %sarge-0.1.1/_static/comment-close.pngPNG  IHDRa OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-bKGD pHYs  tIME!,IDAT8e_Hu?}s3y˕U2MvQ֊FE.łĊbE$DDZF5b@Q":2{n.s<_ y?mwV@tR`}Z _# _=_@ w^R%6gC-έ(K>| ${}